How to change this into a while loop in Haskell? - haskell

Haskell is challenging! What I figured out so far is that I can do the following to simulate a for-loop in Haskell to get a list of numbers from the user:
myList <- sequence [putStr "Enter an integer: " >> (
\s -> read s :: Int) <$> getLine | t <- [1..5]]
Great! So myList contains five integers that I have entered. Great! But here's the catch. Instead of a for-loop that iterates five times (or any finite number of times) how can I convert the above to the equivalent while-loop?
So what I'm thinking of is this, but it won't work, unfortunately. Is there some "magic" way to make it work?
takeWhile (\x -> x > 0) $ sequence [putStr "Enter an integer: " >> (
\s -> read s :: Int) <$> getLine | t <- [1..]]
The problem is that (\x -> x > 0) works with Ints. (Or any Num type.) But what's coming from that list is really a bunch of IO Ints. x > 0 returns a Bool. I need a function that returns an IO Bool? I'm a little lost. Can someone point the way to Haskell enlightenment for me?! Studying this on my own isn't exactly easy!!! Thank you so much!!!

You cannot write this program with a sequence of an infinite list of IO actions. Any operations you perform "outside" of the sequence will be unable to inspect its contents, and any operations inside the sequence will be unable to stop it from continuing.
Instead, you must write an IO action which reads an Int, inspects it, and decides whether to continue or to stop at that time.
positiveInts :: IO [Int]
positiveInts = do
putStr "Enter an integer: "
i <- readLn
if i <= 0
then pure []
else (i:) <$> positiveInts

#amalloy's answer is great. It's kind of conditional sequencing.
Perhaps we may attempt generalizing it further by inventing takeWhileM (basically conditional sequencing) which sequences only an initial part of an indefinitely long list of actions while a predicate satisfies.
takeWhileM :: Monad m => (a -> Bool) -> [m a] -> m [a]
takeWhileM f (a:as) = a >>= \n -> if f n then (n:) <$> takeWhileM f as
else pure []
So for this particular case i run it like
λ> takeWhileM (> 0) . repeat $ putStr "Enter an integer:" >> readLn
Enter an integer:1
Enter an integer:2
Enter an integer:3
Enter an integer:4
Enter an integer:5
Enter an integer:0
[1,2,3,4,5]

Related

Reading numbers from input Haskell

I want to have a function that reads arbitrary int's until the number '0' is inserted, and then presents the numbers inserted in an ordered list.
For that i wrote this function:
import Data.List
readIntegers :: IO()
readIntegers = do
putStrLn "insert a number: "
num<-getLine
let list = ordList ((read num :: Int):list)
if (read num == 0)
then print list
else readIntegers
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
This compiles just fine, but when i insert the number '0', it gives me this error:
*** Exception: <<loop>>
What am i doing wrong ?
As #phg points out, you are essentially constructing an infinite list, and actually evaluating it causes the loop error. A simple implementation to resolve this issue is to define a helper function which takes an additional parameter - a list to store all the inputs read in from the screen, like so:
readInteger :: IO ()
readInteger = readInteger' []
where
readInteger' x = do
putStrLn "insert a number: "
num<-getLine
if ((read num :: Int) == 0)
then print $ ordList x
else readInteger' $ (read num :: Int):x
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
Please note that the above is essentially just an implementation of #phg's answer, but with some changes to your original logic. Firstly, since 0 is a sentinel value, we shouldn't be appending that to our list. Second, we do not need to sort the list every single time we are adding a value to it. Sorting once at the time of printing/passing to another function is sufficient.
Demo
If you want to read an unspecified number of integers without prompting for user input and cut it off the moment you encounter 0, you would probably do well to use getContents, which will read everything from the standard input as a single string, lazily.
Then, it is a simple matter of parsing it to a list of numbers and doing what you want with it, like so:
readIntegers :: ()
readIntegers = do
a <- getContents
let b = ordList $ takeWhile (/= 0) $ map (\x -> read x :: Int) $ words a
mapM (putStrLn . show) b
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
let list = ordList ((read num :: Int):list)
This is basically a recursive definition of a list of the form [x, x, ...] (like if you wrote an equation saying x = 1 + x). That is perfectly fine by itself, since Haskell is lazy; however, if you try to print list (aka "solve the equation"), it will fail, since it will try to print infinitely many numbers.
You probably have a misconception about the workings of the (:) operator. Haskell functions will never perform an assignment operation and concatenate num onto list by changing it, like in imperative languages. There are only pure functions.
If you want to accumulate all numbers, you should try to come up with a recursive definition of readIntegers, keeping its state (the list) in an additional parameter (there are also more sophisticated ways, hiding the state passing, but more complicated to use for a beginner).
For a more sophisticated solution, note that this is an unfold and you can use unfoldM from Control.Monad.Loops to implement it:
import Control.Monad.Loops (unfoldM)
readInts :: IO [Int]
readInts = unfoldM $ fmap (check . read) getLine
where check x = if x == 0 then Nothing else Just x
This has the nice property that it returns the list in the order in which it was read.

