Mittwoch, 23. Dezember 2009

Haskell, C and anonymous functions

There have been some remarkable updates and changes to this post. You might want to skip some parts and look right at the bottom of this entry.

Recently a friend of my asked in how he would benefit from using Haskell. At first I was not able to give him a satisfying answer. But heading on and crawling deeper in the mindset of functional programming and Haskell I came across anonymous functions.
This isn't something specific to functional programming but a rather common concept which simply spoken allows one to pass a function as an argument to another function. There's much more behind it but for me it works to think like that about it.
After reading that this is similar to function pointers in C I hacked together a small example on how to use function pointers in C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct mathfunc {
int (*func)(int *a, int *b);
} mathf;

void loop(int *a, int *b, mathf *mf) {
if (mf == NULL || a == NULL || b == NULL) return;
if (mf->func == NULL) return;
else {
fprintf(stdout, "%i\n", mf->func(a, b));
loop(a, b, ++mf);
}
}

int iadd(int *a, int *b) {
return (*a) + (*b);
}

int imult(int *a, int *b) {
return (*a) * (*b);
}

int isub(int *a, int *b) {
return (*a) - (*b);
}

int idiv(int *a, int *b) {
return (*a) / (*b);
}

int main(int argc, char **argv) {
int a = 12, b = 3;
int *c = &a, *d = &b;

mathf mf[] = {{iadd}, {imult}, {isub}, {idiv}, {NULL}};

loop(c, d, mf);

return 0;
}

Following this I wrote an example in Haskell.
calc :: [a -> a -> a] -> [a] -> [a]
calc (m:ms) (x:y:xs) = (m x y):(calc ms (x:y:xs))
calc _ _ = []

iadd :: (Integral a) => a -> a -> a
iadd x y = x + y

imult :: (Integral a) => a -> a -> a
imult x y = x * y

isub :: (Integral a) => a -> a -> a
isub x y = x - y

idiv :: (Integral a) => a -> a -> a
idiv x y = x `div` y

is = [12,3]
fs = [iadd, imult, isub, idiv]

main = do putStrLn (show (calc fs is))

These two code snippets do exactly (well almost..) the same. Judge yourself which one looks nicer and which you think is more intuitive to read.
After all it's just syntactic sugar..

[Update]
liamoc wrote that I'm not really talking about anonymous functions here but about first class functions. So I read up a bit and now I can contribute this:

Anonymous functions are functions which have no name, they are created on the fly. This can be done in Haskell (and other languages) with the lambda operator: \. The backslash is symbolic for the backslash in the greek lambda letter: λ (see? see? :) )
Personnaly I can't think of a way on how to resemble this in C but maybe some C guru might come up with some tricks.

Furthermore "first class functions" are functions which can be handled like objects. This means that it's possible to instantiate a function on runtime, pass these functions as arguments to other functions (which are then called "higher-order functions") and return functions from functions. For a functional programming language this is something crucial.
This reminds me strong of functors in C++ and I think I'm not to far off with this comparison.

liamoc gave also a nice example of how one could solve the task in a really tight Haskell manner so I also tried to find a smarter solution. This is what I came up with:

calc (f:fs) (x, y) = (f x y):(calc fs (x, y))
calc _ _ = []

functions = [(+),(-),(*),(/)]
xs = (12, 3)

main = do putStrLn (show (calc functions xs))

If you like the idea of anonymous functions try this:

functions = [
\a -> \b -> a * b,
\a -> \b -> a + b,
\a -> \b -> a - b,
\a -> \b -> a `div` b
]

Finally i hope that i got everything right this time. Feel free to correct me. :)
[/Update]

(Real World) Haskell

Thanks to Xmonad I got interested in Haskell recently. So after a few disappointing attempts to learn it from online tutorials like this one or that one I decided to grab Real World Haskell.
Don't get me wrong, the tutorials mentioned above are great and I still return now and then to look up various things. But obviously I am that kind of guy who needs some paper at hand and read it in an calm hour.
I've made some pretty good advancement with this book now and I can only recommend it to everybody interested in functional programming and/or Haskell.