Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applicative vs monadic style for simple IO example

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?

like image 840
Rob Stewart Avatar asked Feb 13 '26 23:02

Rob Stewart


1 Answers

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.

like image 166
Robin Green Avatar answered Feb 16 '26 17:02

Robin Green



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!