How can I execute multiple statements in a single function? - haskell

I am learning Haskell and for an assignment I have to print a Snakes and Ladders game. Starting out, I am trying to print the board and this is what I've done.
import Data.List
aRow :: Int -> String
aRow n = "+" ++ take (4*n) (intercalate "" (repeat "---+")) ++ "\n|" ++ take (4*n) (intercalate "" (repeat " |")) ++ "\n"
board :: Int -> Int -> IO()
board 1 y = putStrLn (aRow y)
I would like another instance of board such that it takes arguments x and y
board x y = putStrLn (aRow y)
board (x-1) y
I know that I can't just call multiple statements like this, but can anyone provide some insight about how I can go along with this? I want to call aRow with argument 'y' and do that 'x' times.
Thanks.
Also: when I call board 1 y I get this as output:
board 1 5
+---+---+---+---+---+
|  |  |  |  |  |

I think the cleanest way is to create the board without doing any IO and then at the end only to print it out using IO.
You can use concat and replicate to achieve this:
board :: Int -> Int -> String
board x y = concat (replicate y (aRow x))
You are probably missing a line at the bottom but I'll let you figure this out!
By the way, take (4*n) (intercalate "" (repeat "---+")) is the same as concat (replicate n "---+") so you could write aRow as:
aRow :: Int -> String
aRow n = '+' : concat (replicate n "---+")
++ "\n|" ++ concat (replicate n " |")
++ "\n"
Edit: I would use unlines :: [String] -> String to concatenate several Strings on multiple lines:
aRow :: Int -> String
aRow n = unlines
[ '+' : concat (replicate n "---+")
, '|' : concat (replicate n " |")
]

So you want to execute an IO (), and then yet another IO () action. Together they should be an IO () as well. So you're looking for a combinator with signature IO () -> IO () -> IO (). You can ask Hoogle about this... oh dear, that gives quite a lot of irrelevant results. But also the right one, namely
(>>) :: Monad m => m a -> m b -> m b
Your IO () -> IO () -> IO () is a special case of this signature, obtained by setting m ~ IO and a ~ b ~ (). So, you can write
board x y = putStrLn (aRow y)
>> board (x-1) y
Because these monadic sequencing operators are quite often used in Haskell, it has special syntactic-sugar syntax for them, namely
board x y = do
putStrLn (aRow y)
board (x-1) y
Ok so this works, but it's not really idiomatic. Manual recursion “loops” with a “counter variable” x are awkward and rather error-prone (you need to get the initial, termination and stepping conditions right). Really, all you're doing there is execute the same action x times in a row. So really you're interested in Int -> IO () -> IO (). Again ask Hoogle; this time the right result comes up a bit earlier...
replicateM_ :: Applicative m => Int -> m a -> m ()
so
board :: Int -> Int -> IO ()
board x y = replicateM_ x $ putStrLn (aRow y)
Even better, as Boomerang remarks, is to avoid IO looping altogether.

You just need to sequence the two monadic functions:
board x y = putStrLn (aRow y) >> board (x - 1) y
or with do notation
board x y = do
putStrLn (aRow y)
board (x - 1) y
Note that x == 0 makes a more natural base case:
board 0 y = return ()
board x y = do
putStrLn (aRow y)
board (x - 1) (aRow y)
See Boomerang's answer for a more idiomatic way of writing the function, though.

Related

Join two IOs with - in haskell

I need to join two IO Strings with a - in between. Here's what I came up with, which works - what's the right way?
import System.Environment
f :: String -> String -> IO String
f x y = (foldl1 (++)) <$> sequence [(getEnv x),(return "-"),(getEnv y)]
You could here use an applicative style function:
f :: String -> String -> IO String
f x y = withHyp <$> getEnv x <*> getEnv y
where withHyp ex ey = ex ++ '-' : ey
So here we join the two Strings that are then joined with a hypen in the middle through the withHyp function.
Or for a list of environment variables that we need to fetch, we can use mapM and perform an intercalate:
import Data.List(intercalate)
f :: [String] -> IO String
f xs = intercalate "-" <$> mapM getEnv xs
I'll be honest, the idea behind your approach actually looks pretty sane to me. To start with, I'd probably use concat intsead of foldl1 (++), and drop some parens, getting us to:
f x y = concat <$> sequence [getEnv x, return "-", getEnv y]
This really doesn't seem that bad to me. But if I really wanted to push farther, here's some thoughts I would have. First, I'd recall the intercalate function.
f x y = intercalate "-" <$> sequence [getEnv x, getEnv y]
There's a handy shorthand for applying a function to each element of a list, too; mapM f = sequence . map f. So:
f x y = intercalate "-" <$> mapM getEnv [x,y]
I would stop there; it looks quite clean and maintainable to me.
One way of joining two IO Strings would be:
dash :: IO String -> IO String -> IO String
dash x y = do
s1 <- x
s2 <- y
return $ s1 <> "-" <> s2
We "unbox" each of x and y to get the contained Strings, then "rebox` them with a hyphen (using the analogy for Functors).
It can be shortened to:
dash = liftA2 (\s1 s2 -> s1 <> "-" <> s2)
Where liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c takes a binary function and "lifts" it into a binary function on Applicatives, which are a superset of Monads.
Your f can then be implemented as f x y = dash (getEnv x) (getEnv y).

