简体   繁体   中英

How to print part of a list on a new line in Haskell

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM