This may be a silly question, but I'm very new to Haskell. (I just started using it a couple of hours ago actually.)
So my problem is that I have a list of 4 elements and I need to print two on one line and two on a new line.
Here's the list:
let list1 = ["#", "@", "#", "#"]
I need the output to look like this:
#@
##
I know that i could use the following to print every element on a new line:
mapM_ putStrLn list1
but I'm not sure how to adapt this for only printing part of the list on a new line.
You want something like Data.Text.chunksOf
for arbitrary lists, which I've never seen anywhere so I always reimplement it.
import Data.List (unfoldr)
-- This version ensures that the output consists of lists
-- of equal length. To do so, it trims the input.
chunksOf :: Int -> [a] -> [[a]]
chunksOf n = unfoldr (test . splitAt n) where
test (_, []) = Nothing
test x = Just x
Then we can take your [String]
and turn it into [[String]]
, a list of lists each corresponding to String
components of a line. We map
concat
over that list to merge up each line from its components, then use unlines
to glue them all together.
grid :: Int -> [String] -> String
grid n = unlines . map concat . chunksOf n
Then we can print that string if desired
main :: IO ()
main = putStrLn $ grid 2 list1
Edit: apparently there is a chunksOf
in a fairly popular library Data.List.Split . Their version is to my knowledge identical to mine, though it's implemented a little differently. Both of ours ought to satisfy
chunksOf n xs ++ chunksOf n ys == chunksOf n (xs ++ ys)
whenever length xs `mod` n == 0
.
You can do:
mapM_ putStrLn [(take 2 list1), (drop 2 list1)]
where take
and drop
return lists with the expected number of elements. take 2
takes two elements and drop 2
drops the first two elements.
Looking at tel link Data.List.Split , another solution can be built on using chop .
Define as follow into the lib,
chop :: ([a] -> (b, [a])) -> [a] -> [b]
chop _ [] = []
chop f as = b : chop f as'
where (b, as') = f as
Then following's simeon advice we end with this one liner,
let fun n = mapM_ putStrLn . chop (splitAt n)
chop appears to be a nice function, enough to be mentioned here to illustrate an alternative solution. (unfoldr is great too).
Beginner attempt:
myOut :: [String] -> IO ()
myOut [] = putStr "\n"
myOut (x:xs) =
do if x=="@"
then putStrLn x
else putStr x
myOut xs
ghci>myOut ["#", "@", "#", "#"]
#@
##
ghci>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.