Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.haskell > #539 > unrolled thread
| Started by | Thoai Nguyen <me@thoaionline.com> |
|---|---|
| First post | 2019-08-06 14:54 +0000 |
| Last post | 2019-08-07 14:41 +0000 |
| Articles | 4 — 3 participants |
Back to article view | Back to comp.lang.haskell
Mixing monads / binding Thoai Nguyen <me@thoaionline.com> - 2019-08-06 14:54 +0000
Re: Mixing monads / binding Benjamin Esham <usenet@esham.io> - 2019-08-06 19:37 +0000
Re: Mixing monads / binding Barry Fishman <barry@ecubist.org> - 2019-08-07 09:30 -0400
RE: Re: Mixing monads / binding Thoai Nguyen <me@thoaionline.com> - 2019-08-07 14:41 +0000
| From | Thoai Nguyen <me@thoaionline.com> |
|---|---|
| Date | 2019-08-06 14:54 +0000 |
| Subject | Mixing monads / binding |
| Message-ID | <dwg2F.243764$Kf5.47661@fx42.iad> |
Hi fam, This is a fairly noob question. Considering the following imaginary functions: someCalculation :: String -> Maybe String someCalculation = Just main :: IO () main = getLine >>= someCalculation >>= putStrLn What I want to do is to run a non-deterministic calculation on an input string, then print the output. In this case, 2 different monads are in use (Maybe & IO). Of course this wouldn't work due to incorrect typing. What would be the right way to handle something like this in Haskell? The someCalculation implementation is just a placeholder, but you get the idea... Many thanks,
[toc] | [next] | [standalone]
| From | Benjamin Esham <usenet@esham.io> |
|---|---|
| Date | 2019-08-06 19:37 +0000 |
| Message-ID | <jz06mssf.wyt3eh@bdesham.net> |
| In reply to | #539 |
Thoai Nguyen wrote:
> Hi fam,
>
> This is a fairly noob question. Considering the following imaginary
> functions:
>
> someCalculation :: String -> Maybe String
> someCalculation = Just
>
> main :: IO ()
> main = getLine >>= someCalculation >>= putStrLn
>
> What I want to do is to run a non-deterministic calculation on an input
> string, then print the output. In this case, 2 different monads are in use
> (Maybe & IO). Of course this wouldn't work due to incorrect typing.
>
> What would be the right way to handle something like this in Haskell?
>
> The someCalculation implementation is just a placeholder, but you get the
> idea...
In Haskell, any non-deterministic calculation is going to end up producing
an IO value, like IO String or IO (Maybe Int) or something like that. More
formally, people refer to this as "a value of type 'IO a'," where "a" is
what's called a "type variable." (In more complicated programs this often
ends up being somewhat obscured by a bunch of monad transformers that rest
on top of the IO monad, so the return value of an impure function might be
"AppT String" instead of "IO String", but under the covers the IO monad is
still involved.)
If your someCalculation function is impure, it needs to have a type more
like
someCalculation :: String -> IO (Maybe String)
if it's possible for the function to fail in some way, or
someCalculation :: String -> IO String
if not. It sounds to me as if your function can indeed fail, so I'll assume
that it's going to return an IO (Maybe String). If you haven't seen this
kind of notation before, it means "a String value that may or may not be
there, embedded within the IO monad." I recommend reading this kind of thing
from the inside out. Note that the type Maybe (IO String) is something
completely different (and I'm not sure I could even describe what it is...
I've never seen that kind of construction before, I don't think.)
A dummy implementation of the someCalculation function with this type
signature looks like
someCalculation :: String -> IO (Maybe String)
someCalculation = return . Just
or, equivalently,
someCalculation :: String -> IO (Maybe String)
someCalculation s = do
return (Just s)
In either version, we first call "Just" on the input to convert it from a
String to a Maybe String. Next we call "return" on the Maybe String to
convert it to an IO (Maybe String).
As for how you'd actually use it, I'd recommend (at least for now) using
do-notation and pattern matching. Your main function as it exists now could
be rewritten
main = do
input <- getLine
result <- someCalculation input
putStrLn result
(although as you point out, this will be rejected by the compiler because
"someCalculation input" has the type Maybe String, not the type IO String
that you need in this context). With the new version of someCalculation,
your main function would become
main = do
input <- getLine
maybeResult <- someCalculation input
case maybeResult of
Just result -> putStrLn result
Nothing -> putStrLn "Oops, it didn't work!"
The case statement is what allows you to deal with the two possibilities for
"maybeResult": it's either "Just result" or else it's "Nothing". You can do
completely different things in the branches of the case statement, if you
want, but both branches must have the same type, and in this particular
situation that type must be IO (). This is also the return type of putStrLn,
so we're good there.
If you're in the kind of situation where, in the case of an error, you want
to just swap in a default value and continue on, you could use the
"fromMaybe" function:
import Data.Maybe (fromMaybe)
main = do
input <- getLine
maybeResult <- someCalculation input
let result = fromMaybe "default value" maybeResult
putStrLn result
Hope this helps,
Benjamin
--
Benjamin Esham
https://esham.io
[toc] | [prev] | [next] | [standalone]
| From | Barry Fishman <barry@ecubist.org> |
|---|---|
| Date | 2019-08-07 09:30 -0400 |
| Message-ID | <7nk1bp6r35.fsf@ecube.ecubist.org> |
| In reply to | #539 |
On 2019-08-06 14:54:01 +00, Thoai Nguyen wrote: > This is a fairly noob question. Considering the following imaginary functions: > > someCalculation :: String -> Maybe String > someCalculation = Just > > main :: IO () > main = getLine >>= someCalculation >>= putStrLn > > > What I want to do is to run a non-deterministic calculation on an > input string, then print the output. In this case, 2 different monads > are in use (Maybe & IO). Of course this wouldn't work due to incorrect > typing. > > What would be the right way to handle something like this in Haskell? > > The someCalculation implementation is just a placeholder, but you get the idea... The first >>= needs to have the same type of Monad on each side of it, which you are not doing. Also if you want to output the result though putStrLn you need a function that converts you Maybe back to a String. answerString :: Maybe String -> String answerString = show If you want to keep someCalculation free of the IO Monad you can nest the Maybe inside the IO Monad: getLine >>= return . someCalculation >>= putStrLn . answerString or: getLine >>= return . answerString . someCalculation >>= putStrLn Note that any 'someCalculation >>= whatever' must return a Maybe, so you can't go from 'Maybe a' to 'IO a' using just >>= operations. -- Barry Fishman
[toc] | [prev] | [next] | [standalone]
| From | Thoai Nguyen <me@thoaionline.com> |
|---|---|
| Date | 2019-08-07 14:41 +0000 |
| Message-ID | <5qB2F.223038$KQ6.218933@fx47.iad> |
| In reply to | #541 |
Thanks for your help guys. I'm gonna go with Barry's implementation (convert and wrap Maybe into IO)
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.haskell
csiph-web