putStr inside IO () function

How to call IO () function inside another IO () function? I want to print to standard output then call function to do the same.
For example,
p :: String -> IO ()
p [x] = putStr x
p xs = q xs
q :: String -> IO ()
q (x:xs) = putStr x ++ p xs
Your first problem is with typing
p [x] = putStr x
{- putStr :: String -> IO ()
x :: Char, not a String
-}
and
q (x:xs) = putStr x ++ p xs
{- (++) :: [a] -> [a] -> [a]
putStr x :: IO (), not a list of anything.
-}
Let's look at q first, since it follows from p. You're breaking it down into characters, so you should use putChar rather than putStr
Also we're looking at sequencing actions, so we should either use (>>) or (>>=) depending on whether or not you need the result. In this case the result is a value of the unit type (()) which is a useless result and safe to ignore.
q :: String -> IO ()
q (x:xs) = putChar x >> p xs
{- or using `do` notation:
q (x:xs) = do
putChar x
p xs
-}
p can be changed likewise to use putChar rather than putStr
p :: String -> IO ()
p [x] = putChar x
p xs = q xs
though be aware that you haven't matched an empty list on either p or q.
About this time you should notice that substituting putChar for putStr just so you can break strings down to Chars is kind of backward thinking. p = putStr and you're done. However, if you're committed to this backward thinking:
import Control.Monad (foldM_, mapM_)
p = foldM_ (\_ x -> putChar x) ()
-- or
p = foldM_ ((putChar .) . flip const) ()
-- or
p = mapM_ putChar

Haskell read n numbers from user and return their sum

I'm trying to write a function isums that reads n numbers from user and returns their sum. Also, after each number, the sum up to that number is printed. I have this so far:
isums :: Int -> IO Int
isums n = do
num <- readLn
putStrLn (show (num + sum))
sum <- isums (n - 1)
return (num + sum)
Also I'm not using IORef.
This would probably be easiest to express using a helper function, as the extra requirement of printing the partial sums after each input adds a bit of extra clutter:
isums :: Int -> IO Int
isums n = helper n 0
where
helper 0 acc = return acc
helper m acc = do
x <- readLn
let x' = acc + x
print x'
helper (m - 1) x'
What you're doing is kinda like a fold (look at foldM), only instead of traversing a list, you're getting the values "to be folded" from IO. If we had a function:
accM :: Monad m => (a -> m a) -> m a -> Int -> m a
accM f acc 0 = acc
accM f acc n = accM f (acc >>= f) (n - 1)
Then we could write this as:
isums :: Int -> IO Int
isums n = accM helper (return 0) n
where
helper acc = do
x <- readLn
let x' = acc + x
print x'
return x'
Which is a bit nicer (and more reusable) as it lets us separate the general behaviour (accM) from the specific behaviour (helper).
Here is one more solution: it builds on the last version of the #Willem's one, but instead of using a list of ()'s (which is a bit underwhelming) as a fuel for the loop (foldM) it applies a list of actions for reading the values.
import Control.Monad
isums n = foldM go 0 (replicate n readLn)
where
go s a = do
x <- a
let s' = s + x
print s'
return s'
Here replicate n readLn creates a list of actions, each of which reads an integer. These actions are not evaluated till the go is called during the looping by means of foldM. The fact that we can create such a list without performing actual reading stems from the Haskell's laziness.
You can use replicateM :: Applicative m => Int -> m a -> m [a] for this:
import Control.Monad(replicateM)
isums :: (Read n, Num n) => Int -> IO n
isums n = do
numbers <- replicateM n readLn
return (sum numbers)
So here we repeat readLn the given number of times, and then we return the sum of the numbers list.
An equivalent can be achieved with an fmap:
import Control.Monad(replicateM)
isums :: (Read n, Num n) => Int -> IO n
isums n = fmap sum (replicateM n readLn)
Or even pointfree (and pointless):
import Control.Monad(replicateM)
isums :: (Read n, Num n) => Int -> IO n
isums = fmap sum . flip replicateM readLn
We can also produce a list of partial sums with scanl:
import Control.Monad(replicateM)
isums :: (Read n, Num n) => Int -> IO [n]
isums = fmap (scanl (+) 0) . flip replicateM readLn
and then later process the list, or in case we need to print these, and return the last one, we can perform a mapM on that list, like:
import Control.Monad(replicateM)
isums :: (Read n, Num n) => Int -> IO ()
isums n = fmap (scanl (+) 0) (replicateM n readLn) >>= mapM_ print
Or in case we need to print the partial sums:
isums :: (Read n, Num n, Show n) => Int -> IO n
isums n = foldM f 0 (replicate n ())
where f a _ = readLn >>= \b -> let c = a + b in print c >> return c

