Parallelizing evaluation and pointwise addition of lists - haskell

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.

Related

What's preventing IO flush in my code?

I tried solving this, and the following is trial stuff.
When I test this in ghci with hSetBuffering stdout NoBuffering, solveAct 1, 15 10, ghci showed few lines of results and blocked much time, and showed rest result at once.
How can I see the intermediate results in real time?
import Control.Monad
import Data.List
import Data.Maybe
import System.IO
readInts = fmap read . words <$> getLine :: IO [Int]
main = do
t <- readLn :: IO Int
hSetBuffering stdout NoBuffering
sequence_ $ solveAct <$> [1..t]
showTable x = intercalate "\n" $ intercalate " " . fmap show <$> x
solveAct i = do
[j, n] <- readInts
putStrLn $ "Case #" ++ show i ++ ":"
putStrLn $ showTable (take n $ solve (j-1))
digits n = [[x ^ y | y <- [1..n-1]] | x <- [2..10]]
primes = 2 : [x | x <- [3,5..], all (\y -> x `rem` y /= 0) $ takeWhile (<= intSqrt x) primes]
intSqrt = floor . sqrt . fromIntegral
getNDivisor n = listToMaybe [x | x <- takeWhile (<= intSqrt n) primes, n `rem` x == 0]
casesOfMat = subsequences . transpose . digits
casesOfJam n = fmap ([1 + x^n | x <- [2..10]]:) $ casesOfMat n
eachBaseReps n = fmap sum . transpose <$> casesOfJam n
solve :: Int -> [[Int]]
solve n = do
decimals <- eachBaseReps n
let divs = getNDivisor <$> decimals
guard $ all isJust divs
return $ last decimals : catMaybes divs
You are seeing the results in real time. It's just that the computation of all isJust . map getNDivisor takes a long time for the third element of eachBaseReps 14.

Error in recursive function / trying to find all subdirectories of a given directory

I'm trying to write a function that returns all subdirectories of a given directory (recursive).
What I have so far is:
import System.Directory
import Control.Monad
import Data.List
getSubDirs :: FilePath -> IO [FilePath]
getSubDirs dir =
getDirectoryContents dir
>>= filterM (\x -> return $ x /= "." && x /= "..")
>>= mapM (makeAbsolute . (\x -> dir ++ "/" ++ x))
>>= filterM doesDirectoryExist
>>= return . reverse
getDirTree :: [FilePath] -> IO [FilePath]
getDirTree [] = return []
getDirTree l#(x:xs) = do
a <- getSubDirs x >>= getDirTree
b <- getDirTree xs
return (nub $ l ++ a ++ b)
Which seems to work. But there is something wrong with the recursion - I would like to get rid of the nub in getDirTree.
This looks wrong:
getDirTree l#(x:xs) = do
-- ...
b <- getDirTree xs
return (nub $ l ++ a ++ b)
The last line adds l which is x:xs with b, which will contain the l argument in the getDirTree xs call, so b will contain xs. Hence xs is included twice (at every recursive step!).
Try return ( x : a ++ b ) instead.
This seems to work:
getDirTree' :: FilePath -> IO [FilePath]
getDirTree' path = do
subs <- getSubDirs path
as <- mapM getDirTree' subs
return $ subs ++ concat as

How to set getLine to only receive strings that can be converted to numbers?

main = do
putStrLn "Hello,Name please?"
first <- getLine
second <- getLine
third <- getLine
if (second == "divide") then putStrLn (show (read first ::Double )/ (read third :: Double))
else putStrLn "Cannot do"
So i want a number in first and third variables,and the second variable will be given the work divide and the if statement will begin and convert the String in first to a Double.But i think the issue is that the variable First is expecting a String like "one" that cannot be converted to a Double.How to fix this to allow getLine to only receive Strings that can be changed in numbers
Here's a quick idea that could help you:
import Control.Applicative
import Data.Char
getNum :: (Num a, Read a) => IO (Maybe a)
getNum = do
(x, xs) <- break (not . isDigit ) <$> getLine
case xs of
[] -> return $ Just $ read x
_ -> return Nothing
main :: IO ()
main = do
x <- getNum :: IO (Maybe Double)
case x of
Nothing -> do
putStrLn "Not a number, try again"
main
Just x' ->
putStrLn $ "Your number: " ++ show x'
return ()
You cannot "make" getLine accept only numbers, you make a function that does. You can even modify this function to accept only the first set of numbers before a non-digit (right now it returns Nothing if any non-digit is in the string).
Update
Here's a program that asks for two numbers and an operation, doing some value checking:
import Control.Applicative
import Data.Char
import Data.Maybe
getNum :: (Num a, Read a) => IO (Maybe a)
getNum = do
(x, xs) <- break (not . isDigit ) <$> getLine
case xs of
[] -> return $ Just $ read x
_ -> return Nothing
main :: IO ()
main = do
putStr "First: "
x <- getNum :: IO (Maybe Double)
putStr "Operation: "
op <- getLine
putStr "Second: "
y <- getNum :: IO (Maybe Double)
if isJust x && isJust y then do
let
x' = fromJust x
y' = fromJust y
putStr "Result: "
case op of
"divide" -> putStrLn $ show $ x' / y'
"sum" -> putStrLn $ show $ x' + y'
_ -> putStrLn "No operation"
else
putStrLn "Invalid numbers"
return ()

How to print list of tuples like table in 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

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