Iteratively printing every integer in a List

Say I have a List of integers l = [1,2]
Which I want to print to stdout.
Doing print l produces [1,2]
Say I want to print the list without the braces
map print l produces
No instance for (Show (IO ())) arising from a use of `print'
Possible fix: add an instance declaration for (Show (IO ()))
In a stmt of an interactive GHCi command: print it
`:t print
print :: Show a => a -> IO ()
So while I thought this would work I went ahead and tried:
map putStr $ map show l
Since I suspected a type mismatch from Integer to String was to blame. This produced the same error message as above.
I realize that I could do something like concatenating the list into a string, but I would like to avoid that if possible.
What's going on? How can I do this without constructing a string from the elements of the List?
The problem is that
map :: (a -> b) -> [a] -> [b]
So we end up with [IO ()]. This is a pure value, a list of IO actions. It won't actually print anything. Instead we want
mapM_ :: (a -> IO ()) -> [a] -> IO ()
The naming convention *M means that it operates over monads and *_ means we throw away the value. This is like map except it sequences each action with >> to return an IO action.
As an example mapM_ print [1..10] will print each element on a new line.
Suppose you're given a list xs :: [a] and function f :: Monad m => a -> m b. You want to apply the function f to each element of xs, yielding a list of actions, then sequence these actions. Here is how I would go about constructing a function, call it mapM, that does this. In the base case, xs = [] is the empty list, and we simply return []. In the recursive case, xs has the form x : xs. First, we want to apply f to x, giving the action f x :: m b. Next, we want recursively call mapM on xs. The result of performing the first step is a value, say y; the result of performing the second step is a list of values, say ys. So we collect y and ys into a list, then return them in the monad:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM f [] = return []
mapM f (x : xs) = f x >>= \y -> mapM f ys >>= \ys -> return (y : ys)
Now we can map a function like print, which returns an action in the IO monad, over a list of values to print: mapM print [1..10] does precisely this for the list of integers from one through ten. There is a problem, however: we aren't particularly concerned about collecting the results of printing operations; we're primarily concerned about their side effects. Instead of returning y : ys, we simply return ().
mapM_ :: Monad m => (a -> m b) ->[a] -> m ()
mapM_ f [] = return ()
mapM_ f (x : xs) = f x >> mapM_ f xs
Note that mapM and mapM_ can be defined without explicit recursion using the sequence and sequence_ functions from the standard library, which do precisely what their names imply. If you look at the source code for mapM and mapM_ in Control.Monad, you will see them implemented that way.
Everything in Haskell is very strongly typed, including code to perform IO!
When you write print [1, 2], this is just a convenience wrapper for putStrLn (show [1, 2]), where show is a function that turns a (Show'able) object into a string. print itself doesn't do anything (in the side effect sense of do), but it outputs an IO() action, which is sort of like a mini unrun "program" (if you excuse the sloppy language), which isn't "run" at its creation time, but which can be passed around for later execution. You can verify the type in ghci
> :t print [1, 2]
print [1, 2]::IO()
This is just an object of type IO ().... You could throw this away right now and nothing would ever happen. More likely, if you use this object in main, the IO code will run, side effects and all.
When you map multiple putStrLn (or print) functions onto a list, you still get an object whose type you can view in ghci
> :t map print [1, 2]
map print [1, 2]::[IO()]
Like before, this is just an object that you can pass around, and by itself it will not do anything. But unlike before, the type is incorrect for usage in main, which expects an IO() object. In order to use it, you need to convert it to this type.
There are many ways to do this conversion.... One way that I like is the sequence function.
sequence $ map print [1, 2]
which takes a list of IO actions (ie- mini "programs" with side effects, if you will forgive the sloppy language), and sequences them together as on IO action. This code alone will now do what you want.
As jozefg pointed out, although sequence works, sequence_ is a better choice here....
Sequence not only concatinates the stuff in the IO action, but also puts the return values in a list.... Since print's return value is IO(), the new return value becomes a useless list of ()'s (in IO). :)
Using the lens library:
[1,2,3] ^! each . act print
You might write your own function, too:
Prelude> let l = [1,2]
Prelude> let f [] = return (); f (x:xs) = do print x; f xs
Prelude> f l
1
2

How to do multiple actions in Haskell

