Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.haskell > #539 > unrolled thread

Mixing monads / binding

Started byThoai Nguyen <me@thoaionline.com>
First post2019-08-06 14:54 +0000
Last post2019-08-07 14:41 +0000
Articles 4 — 3 participants

Back to article view | Back to comp.lang.haskell


Contents

  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

#539 — Mixing monads / binding

FromThoai Nguyen <me@thoaionline.com>
Date2019-08-06 14:54 +0000
SubjectMixing 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]


#540

FromBenjamin Esham <usenet@esham.io>
Date2019-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]


#541

FromBarry Fishman <barry@ecubist.org>
Date2019-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]


#542

FromThoai Nguyen <me@thoaionline.com>
Date2019-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