How to print list of tuples like table in Haskell - haskell

i have a list of tuples like:
[("3",69.46),("4",38.32),("5",111.67),("9",97.13)]
and i want to print this list of tuple like :
3 69.46
4 38.32
5 111.67
9 97.13
What is the best way to implement this?
(The length of list is dynamic)
Thanks

One way would be like this:
printList xs = mapM_ (\(a,b) -> putStr a >> putStr (" " ++ show b) >> putStrLn "") xs
Or in a more readable way:
printList xs = mapM_ (\(a,b) -> do
putStr a
putStr (" " ++ show b)
putStrLn "") xs
Or as #icktoofay points out you can use a single putStrLn:
printList xs = mapM_ (\(a,b) -> putStrLn $ a ++ " " ++ show b) xs
In ghci:
λ> printList [("3",69.46),("4",38.32),("5",111.67),("9",97.13)]
3 69.46
4 38.32
5 111.67
9 97.13

Related

Parallelizing evaluation and pointwise addition of lists

I have the following code:
normalHands :: [[[Char]]]
normalHands = -- a very long list
sevenHeads :: [[[Char]]]
sevenHeads = -- a very long list
countYakus :: [Int]
countYakus = foldr countYaku [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] (normalHands ++ sevenHeads) where
countYaku hand [p,oP,dT,aS,cS,fS,sO,cF,cT,dM,aO,tOAK,tP,sT,sF,f] =
-- involves pointwise addition of lists. The length of the accumulator is not changed.
How should I parallelize this? I tried the following:
import Control.Concurrent
import Control.Concurrent.QSem
import Control.Monad
import Data.List
--...
main :: IO ()
main = let
[pinfu, onePair, dragonTriplet, allSimples,
colorfulSequences, fullSequence, semiOrphans, concealedFour, colorfulTriplets, dragonsMinor, allOrphans, threeOfAKind,
twoPairs, semiTerminals, semiFlush, flush] = countYakus
in do
qSem <- newQSem 0
forkIO $ putStrLn ("0: " ++ show pinfu ++ ' ' : show onePair) >> signalQSem qSem
forkIO $ putStrLn ("1: " ++ show dragonTriplet ++ ' ' : show allSimples) >> signalQSem qSem
forkIO $ putStrLn ("2: " ++ show colorfulSequences ++ ' ' : show fullSequence) >> signalQSem qSem
forkIO $ putStrLn ("3: " ++ show semiOrphans ++ ' ' : show concealedFour) >> signalQSem qSem
forkIO $ putStrLn ("4: " ++ show colorfulTriplets ++ ' ' : show dragonsMinor) >> signalQSem qSem
forkIO $ putStrLn ("5: " ++ show allOrphans ++ ' ' : show threeOfAKind) >> signalQSem qSem
forkIO $ putStrLn ("6: " ++ show twoPairs ++ ' ' : show semiTerminals) >> signalQSem qSem
forkIO $ putStrLn ("7: " ++ show semiFlush ++ ' ' : show flush) >> signalQSem qSem
sequence_ $ replicate 8 (waitQSem qSem)
I compiled this with -O2 +RTS -N8, but despite I have 8 cores, my system monitor clearly shows that this code is being run in only one core. I guess it's because of normalHands ++ sevenHeads. So what is the correct way to parallelize this?
EDIT: Exploiting the associativity and commutativity of pointwise addition, I tried this:
countYakus :: [[[Char]]] -> [Int]
countYakus = foldl' countYaku [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] where
-- ...
divideList :: Int -> [a] -> [[a]]
divideList 0 _ = []
divideList n xs = let
(ys,zs) = splitAt n xs
in if null zs
then coZip ys (replicate n [])
else coZip ys (divideList n zs)
where
coZip :: [a] -> [[a]] -> [[a]]
coZip [] yss = yss
coZip (x:xs) (ys:yss) = (x:ys) : coZip xs yss
main :: IO ()
main = do
acc <- newIORef [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
mapM_ (\hands -> forkIO . atomicModifyIORef' acc $ \cs -> (zipWith (+) cs $ countYakus hands, ())) $ divideList 8 (normalHands ++ sevenHeads)
cs <- readIORef acc
mapM_ (putStrLn . show) cs
But it still runs only on one core.
EDIT 2: I tried using MVar:
main :: IO ()
main = do
acc <- newIORef [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
mVar <- newEmptyMVar
mapM_ (\hands -> forkIO $ putMVar mVar (countYakus hands)) $ divideList 8 (normalHands ++ sevenHeads)
replicateM_ 8 $ do
xs <- takeMVar mVar
ys <- readIORef acc
writeIORef acc (zipWith (+) xs ys)
cs <- readIORef acc
mapM_ (putStrLn . show) cs
But it still runs on only one core.

haskell show with function application

this line of code in Haskell produces an error on compilation:
lineStat :: String -> [String]
lineStat xs = zipWith (\n line -> show n ++ " " ++ show $ length line) [1..] $ lines xs
Error:
Couldn't match expected type Int -> String with actual type [Char]
The first argument of ($) takes one argument,but its type [Char] has none
However this line of code works:
lineStat xs = zipWith (\n line -> show n ++ " " ++ show (length line)) [1..] $ lines xs
Why?
It's a precedence issue.
show n ++ " " ++ show $ length line
means
(show n ++ " " ++ show) (length line)
which makes no sense since show is not a string. It does not mean
show n ++ " " ++ (show (length line))
To get the wanted one, you need parentheses. Use one of these:
zipWith (\n line -> show n ++ " " ++ show (length line)) [1..] $ lines xs
-- or
zipWith (\n line -> show n ++ " " ++ (show $ length line)) [1..] $ lines xs
I'd prefer the former since it's simpler.
Your problem boils down to:
*Main> let line = "abc"
*Main> " " ++ show (length line)
" 3"
*Main> " " ++ show $length line
<interactive>:9:1: error:
• Couldn't match expected type ‘Int -> t’ with actual type ‘[Char]’
The root cause for this is that $ has lower precedence than ++:
*Main> :info (++)
...
infixr 5 ++
*Main> :info ($)
...
infixr 0 $
as defined in the Haskell Report
Therefore, you need parentheses around show $ length line.

Adding an additional step to ">>="

I have this which works fine:
forM_ [1..10] $ \x -> myFunc1 x 99 >>= putStrLn . show >> return ()
myFunc1 :: Int -> Int -> IO Bool
myFunc1 .....
I want to do add an additional string to the output:
forM_ [1..10] $ \x -> myFunc1 x 99 >>= (++) "the result is: " >>= putStrLn . show >> return ()
But that doesn't compile. I've tried different variations but still no success. Your suggestions?
The first thing that sticks out is that the expression:
(++) "the result is: "
is not an IO-action - it's just a pure function String -> String, and
that's one reason why you code isn't type checking.
To turn it into an IO-action you can compose it with return:
return . ( (++) "the result is: " )
:: String -> IO String
Now you can use it with >>=.
However, that's not where the real problem is...
To prepend "the result is: " before the show you have to insert it in the putStrLn call:
... >>= putStrLn . (++ "the result is: ") . show
(Note that there is no need to >> return () since putStrLn already returns ()).
Honestly, this is a lot simpler using do-notation:
forM_ [1..10] $ \x -> do
s <- myFunc1 x 99
putStrLn $ "the result is: " ++ show s
You can compose show with the concatenation function like so:
forM_ [1..10] $ \x -> myFunc1 x 99 >>= putStrLn . ("the result is: " ++) . show >> return ()
Replace ++ with add
add x y = return (x ++ show (y))
forM_ [1..10] $ \x -> myFunc1 x 99 >>= add "the result is: " >>= putStrLn . show >> return ()
reason: The return type of ++ is not IO type

Haskell "\n" shown as string in IO String

imP:: Int -> IO String
imP n = do
x <- getLine
if n >= 0 then return ( (concat (replicate n " ")) ++ fun1 x) else return ( fun2 n x)
where
fun1 [] = ""
fun1 (x:xs)
| isAlpha x = [x] ++ fun1 xs
| otherwise = "\n" ++ fun1 xs
fun2 n [] = ""
fun2 n (x:xs)
| isAlpha x = [x] ++ fun2 n xs
| otherwise = "\n" ++ (concat (replicate (abs n) " ")) ++ fun2 n xs
I have this code. And given an input "hello3mello" to getLine it returns:
"hello\nmello"
But I need:
"hello
mello"
EDIT:
<interactive>:32:9:
Couldn't match type `IO String' with `[Char]'
Expected type: String
Actual type: IO String
In the first argument of `putStr', namely `(imP 3)'
In the expression: putStr (imP 3)
The type of putStr is String -> IO (), you can't apply it to imP 3 :: IO String because putStr expects a pure String not an IO String. Which is exactly what GHC's error message is reporting.
I assume you're not familiar with monads, so I'd recommend reading any of the many tutorials. In the meantime, use \x -> imP x >>= putStr

Print List of Lists without brackets

I am trying to print Pascals triangle up to some arbitrary row, after some thought I came up with this solution:
next xs = zipWith (+) ([0] ++ xs) (xs ++ [0])
pascal n = take n (iterate next [1])
main = do
n <- readLn :: IO Int
mapM_ putStrLn $ map show $ pascal n
Which works quite well, except for the printing. When I apply pascal 4 I get:
[1]
[1,1]
[1,2,1]
[1,3,3,1]
When what I really want is this:
1
1 1
1 2 1
1 3 3 1
Is there any way I can do this?
Define your own pretty-printing function:
import Data.List (intercalate)
show' :: Show a => [a] -> String
show' = intercalate " " . map show
You could unwords / unlines:
import Data.List
...
putStr $ unlines $ map (unwords . map show) $ pascal n

Resources