Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell do notation to bind

I´am trying to desugar a do statement in Haskell. I have found some examples here on SO but wasn´t able to apply them to my case. Only thing I can think of is a heavy nested let statement, which seems quite ugly.

Statement in which do notation should be replaced by bind:

do num <- numberNode x
   nt1 <- numberTree t1
   nt2 <- numberTree t2
   return (Node num nt1 nt2)

Any input is highly appreciated =)

like image 729
floAr Avatar asked Jun 06 '13 14:06

floAr


People also ask

What is do notation in Haskell?

Translating the bind operator (>>=) passes a value, namely the result of an action or function, downstream in the binding sequence. do notation assigns a variable name to the passed value using the <- .

What is bind Haskell?

The next function is >>=, or bind. It's like function application, only instead of taking a normal value and feeding it to a normal function, it takes a monadic value (that is, a value with a context) and feeds it to a function that takes a normal value but returns a monadic value.

What is a Haskell Monad?

A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.

What does left arrow mean in Haskell?

The left arrow gets used in do notation as something similar to variable binding, in list comprehensions for the same (I'm assuming they are the same, as list comprehensions look like condensed do blocks), and in pattern guards, which have the form (p <- e). All of those constructs bind a new variable.


3 Answers

numberNode x >>= \num ->
  numberTree t1 >>= \nt1 ->
    numberTree t2 >>= \nt2 ->
      return (Node num nt1 nt2)

Note that this is simpler if you use Applicatives:

Node <$> numberNode x <*> numberTree t1 <*> numberTree t2
like image 160
Gabriella Gonzalez Avatar answered Oct 28 '22 18:10

Gabriella Gonzalez


This is an excellent use case for applicative style. You can replace your entire snippet (after importing Control.Applicative) with

Node <$> numberNode x <*> numberTree t1 <*> numberTree t2

Think of the applicative style (using <$> and <*>) as "lifting" function application so it works on functors as well. If you mentally ignore <$> and <*> it looks quite a lot like normal function application!

Applicative style is useful whenever you have a pure function and you want to give it impure arguments (or any functor arguments, really) -- basically when you want to do what you specified in your question!


The type signature of <$> is

(<$>) :: Functor f => (a -> b) -> f a -> f b

which means it takes a pure function (in this case Node) and a functor value (in this case numberNode x) and it creates a new function wrapped "inside" a functor. You can add further arguments to this function with <*>, which has the type signature

(<*>) :: Applicative f => f (a -> b) -> f a -> f b

As you can see, this is very similar to <$> only it works even when the function is wrapped "inside" a functor.

like image 45
kqr Avatar answered Oct 28 '22 18:10

kqr


I'd like to add to the posts about Applicative above..

Considering the type of <$>:

(<$>) :: Functor f => (a -> b) -> f a -> f b

it looks just like fmap:

fmap :: Functor f => (a -> b) -> f a -> f b

which is also very much like Control.Monad.liftM:

liftM :: Monad m => (a -> b) -> m a -> m b

I think of this as "I need to lift the data constructor into this type"

On a related note, if you find yourself doing this:

action >>= return . f

you can instead do this:

f `fmap` action

The first example is using bind to take the value out of whatever type action is, calling f with it, and then repacking the result. Instead, we can lift f so that it takes the type of action as its argument.

like image 29
dino Avatar answered Oct 28 '22 16:10

dino