How to wrap char literal in IO monad in Haskell? - haskell

I know you're supposed to wrap up the operations you want to perform on a result in a monad rather than unwrap things from the monad.
What I can't find are any idiot-friendly examples of how to do that.
For example, I want to do something like this:
myFunction = do
c <- getChar
if (c == 'q')
then putStrLn "take action 1"
else putStrLn "take action 2"
But you can't compare a char literal to an IO Char directly.
GHCi version is 8.4.4.
Error Message:
[1 of 2] Compiling Lib ( /Users/jamesstrieter/hask-tink/src/Lib.hs, interpreted )
/Users/jamesstrieter/hask-tink/src/Lib.hs:66:18: error:
• Couldn't match expected type ‘IO char’ with actual type ‘Char’
• In the second argument of ‘(==)’, namely ‘'q'’
In the expression: x == 'q'
In an equation for ‘what2do’: what2do x = x == 'q'
• Relevant bindings include
x :: IO char
(bound at /Users/jamesstrieter/hask-tink/src/Lib.hs:66:9)
what2do :: IO char -> Bool
(bound at /Users/jamesstrieter/hask-tink/src/Lib.hs:66:1)
|
66 | what2do x = x == 'q'
| ^^^
Failed, no modules loaded.

The code you posted looks perfectly correct and functional.
do-notation is a way of working with value in monad.
c <- getChar within the do block binds c to the char inside the IO Char you get with getChar. You can compare c == 'q' just fine here because c is a plain char, not an IO Char.
To answer you direct question, you can use the return function to put a pure value into any monad, including IO, so return 'q' "wraps" the character literal 'q' into a monad. This isn't what you want in this case, the code you already have is what you are looking for.

But you can't compare a char literal to an IO Char directly.
Sure, but when you "bind" the result of the IO action it is no longer an IO Char but just a Char so that's why it works.
In more words:
Prelude> :t getChar
getChar :: IO Char
Prelude> c <- getChar
x
Prelude> :t c
c :: Char