Im trying to write a simple function to learn the IO monad in Haskell. The function is supposed to take the sum of some given integers from the console but when the function has run for example 4 times it says "1*** Exception: Char.digitToInt: not a digit '\n'"
import Data.Char
readInts :: IO ()
readInts = do
putStrLn "Choose nr of ints to sum."
c <- getChar
let i = digitToInt c
-- code.
let sum = getInts i
let str = "\nSum is: " ++ [intToDigit i].
putStrLn str
getInt :: IO Int
getInt = do
c <- getChar
return (digitToInt c)
getInts :: Int -> IO Int
getInts n = if n == 0
then return 0
else
do i <- getInt
j <- getInts
return (i+j)
Can somebody please explain where my recursion is going wrong?
You're simply using the wrong tools to convert between "keyboard data" and numbers. Has little to do with IO.
intTodigit, as the name says, acts on single digits / characters, not on general numbers. What you want is to read / print entire strings, which can handle multi-digit numbers. Replace getChar with getLine, digitToInt with read, and [intToDigit i] with show i. Then it should work fine.
However, it would be better to make some more simplifications.
getInt basically exists already, though in more general form: readLn gets a line from stdin and inteprets it as the required type.
getInts is implemented more complicately than necessary. Explicit recursion over a counting variable (BTW, it has to be getInts (n-1) in the recursion) is ugly; such looping is obviously so common that there exists a standard solution (you need to import Control.Monad) for it which looks alot like loops in imperative languages you might be used to:
getIntsAndSum :: Int -> IO Int
getIntsAndSum n = fmap sum . forM [1 .. n] $ \k -> do
i <- getInt
return i
which can in fact be further simplified to
fmap sum . forM [1 .. n] $ \_ -> getInt
because do blocks a just an optional construct to help you chain actions, but when there's only one action you can simply write that on its own.
Ideally, you would not have to first ask for the number of numbers at all: just gather all numbers you're given, and sum them up. This works, as jamshidh said, very simply with interact.
main = interact processInput
where processInput allInput = show (sum allNumbers)
where allNumbers = map read . lines allInput
and that's it! Nothing else needed. In fact, this can be written yet simpler: you basically have just one simple data-flow pipeline.
main = interact $ show . sum . map read . lines
getChar gets every char, including any "\n" that you type in (which you need to submit the answer). Try filtering these out.
A better way to solve this could be to use "interact" to get the user input, and break apart the data using lines. That way the user could input multi digit numbers, and the "\n"'s would be removed.
The following sums numbers entered at the command line (without any prompting, end inputting by typing ^d).
main = interact (show . sum . fmap read . lines)

How to generate a list of repeated applications of a function to the previous result of it in IO context

