Proper use of do notation

I am trying to understand Monad and I have the following code

fabcd = do one <- a + b two <- c * d three <- one + two return three 

Above compilation

but get an error when I

  * Main> f 1 2 3 4

 : 1: 1:
     No instances for (Num (a0 -> t0), Monad ((->) a0), Monad ((->) t0))
       arising from a use of `f '
     Possible fix:
       add instance declarations for
       (Num (a0 -> t0), Monad ((->) a0), Monad ((->) t0))
     In the expression: f 1 2 3 4
     In an equation for `it ': it = f 1 2 3 4

 : 1: 9:
     No instance for (Num (a0 -> a0 -> t0))
       arising from the literal `4 '
     Possible fix:
       add an instance declaration for (Num (a0 -> a0 -> t0))
     In the fourth argument of `f ', namely` 4'
     In the expression: f 1 2 3 4
     In an equation for `it ': it = f 1 2 3 4

I think I would be one step closer to understand the Monad if I know why the above code does not work on
f 1 2 3 4

+4
source share
5 answers

The problem is that you confuse wrapped monadic values ​​with pure values.

The first thing to know is the designation of syntactic sugar for regular function calls ( >>= and >> ). This way, it helps to see what your desugars code is, too.

Let's try something simpler

  fab = do one <- a + b return one 

You have the same problem as your code, but easier. To understand why this does not work, we ask: what does it mean? Well, we can rewrite the <- character using >>=

  fab = (a + b) >>= \x -> return x 

(this is not the simplest view, but clearly indicates)

If you check the following in GHCi

  >> :t (>>=) Monad m => ma -> (a -> mb) -> mb 

that is, the function >>= takes: an argument of type m of a and a function from a to m from b and returns a m of b .

How about this code?

 (a + b) 

There will be a number. How about the other half

  \x -> return x 

Takes an object of type a and returns an object of type ma for any a

So, you need to have a number, this is also some kind of monad. Can you come up with something like that? It is not clear what it will be, which is the reason for the suspicion that this should introduce a check.

One good way to make peace with monads is to look at some specific examples.

Maybe monad expresses calculations that may fail

  instance Monad Maybe where return = Just (>>=) (Just a) f = fa (>>=) Nothing _ = Nothing 

This allows you to say things with a type such as

  f args = do x <- functionThatMightFail args y <- anotherfunctionThatMightFail x return y 

or the same code is easier

 f args = do x <- functionThatMightFail args anotherfunctionThatMightFail x 

or maybe

 f args = functionThatMightFail args >>= anotherfunctionThatMightFail 

On the other hand, the List monad captures the idea of ​​performing the same function for each element of the list, and then combines the results together. There are many simple examples:

 f = do x <- [1,2,3,4] [1..x] 

If you understand these, play with the State monad. This will help you get a more general idea that "monads are computational models." Then I checked Parsec and, of course, IO

+8
source

I’m going to disagree with everyone else and say what you’re doing is almost certainly not connected with monads. You probably just want to use the boring old code instead:

 fabcd = three where one = a + b two = c * d three = one + two 

or more succinctly:

 fabcd = a + b + c * d 
+8
source

I think you are confused by what <- . This operator "unpacks" the data from the monad; IO monad in this case. For example, if you called readLn , you would get a result like IO a . If you want to use a inside the monad, you can put input <- readLn in the do construct and bind the value of a to input . However, the value a + b not included in the IO monad or any monad. In your example, use a + b just type Int . Therefore, if you want to declare a variable equal to it, you use the let statement: let one = a + b . The same goes for your other statements. Therefore, you would like to rewrite this function as:

 fabcd = do let one = a + b let two = c * d let three = one + two return three 

Additional note: adding type signatures often helps to debug things like this. If I add this type signature to your original function: f :: Int -> Int -> Int -> Int -> IO Int , I get a much more useful error that says the expected type was IO t0 , but the actual type was Int in the expression one <- a + b . This should help you understand that <- expects a monadic value as an argument to the right side, but instead got Int .

+3
source

Which Monad are you trying to use?

The closest match to what you are trying to do is the monad ((->) a) function (hence the GHC errors), but since you supply both arguments at each stage, this does not work.

Don't try to understand Monads in general by simply clicking the code in do-blocks: understand how to use a specific Monad (for example, learn how to use IO, learn how to use a monadic parsing library, etc.) and then understand the commonality they have and how it works Monad abstraction.

Each Monad has its own unique characteristics and way of working (because if they did not, then which point has more than one?).

I especially like the approach of Real World Haskell to this: various monads are introduced everywhere with the help of auxiliary combinators to help manage the template, and then in Chapter 7 it is all brought together and the formal form of Monad is officially introduced.

+1
source

If you are trying to use the Maybe motive to handle errors, here is an example:

 module Bbb where import Data.Maybe fabcd = do one <- return $ a + b two <- return $ c * d three <- return $ one + two return three main = print $ fromJust $ f 1 2 3 4 

import Data.Maybe for fromJust which is just

 fromJust (Just x) = x 

If you are just trying to interpret <- as assignments, do not :)

+1
source

Source: https://habr.com/ru/post/1379080/


All Articles