How liftM (: []) works

I am trying to understand the expression below. It converts the list of characters ['a','b','c'] to the list of strings ["a", "b", "c"]

 liftM (:[]) "abc" 

How does this happen?

+7
haskell
source share
4 answers

The liftM function includes a function that receives input and outputs the result to a function that receives input in some monad and outputs in the same monad. Let's look at its definition:

 liftM :: Monad m => (a -> b) -> ma -> mb liftM f mx = mx >>= \x -> return (fx) 

Haskell strings are lists of characters ( type String = [Char] ), so

 "abc" = ['a', 'b', 'c'] :: [Char] 

From your application compiler, a = Char , b = [Char] , ma = [Char] , m = [] . So mb = [[Char]] = [String] . A list is a monad, where return x = [x] and (>>=) = concatMap . Therefore, if we specialize above the definition, we get:

 liftM f mx = concatMap (\x -> [fx]) mx 

And if we apply the arguments, we get:

 concatMap (\x -> [[x]]) ['a', 'b', 'c'] = concat $ map (\x -> [[x]]) ['a', 'b', 'c'] = concat $ [[['a']], [['b']], [['c']]] = [['a'], ['b'], ['c']] = ["a", "b", "c"] 
+10
source share

The robot puzzle operator (:[]) is a section of the cons (:) list and an empty list [] , i.e. (:[]) equivalent to (\x -> x:[]) ; which, in turn, can also be written using the list syntax as (\x -> [x]) .

Rewritten in this way, we have

 liftM (\x -> [x]) "abc" 

The string literal "abc" also just syntactic sugar for the character list ['a', 'b', 'c'] , so we can, in turn, rewrite above a

 liftM (\x -> [x]) ['a', 'b', 'c'] 

liftM is just fmap from the dark days when Functor not a Monad superclass , giving

 fmap (\x -> [x]) ['a', 'b', 'c'] 

The Functor [] instance sets fmap = map , giving

 map (\x -> [x]) ['a', 'b', 'c'] 

which boils down to

 [['a'], ['b'], ['c']] 

Or, back to the string notation

 ["a", "b", "c"] 

Qed

+12
source share

liftM equivalent to fmap , only specialized for monads. (:[]) uses (:) to create a function that creates lists of one item. Just as (+2) is a compact way of writing (\x -> x + 2) , (:[]) equivalent to (\x -> x : []) or (\x -> [x]) .

Your expression could be written as:

 fmap (\x -> [x]) "abc" 

The existence of liftM reflects the fact that any legal Monad can be made in Functor by doing fmap fm = m >>= \x -> return (fx) . You can always replace liftM with fmap , so the only reasons for using it are:

  • to determine fmap for free if you already have a Monad instance (and you don't want to use the GHC DeriveFunctor ) and

  • a completely optional style choice (if you write explicitly monodic code and feel that liftM looks better than fmap ).

+9
source share

liftM defined as:

 liftM fm = m >>= \x -> return (fx) 

We use liftM with a list of (characters), so we need to look at an instance of the Monad list to see how >>= and return are defined:

 instance Monad [] where return x = [x] xs >>= f = concat (map f xs) 

Thus,

 liftM f xs = xs >>= \x -> return (fx) = concat (map (\x -> [fx]) xs) 

concat outside and [ ] on the inside cancel each other out, therefore

 liftM f xs = map (\x -> fx) xs = map f xs 

In other words, liftM in the monad list is just map .

 map (:[]) ['a', 'b', 'c'] = [(: []) 'a', (: []) 'b', (: []) 'c'] = ['a' : [], 'b' : [], 'c' : []] = [['a'], ['b'], ['c']] = ["a","b","c"] 

because a string is just a list of characters.

+7
source share

All Articles