Jonathan David Page talks about whatever he happens to be thinking about. Sometimes other people join in.
A collection of cool people and projects.
A clarification regarding my use of the word "simple(ish)": I am assuming, firstly, that you are already comfortable with programming in an imperative language such as C, Java, or Python, and secondly, that you already know at least a little Haskell.
Haskell type signatures, to the uninitiated, are a little odd. Take the following simple two-argument function:
plus :: Int -> Int -> Int plus a b = a + b
If you're coming from an imperative language, you might be tempted to read that signature as "this function takes an
Int and an
Int and returns an
Int". That'll do in most cases, but it isn't really true. And the fact that it isn't true is a really cool feature of Haskell.
-> arrow is a right-associative operator. So you whould read
Int -> Int -> Int as
Int -> (Int -> Int), which doesn't help anything at all, because now it looks even worse. And now here is the kicker: all functions in Haskell take exactly one argument. One. Even our
plus function there. Which is odd, because it sure looks like it takes two arguments. The thing is, Haskell does a little magic trick for us (which isn't really magic). This magic is called currying.
The trick is that when you do
plus 2 3, two things happen. First, 2 is applied to
plus. Application is a fancy way of saying that an argument is given to a function. This application results in a new function, which also takes one argument. 3 is applied to that function, which one might notate as
(plus 2), and returns an
plus 2 3 is the same as
(plus 2) 3. So the
Int -> (Int -> Int) means that
plus is a function which takes an
Int, returning a function which takes an
Int, returning an
So why is that useful? Well, consider the builtin function
map, which has the signature:
map :: (a -> b) -> [a] -> [b]
Basically, it takes a function which takes a thing of type
a and returns a thing of type
b, and an array of things of type
a. It then spits out an array of things of type
b, which is generated by applying the function to every argument the array of things of type
map (\b -> plus 2 b) [3 1 4 1 6] returns
[5 3 6 3 8].
Now, remember that
(plus 2) returns a function, right? So you could also do:
map (plus 2) [3 1 4 1 6]
and get the same result.
tl;dr: Calling a Haskell function with not enough arguments basically returns what you might think of as a half-called function. It's got some arguments already, you just need to supply the remaining ones. And it's just another function.