what intuitive meaning of join
monad?
the monads-as-containers analogies make sense me, , inside these analogies join
makes sense. value double-wrapped , unwrap 1 layer. know, monad not container.
how might 1 write sensible, understandable code using join
in normal circumstances, when in io
?
for list monad, join
concat
, , concatmap
join . fmap
. join
implicitly appears in list expression uses concat
or concatmap
.
suppose asked find of numbers divisors of number in input list. if have divisors
function:
divisors :: int -> [int] divisors n = [ d | d <- [1..n], mod n d == 0 ]
you might solve problem this:
foo xs = concat $ (map divisors xs)
here thinking of solving problem first mapping divisors function on of input elements , concatenating of resulting lists. might think "functional" way of solving problem.
another approch write list comprehension:
bar xs = [ d | x <- xs, d <- divisors x ]
or using do-notation:
bar xs = x <- xs d <- divisors return d
here might said we're thinking little more imperatively - first draw number list xs
; draw divisors divisors of number , yield it.
it turns out, though, foo
, bar
same function.
morever, these 2 approaches same in any monad. is, monad, , appropriate monadic functions f , g:
do x <- f y <- g x same as: (join . fmap g) f return y
for instance, in io monad if set f = getline
, g = readfile
, have:
do x <- getline y <- readfile x same as: (join . fmap readfile) getline return y
the do-block more imperative way of expressing action: first read line of input; treat returned string file name, read contents of file , return result.
the equivalent join expression seems little unnatural in io-monad. shouldn't using in same way used concatmap
in first example.