Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error while declaring a lambda function: declare an instance first

Tags:

haskell

I am trying to understand lambda functions (i.e. anonymous functions) in Haskell by writing a few simple functions that use them.

In the following example, I am simply trying to take in 3 parameters and add two of the three using an anonymous function and adding the third parameter after that. I am getting an error saying that I must declare an instance first.

specialAdd x y z = (\x y -> x + y) + z

I appreciate any explanation of why my example is not working and/or any explanation that would help me better understand lambda functions.

like image 918
AnchovyLegend Avatar asked Mar 27 '13 13:03

AnchovyLegend


2 Answers

specialAdd x y z = (\x y -> x + y) + z

In this example, what you are trying to do is add a function to a number, which is not going to work. Look at (\x y -> x + y) + z: it has the form a + b. In order for such an expression to work, the a part and the b part must be numbers of the same type.

Haskell is a bit of an unusual language, so its error messages are rarely of the form "you can't do that". So what's going on here is that Haskell sees that (\x y -> x + y) is a function, and since in an expression like a + b, b must be the same type as a, it concludes that b must also be a function. Haskell also allows you to define your own rules for adding non-built-in types; so it can't just give you an error saying "you can't add two functions," but instead the error is "you have not defined a rule that allows me to add two functions."

The following would do what you want:

specialAdd x y z = ((\x y -> x + y) x y) + z

Here you are applying the function (\x y -> x + y) to arguments x and y, then adding the result to z.

like image 54
Luis Casillas Avatar answered Oct 15 '22 12:10

Luis Casillas


A good way to practice anonymous function is to use them with high order function as fold or map.

Using map as an entry point,

Basic definition of map,

map f [] = []
map f (x:xs) = f x : f xs  

Built up an example,

>>> let list = [0..4]
>>> let f x = x + 1

Applying map we obtain,

>>> map f list 
[1,2,3,4,5]

Now, we can omit the declaration of f and replace it using anonymous function,

>>> map (\x->x+1) list 
[1,2,3,4,5]

then we deduce, map f list == map (\x->x+1) list, thus

f = \x-> x + 1 --- The same as f x = x + 1, but this is the equivalent lambda notation.  

then starting with a simple function we see how to translate it into an anonymous function and then how an anonymous function can be rely to a lambda abstraction.

As an exercise try to translate f x = 2*x.

Now more complex, an anonymous function which take two arguments,

Again an working example,

>>> let add x y = x + y
>>> foldl' add 0 [0..4]
10

Can be rewrite using anonymous function as,

>>> foldl' (\x y -> x + y) 0 [0..4]  

Again using equality we deduce that add = \x y -> x + y
Moreover as in hakell all function are function of one argument, and we can partial apply it, we can rewrite our previous anonymous function as, add = \x -> (\y -> x + y).

Then where is the trick ?? Because, I just show the use of anonymous function into high order one, and starting from that, showing how this can be exploited to rewrite function using lambda notation. I mean how can it help you to learn how to write down anonymous function ?

Simply cause I've give you (show you) an existing framework using high order function.
This framework is a huge opportunity to accommodate you with this notation.
Starting from that an infinity range of exercise can be deduce, for example try to do the following.

A - Find the corresponding anonymous function ?

1 - let f (x,y) = x + y in map f [(0,1),(2,3),(-1,1)]  
2 - let f x y = x * y in foldl' f 1 [1..5] 

B - Rewrite all of them using lambda notation into a declarative form (f = \x-> (\y-> ...) 

And so on ....


To summarize,

A function as

(F0)   f x1 x2 ... xn = {BODY of f}

can always be rewrite as,

(F1)   f = \x1 x2 ... xn -> {BODY of f}

where

(F2)   (\x1 x2 ... xn -> {BODY of f})

F2 form are just anonymous function, a pure translation of the function into lambda calculus form. F1 is a declarative lambda notation (because we declare f, as we define it, binding it to the anonymous F2). F0 being the usual notation of Haskeller.

A last note focusing on the fact we can put parenthesis between the argument, this create a closure. Doing that mean that a subset of the function's code can be fully evaluated using a subset of the function's argument, (mean converting to a form where no more free variable occurs), but that's another story.

like image 24
zurgl Avatar answered Oct 15 '22 12:10

zurgl