One of the most important things to understand about the IO monad is that the expression m >>= f does not execute the action m, nor does it ever call the function f.
Instead, it just creates a new IO action that wraps both m and f, which, when executed, will finally execute m, extract the return value, and then execute the next action calculated on the spot by calling f with that value.
That's it. Your entire Haskell program is nothing but a DSL for building a single IO action that gets assigned to main, which the Haskell runtime will execute for you.
So when you write
-- Rewritten slightly for brevity
myFunction = do
c <- getChar
putStrLn (if (c == 'q')
then "take action 1"
else "take action 2")
this is desugared to
myFunction = getChar >>= (\c ->
putStrLn (if (c == 'q')
then "take action 1"
else "take action 2")
and what you are actually saying is "Build an IO action containing getChar and a function of type Char -> IO (), such that when this action is executed, it executes getChar and passes the resulting Char to the function to produce another IO action to be executed immediately."

Related

Why can't I put a print function statement here?

I am trying following code with try-catch block:
import System.Environment
import System.IO
import System.IO.Error
import Control.Exception
isBinary :: String -> Bool
isBinary ss = do
print "In isBinary fn" -- works if this line is removed.
let ans = any (\c -> ord c > 127) ss
ans
toTry :: String -> IO ()
toTry firline = do
print "In toTry fn."
let answer = isBinary firline
if not answer then do
print "Sent line not binary: "
else
print "Sent line binary"
handler :: IOError -> IO ()
handler e = putStrLn "Whoops, had some trouble!"
ss = "this is a test"
main = do
toTry ss `catch` handler
However, I am getting following error:
$ runghc trycatch3.hs
trycatch3.hs:9:9: error:
• Couldn't match expected type ‘Bool’ with actual type ‘IO Bool’
• In a stmt of a 'do' block: print "in isBinary fn"
In the expression:
do { print "in isBinary fn";
let ans = any (\ c -> ...) ss;
return ans }
In an equation for ‘isBinary’:
isBinary ss
= do { print "in isBinary fn";
let ans = ...;
return ans }
trycatch3.hs:10:30: error:
• Variable not in scope: ord :: Char -> Integer
• Perhaps you meant one of these:
‘or’ (imported from Prelude), ‘odd’ (imported from Prelude)
The error goes away and program works well if the print statement is removed from isBinary function.
Why can't I put print statement in this function?
The answer is, "because types". Specifically:
isBinary :: String -> Bool
isBinary ss = do
....
Since it's a do block, the return type of isBinary must match a monadic type Monad m => m t for some m and some t. Here, since print "" :: IO (), m is IO, so it should've been
isBinary :: String -> IO Bool
isBinary ss = do
and now
print "In isBinary fn" -- works
let ans = any (\c -> ord c > 127) ss -- also works
ans -- doesn't work
ans doesn't work because of types, again. Its type is Bool, but it must be IO Bool -- first, because this do block belongs to IO monad, on account of print; and second, because of the return type of the function as a whole.
Instead, use
return ans
and now it'll work, because return injects a value into the monadic context, and being the last do block value it becomes the value produced by the do block overall (if return val appears in the middle it just passes the val to the next step in the combined computation).
The function toTry will have to be augmented to use the new definition:
toTry :: String -> IO ()
toTry firline = do
print "In toTry fn."
-- let answer = isBinary firline -- incorrect, now!
answer <- isBinary firline -- isBinary ... :: IO Bool
if not answer then do -- answer :: Bool
print "Sent line not binary: "
else
print "Sent line binary"
m a on the right of <-, a on the left.
See this for a general description of do notation.
You might be confused by the same print line working in toTry, but not in isBinary. The difference stems from the declaration:
isBinary :: String -> Bool
This means that isBinary is a pure function (i.e. no side effects), taking a string and returning a boolean. In fact, you could simplify it to
isBinary ss = any (\c -> ord c > 127) ss
or even use the point-free style
isBinary = any (\c -> ord c > 127)
However, toTry is
toTry :: String -> IO ()
I.e. it takes a string and returns the IO monad which is impure (can have side effects, such as printing text to the console).
Haskell is a language that encourages using pure functions, and enforces it using the type system, by forcing the programmer to explicitly mark impure code.
Further reading:
What does "pure" mean in "pure functional language"?
Looking at your code, it seems your use of print in isBinary is not an integral part of what you want the function to do, but merely a debug print statement that will be removed later on. In that case, you do not want to change the type of isBinary to String -> IO Bool (for more on that, see Will Ness' answer), as you don't actually need IO except for debugging. Rather, the core libraries offer the Debug.Trace module, which caters to this kind of situation. With it, we can add your debug print statement like this:
isBinary :: String -> Bool
isBinary ss = trace "In isBinary fn" $ any (\c -> ord c > 127) ss
Then, once you are done debugging, you can remove the use of trace -- and it bears repeating you really should do that later on. Quoting the Debug.Trace documentation:
Functions for tracing and monitoring execution.
These can be useful for investigating bugs or performance problems. They should not be used in production code.

How to dispatch different types from a ContT?

I want to create a generalized form of IO based on ContT. I created a GADT to represent different IO actions:
data Cmd a where
PutChar :: Char -> Cmd ()
GetChar :: Cmd Char
I wrote a function that transforms these into IO commands for use in the IO monad like so:
continueIO :: Cmd a -> IO a
continueIO (PutChar c) = putChar c
continueIO GetChar = getChar
Here's what a sample usage of this should look like:
echoChar :: (Monad m) => ContT r m (Cmd a)
echoChar = ContT $ \k -> do
c <- k GetChar
k (PutChar c)
It should be run with something like runContT echoChar continueIO. However, the PutChar and GetChar commands conflict in their types. How can I dispatch both types from the same ContT?
P.S. Sorry if anything in this question is awkwardly worded. I'm trying to give myself a challenge here and I don't completely understand what I'm trying to do.
Edit: I am not restricted in my solution, and I do not have to use ContT.
Either your commands all need to be closures that return the same type (such as IO (), in which case you can’t do getChar) or you need to have a polymorphic result type that can hold either IO () or IO Char, and ContinueIO needs to take this as its argument. Then you need to decide what happens when you pass an IO Char to GetChar or nothing to PutChar. (This version could be a Monoid with <> = ContinueIO and mempty = id, and then you could foldMap over any Foldable structure.)

How does getLine work in haskell?

Looking at the definition of getLine in the Haskell Prelude,
I get how the recursion works, where you keep asking for a character until you hit a newline and you buildup a list which you then return wrapped in an IO.
However my question is how do the return statements work in this case, specifically how does return (c:....:return "") work when you hit the base case. How do you cons a return "" on to a list?
return isn't a control structure like in most languages. It's a constructor for monadic values. Let's take a look at its type:
return :: Monad m => a -> m a
In this case, given a String value, it produces a IO String value.
The fact that return is the last expression evaluated in each branch of the if doesn't mean return ends execution; other expressions could occur after return. Consider this simple example from the list monad:
foo :: Int -> Int -> [Int]
foo x y = return x ++ return y
In the list monad, return simply creates a new single-item list containing its argument. Those two lists are then concatenated into the final result list returned by the function.
$ return 3 :: [Int]
[3]
$ foo 3 4
[3,4]
do-notation is a syntax sugar.
do x <- e
rest
is equivalent to
e >>= \x -> rest
where >>= is a flatMap or bind operation (it attaches a callback to IO container).
flatMap :: IO a -> (a -> IO b) -> IO b meaning is: given container of type IO a attach a callback of type a -> IO b, fired when container succeeds in its operation, and this produces a new container of type IO b
So
getLine =
getChar >>= \c ->
if c == '\n'
then (return [])
else getLine >>= \rest ->
return (c : rest)
What is means? getLine immediately delegates execution to getChar IO-container, with a callback, which analyses the character passed to it. If its a newline, it does "return """, which is a construction of IO-container, returning empty String immediately.
Otherwise, we call ourselves, grab the rest and return current character attached to rest.
P.S.: return is used to turn a pure value into container, since Monad interface doesn't allow us to bind non-container-producing callbacks (there are very good reasons for this).

Get and put a string in Haskell throws error

I found the following Haskell code, but I'm confused:
main = putStrLn "Enter 1st String:"
>> getLine
>>= \a -> read a
What do the two "greater than" symbols (>>) mean? A new statement?
What do the two "greater than" symbols followed by an equal sign (>>=) mean?
This Haskell code throws the following error:
a.hs:3:13:
No instance for (Read (IO t0)) arising from a use of ‘read’
In the expression: read a
In the second argument of ‘(>>=)’, namely ‘\ a -> read a’
In the expression:
putStrLn "Enter 1st String:" >> getLine >>= \ a -> read a
1) does two greater than symbols mean a new statement?
In this context, yes. In the IO monad, >> is a rough equivalent of the ; in many imperative programming languages.
2) what does two greater than symbols followed by equal sign mean?
x >>= y is like x >> y except it takes the result of x and applies to y, which has to be a function. Briefly put, getLine >>= \a -> action means "read a line, bind that value to variable a, and run action (which can depend from a).
I'd recommend a monad tutorial to fully understand these. You can start with a general tutorial such as LYAH.
Your code is more commonly written in do notation:
main = do
putStrLn "Enter 1st String:"
a <- getLine
read a
where the last line makes no sense: read returns a value but does not do any I/O, so we can not chain that to a sequence of I/O actions. This triggers a compiler error. If you know some imperative programming, think about the pseudocode
print("some message");
a = inputLine();
toInteger(a);
The last line makes no sense: it converts the string into an integer... and then does not use the result in any way.
About your second question: your main is not a valid monadic expression. When specialised to the IO monad, the bind and then operators have type
(>>=) :: IO a -> (a -> IO b) -> IO b
(>>) :: IO a -> IO b -> IO b
If you try to align the types of your main expression, you will identify the problem very quickly:
putStrLn "Enter 1st String:" >> getLine >>= \a -> read a
{ IO () } {IO String} {actual: Read t => String -> t }
{ IO String } {expected: String -> IO t} ??? }
The type expected for the second argument of >>= is String -> IO t, but read doesn't return an IO value.

Output Integer to stdout in Haskell

I have a simple function like:
nth :: Integer -> Integer
And I try to print it's result as follows:
main = do
n <- getLine
result <- nth (read n :: Integer)
print result
The following error is generated:
Couldn't match expected type `IO t0' with actual type `Integer'
In the return type of a call of `nth'
In a stmt of a 'do' expression:
result <- nth (read n :: Integer)
Also tried with putStrLn and a lot of other combinations with no luck.
I can't figure it out and I would need some help, being that I don't fully understand how stuff works around these IOs.
nth is a function, not an IO action:
main = do
n <- getLine
let result = nth (read n :: Integer)
print result
The do syntax unwraps something within a monad. Everything on the right hand side of the arrow must live within the IO monad, otherwise the types don't check. An IO Integer would be fine in your program. do is syntactic sugar for the more explicit function which would be written as follows:
Recall that (>>=) :: m a -> (a -> m b) -> m b
main = getLine >>= (\x ->
nth >>= (\y ->
print y))
But nth is not a monadic value, so it doesn't make sense to apply the function (>>=), which requires something with the type IO a.

Resources