haskell: debugging <<loop>> exception

For practising Haskell, I have implemented Fermat's factorization method (see https://en.wikipedia.org/wiki/Fermat%27s_factorization_method). However when I run my program, Haskell keeps telling me:
$ ./fermat 7
fermat: <<loop>>
so it seems, that there's an endless loop in my Code (cmp. http://www.haskell.org/pipermail/haskell-cafe/2013-June/108826.html). Can anyone give me a hint, what I'm doing wrong?
Also I would like to extend the question How to debug Haskell code? for tips on how this particular exception can be debugged.
import Data.List
import System.Environment
import Debug.Trace
isQuad :: Integer -> Bool
isQuad x = a == b
where
a = ceiling $ s
b = floor $ s
s = sqrt (fromIntegral x :: Double)
test :: Integer -> Integer -> Integer -> Bool
test nr n s = trace(show nr ++ " " ++ show n ++ " " ++ show s)
isQuad(
(+)
( (\j -> j * j) s + nr )
(-n)
)
fermat :: Integer -> (Integer, Integer)
fermat n = (s + x, s - x)
where
s = ceiling $ sqrt (fromIntegral x :: Double)
r = trace
(show s ++ " " ++ show n)
(\(Just i) -> i) $
find
(\nr -> test nr n s)
[0..n]
x = floor $ sqrt (fromIntegral r :: Double)
fact :: Integer -> (Integer, Integer)
fact x
| x == 1 = (1, 1)
| even x = (2, x `div` 2)
| otherwise = fermat x
f :: String -> String
f x = x ++ " = " ++ show a ++ " x " ++ show b
where
(a, b) = fact $ (read x :: Integer)
main = do
args <- getArgs
putStrLn $ unlines $ map f args
In fermat, s depends on x, x depends on r, and r depends on s.
Sometimes laziness might make this kind of cyclic dependency ok, but in this case all the dependencies seem to be strict.
This is just from inspection and I don't have any particular advice on how to debug the problem in general beyond that in the linked post.
I would say that <<loop>> implies that the run-time system has been able to detect an infinite loop, which means that a value depends on itself, e.g. let x = x + 1 in x. So that's a bit of a clue for tracking down the problem.
If you wrote an infinite loop in function calls, e.g. let f x = f x + 1 in f 1, it typically would just run forever. Sometimes the optimizer might turn these function calls into values, but it can't do so in general.

Haskell IO function accepting return value from a another function

module PRO where
average1 :: IO Float
avarage1 =
do
putStrLn "Enter Marks in Form of a List"
marks <- getLine
let m = (read marks)::[Int]
x<-(sum' (m))
avg <- x/length (m)
if(x/=[])
then
putStrLn ("empty List")
else
putStrLn ("Your Avarage is " ++ show(avg))
sum' :: (Num a) => [a] -> a
sum' xs = foldl (\acc x -> acc + x) 0 xs
My program doesn't seems to work! My question is why can't I assign avg the returning sum of the sum' function?
module PRO where
average1 :: IO ()
average1 =
do
putStrLn "Enter Marks in Form of a List"
marks <- getLine
let m = (read marks)::[Int]
let x = sum' m
let avg = (fromIntegral x)/(fromIntegral $ length m)
if(m==[])
then
putStrLn ("empty List")
else
putStrLn ("Your Avarage is " ++ (show avg))
sum' :: (Num a) => [a] -> a
sum' xs = foldl (\acc x -> acc + x) 0 xs
i) The type signature of average1 is incorrect, the function does not return a value
ii) [Edit: this point was incorrect]
iii) the average value is a float, so you need to cast the integer arguments
iv) Your test if (x/=[]) is the wrong way round and should use m not x
v) most of your lines are not in the IO monad and so should use let inside a do block
You can't use the <- notation for assigning the return values of sum' m and x/length m. <- can only be used when the right-hand side is a monadic expression (in this case, an IO value), which neither one is, and so you should use let x = sum' m and let avg = x / fromInteger (length m) instead (fromInteger is needed to convert the Int returned by length m to a Fractional value so it can be passed to /). (Also, you need to change x /= [] to m /= [].)

Resources