Why i can't do this? Its forbidden the use of 'do' in this question :/ How i can call words in my list and at same time result an IO? Thanks.. this is my actual code :/
main :: IO()
main =
putStr "Name of File: " >>
getLine >>=
\st ->
openFile st ReadMode >>=
\handle ->
hGetContents handle >>=
\y ->
words y >>=
\strings ->
strings !! 1 >>=
\string->
putStr string
[Edit] Solution :
main :: IO()
main =
putStr "Name of File: " >>
getLine >>=
\st ->
openFile st ReadMode >>=
\handle ->
hGetContents handle >>=
\y ->
return (words y) >>=
\strings ->
return (strings !! 1) >>=
\string->
putStr string
Use return (words y)
instead of just words y
. return
wraps a pure value (such as the [String]
that words
returns) into a monad.
From your wording, it sounds like this question is homework. If so, it should be tagged as such.
(This doesn't directly answer the question, but it will make your code more idiomatic and thus easier to read.)
You are using the pattern \x -> f x >>= ...
a lot, this can (and should) be eliminated: it is (mostly) unnecessary noise which obscures the meaning of the code. I won't use your code, since it is homework but consider this example (note that I'm using return
as suggested by the other answer):
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (lines str) >>=
\lns -> return (length lns) >>=
\num -> print num
(It reads a file name from the user, and then prints the number of lines in that file.)
The easiest optimisation is the section where we count the number of lines (this corresponds to the part where you are separating the words and getting the second one): the number of lines in a string str
is just length (lines str)
(which is the same as length . lines $ str
), so there is no reason for us to have the call to length
and the call to lines
separate. Our code is now:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (length . lines $ str) >>=
\num -> print num
Now, the next optimisation is on \num -> print num
. This can be written as just print
. (This is called eta conversion). (You can think about this as "a function that takes an argument and calls print
on it, is the same as print
itself"). Now we have:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (length . lines $ str) >>= print
The next optimisation we can do is based on the monad laws. Using the first one, we can turn return (length . lines $ str) >>= print
into print (length . lines $ str)
(i.e. "creating a container that contains a value (this is done by return
) and then passing that value to print
is the same as just passing the value to print
"). Again, we can remove the parenthesis, so we have:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> print . length . lines $ str
And look! We have an eta-conversion we can do: \str -> print . length . lines $ str
becomes just print . length . lines
. This leaves:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>= print . length . lines
At this point, we can probably stop, since that expression is much simpler than our original one (we could keep going, by using >=>
if we wanted to). Since it is so much simpler, it is also easier to debug (imagine if we had forgotten to use lines
: in the original main
it wouldn't be very clear, in the last one it's obvious.)
In your code, you can and should do the same: you can use things like sections (which mean \x -> x !! 1
is the same as (!! 1)
), and the eta conversion and monad laws I used above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With