Question

Here's two really simple functions f and g.

{-# LANGUAGE ScopedTypeVariables #-}

module Test where

import Control.Applicative

f :: IO ()
f = do
    y <- (<*>) (pure (show . (*10))) (read <$> readFile "data")
    writeFile "out" y

g :: IO ()
g = do
    y <- (readFile "data" >>= return . show . (*10) . read)
    writeFile "out" y

The file read and *10 in fis written in the applicative style with pure and (<*>). The file read and *10 in g is written in the monadic style, with >>=. (I have deliberately avoided using liftM in g to emphasize the question below).

What is the semantic difference between f and g? Or in this case, is it just a stylistic choice?

Was it helpful?

Solution

show . (*10) . read is a "non-monadic" function - by which I mean, it does not do anything in the IO monad, as you can see from its type.

>>= return . can be shortened to

`liftM`

But

`liftM`

should always be equivalent to

`fmap`

fmap neither needs the monad typeclass nor the applicative typeclass, it merely needs the functor typeclass.

Now turning our attention to the applicative version, this:

(<*>) (pure ...

is equivalent to <$>, which is just fmap.

So in both cases we are "really" just working with a functor operation, inbetween reading and writing, and although you have combined the functions in a slightly different way (we'd need to apply one or more "laws" to translate the two versions into each other), the semantics are - or should be - identical. Certainly they are with the IO monad, anyway.

OTHER TIPS

Yes, the choice is purely stylistic, but both can be tidied up to be more idiomatic:

The applicative functions are best written as operators, and pointfree:

f :: IO ()
f = show . (*10) . read <$> readFile "data" >>= writeFile "out"

In monadic style, it looks neater if you go more wholeheartedly not pointfree, avoiding operators:

g :: IO ()
g = do 
    y <- readFile "data" 
    let x = show . (*10) . read $ y
    writeFile "out" x
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top