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]
You have a few beginner mistakes here.
AntwortenLöschenFirstly, anonymous functions are lambda expressions, i.e, they are functions without names. The term you are looking for is "first class functions".
Also, the operators are functions too, so you don't need most of that code in the haskell version.
Here is how I would write that haskell program.
calc :: [a -> b -> a] -> (a,b) -> [a]
calc funcs arg = map ($ arg) (map uncurry funcs)
is = (12,3)
fs = [(+),(*),(-),div]
main = putStrLn (show (calc fs is))
Hi!
AntwortenLöschenIt's really nice that someone actually reads my stuff.
Thanks for your input, looks like i have still to learn some more.
I thought about a different solution using lamda expressions yesterday after posting the above:
calc :: [a -> a -> a] -> [a] -> [a]
calc (m:ms) (x:y:xs) = (m x y):(calc ms (x:y:xs))
calc _ _ = []
is = [12,3]
fs = [ \a -> \b -> a * b,
\a -> \b -> a + b,
\a -> \b -> a - b,
\a -> \b -> a `div` b]
main = do putStrLn (show (calc fs is))
This looks already simplier than my first version, yet not as sophisticated than yours.
Also, I was not aware of the uncurry function.
Taking your example apart in ghci gave me some further insight on this. Now I've even an idea about what '$' does.