0

I've started to work through http://www.cs.nott.ac.uk/~pszgmh/monads for a intro on functional programming course. What better way to try and understand stuff than to actually try and test the code.

Alas, on the second page I encounter the following:

data Expr = Val Int | Div Expr Expr

eval            :: Expr -> Int 
eval (Val n)    = n 
eval (Div x y)  = eval x `div` eval y

Which produces an error when I try to run it. I'm not quite sure why this happens. When I try

eval (Val 4) `div` eval (Val 2) 

in the repl-loop, it works just fine, but

eval 4 `div` eval 2 

Ends in a type inference error.

When I update my definition to the following:

data Expr = Val Int | Div Expr Expr

eval            :: Expr -> Int 
eval (Val n)    = n 
eval (Div x y)  = eval (Val x) `div` eval (Val y)

I get a type error in definition. What is wrong with the first definition? The course uses Hugs by the way.

Apeiron
  • 602
  • 6
  • 17

1 Answers1

3

What eval expects is an argument of a type that eval is defined for. Looking at the signature, it requires an argument of type Expr, either a Val or a Div. eval 4 means that you're passing an Int to the function. For that to work, eval would have to be defined as:

eval :: Int -> Int

By writing (Val 4), you are invoking one of the data constructors of Expr type, creating a new value of type Expr, which you can pass to eval and make the compiler happy.

Kapol
  • 6,383
  • 3
  • 21
  • 46
  • Yeah, I get that much, but then why doesn't eval (Div (Val 4) (Val 2)) work or eval (Div (eval Val 4) (eval Val 2)) ? – Apeiron Dec 06 '15 at 12:08
  • @Apeiron I tried `eval (Div (Val 4) (Val 2))` and it works. The result is `2`. `eval (Div (eval Val 4) (eval Val 2))` doesn't work, because `eval Val 4` will result in an `Int` and you cannot use an `Int` in `Div` constructor - you need an `Expr`. – Kapol Dec 06 '15 at 12:13