As a part of a solution for the problem I'm trying to solve I need to generate a list of repeated application of a function to it's previous result. Sounds very much like iterate function, with the exception, that iterate has signature of
iterate :: (a -> a) -> a -> [a]
and my function lives inside of IO (I need to generate random numbers), so I'd need something more of a:
iterate'::(a -> IO a) -> a -> [a]
I have looked at the hoogle, but without much success.
You can actually get a lazy iterate that works on infinite lists if you use the pipes library. The definition is really simple:
import Pipes
iterate' :: (a -> IO a) -> a -> Producer a IO r
iterate' f a = do
yield a
a2 <- lift (f a)
iterate' f a2
For example, let's say that our step function is:
step :: Int -> IO Int
step n = do
m <- readLn
return (n + m)
Then applying iterate to step generates a Producer that lazily prompts the user for input and generates the tally of values read so far:
iterate' step 0 :: Producer Int IO ()
The simplest way to read out the value is to loop over the Producer using for:
main = runEffect $
for (iterate' step 0) $ \n -> do
lift (print n)
The program then endlessly loops, requesting user input and displaying the current tally:
>>> main
0
10<Enter>
10
14<Enter>
24
5<Enter>
29
...
Notice how this gets two things correct which the other solutions do not:
It works on infinite lists (you don't need a termination condition)
It produces results immediately. It doesn't wait until you run the action on the entire list to start producing usable values.
However, we can easily filter results just like the other two solutions. For example, let's say I want to stop when the tally is greater than 100. I can just write:
import qualified Pipes.Prelude as P
main = runEffect $
for (iterate' step 0 >-> P.takeWhile (< 100)) $ \n -> do
lift (print n)
You can read that as saying: "Loop over the iterated values while they are less than 100. Print the output". Let's try it:
>>> main
0
10<Enter>
10
20<Enter>
30
75<Enter>
>>> -- Done!
In fact, pipes has another helper function for printing out values, so you can simplify the above to a pipeline:
main = runEffect $ iterate' step 0 >-> P.takeWhile (< 100) >-> P.print
This gives a clear view of the flow of information. iterate' produces a never-ending stream of Ints, P.takeWhile filters that stream, and P.print prints all values that reach the end.
If you want to learn more about the pipes library, I encourage you to read the pipes tutorial.
Your functions lives in IO, so the signature is rather:
iterate'::(a -> IO a) -> a -> IO [a]
The problem is that the original iterate function returns an infinite list, so if you try to do the same in IO you will get an action that never ends. Maybe you should add a condition to end the iteration.
iterate' action value = do
result <- action value
if condition result
then return []
else
rest <- iterate' action result
return $ result : rest
Firstly, your resulting list must be in the IO monad, so iterate' must have produce an IO [a], rather than '[a]'
Iterate can be defined as:
iterate (a -> a) -> a -> [a]
iterate f x = x : iterate f (f x)
so we could make an iterateM quite easily
iterateM :: (a -> m a) -> m a -> [m a]
iterateM f x = x : iterateM f (x >>= f)
This still needs your seed value to be in the monad to start though, and also gives you a list of monadic things, rather than a monad of listy things.
So, lets change it a bit.
iterateM :: (a -> m a) -> a -> m [a]
iterateM f x = sequence $ go f (return x)
where
go f x = x : go f (x >>= f)
However, this doesn't work. This is because sequence first runs every action, and then returns. (You can see this if you write some safeDivide :: Double -> Double -> Maybe Double, and then try something like fmap (take 10) $ iterateM (flip safeDivide 2) 1000. You'll find it doesn't terminate. I'm not sure how to fix that though.

How can i use the loop without any error in this code?

This is a program so that the GHC takes a number n from user and then it forms a list of n numbers which again are given by the user. this code is showing some parse error for loop. How can i remove that error?
import System.IO
main = do
putStrLn "Please enter the number"
number <- readLn :: IO Int
putStrLn $ "The num is:" ++ show number
loop number
xs <- sequence [readLn :: IO Int]
putStrLn xs
loop:: Int -> IO ()
loop n = if 0==n then return () else return loop (n-1)
In addition to what the other answers have said:
You don't need to write a loop function.
import System.IO
main = do
putStrLn "Please enter the number"
number <- readLn :: IO Int
putStrLn $ "The num is:" ++ show number
xs <- sequence (replicate number (readLn :: IO Int)) -- pay attention to this line
print xs
So we start with readLn. replicate makes a list of number readLns. (Depending on your perspective, you might think this is the clever bit.)
The clever bit: sequence takes that list of IO actions, and turns it into one big IO action. Each readLn happens in turn, and the return values are collected and returned in a list.
There are three errors in your code. Copying it and starting it in GHC gives the following messages:
temp.hs:9:13
Couldn't match expected type `Char' with actual type `Int'
Expected type: String
Actual type: [Int]
In the first argument of `putStrLn', namely `xs'
In the expression: putStrLn xs
This one is quite clear. putStrLn needs a String, but xs is a list of Ints. So simply using print xs instead of putStrLn xs solves the problem (print = putStrLn . show).
The next two are actually about the the same problem:
temp.hs:13:38:
No instance for (Monad ((->) t0))
arising from a use of `return'
Possible fix: add an instance declaration for (Monad ((->) t0))
In the expression: return loop (n - 1)
In the expression:
if 0 == n then return () else return loop (n - 1)
In an equation for `loop':
loop n = if 0 == n then return () else return loop (n - 1)
temp.hs:13:45:
Couldn't match expected type `IO ()'
with actual type `Int -> IO ()'
In the first argument of `return', namely `loop'
In the expression: return loop (n - 1)
In the expression:
if 0 == n then return () else return loop (n - 1)
The problem is in the types. loop is of type Int -> IO (). So the first branch of the function is alright, because you return (). However, in the else branch, you return something completely different, because return is not some built-in statement of the language, but a normal function. So return loop (n - 1) first lifts your loop function into the monad and than applies it to (n - 1).
Instead, what you want is:
loop n = if n == 0 then return () else loop (n - 1)
Also note that you don't need 0 == n in Haskell, as there is no way to accidentally use assignment instead of equality comparison (it doesn't compile).
Edit: As the other answers pointed out, loop isn't really doing anything - it only calls itself n-1 times and then returns ().
If I understand your intent correctly, you meant to create a "loop" construct that would perform an action n times, and produce a list of the results. In the code you have,
loop number
xs <- sequence [readLn :: IO Int]
But these two statements are separate; you need to instead send the action you wish to be repeated to the loop as inut:
xs <- loop number readLn :: IO [Int]
Now of course you need to rewrite your loop to accept an action as a parameter
loop :: Int -> IO a -> IO [a]
loop 0 action = return [] -- don't perform the action
loop n action = do
x <- action -- perform the action once
xs <- loop (n-1) action -- then perform it (n-1) times
return (x:xs) -- produce the resultant list
Here I've written it with pattern matching, instead of if n == 0. I could just as easily write it with an "if" construct, but I personally tend to find those rather ugly.
But wait, maybe something like this already exists in the standard libraries. Stop...Hoogle time! Hoogling the type signature for our new loop, a -> IO a -> IO [a], we discover replicateM.
xs <- replicateM number readLn :: IO [Int]

Resources