Haskell/More on functions
As functions are absolutely essential to functional programming, there are several nice features that make using functions easier.
let and where revisited[edit]
First, a few extra words about let
and where
, which are useful to make local function definitions. A function like addStr
from the List processing chapter...
addStr :: Float > String > Float addStr x str = x + read str sumStr :: [String] > Float sumStr = foldl addStr 0.0
... can be rewritten using local bindings in order to reduce clutter on the top level of the program (which makes a lot of sense assuming addStr
is only used as part of sumStr
). We can do that either with a let binding...
sumStr = let addStr x str = x + read str in foldl addStr 0.0
... or with a where
clause...
sumStr = foldl addStr 0.0 where addStr x str = x + read str
... and the difference appears to be only one of style  bindings coming either before or after the rest of the definition. The relation between let
and where
, however, is similar to the one between if
and guards, in that a let...in construct is an expression while a where
clause isn't. That means we can embed a let
binding, but not a where
clause, in a complex expression in this way:
f x = if x > 0 then (let lsq = (log x) ^ 2 in tan lsq) * sin x else 0
The expression within the outer parentheses is selfcontained, and evaluates to the tangent of the square of the logarithm of x
. Note that the scope of lsq
does not extend beyond the parentheses; and therefore changing the thenbranch to
then (let lsq = (log x) ^ 2 in tan lsq) * (sin x + lsq)
wouldn't work  we would have to drop the parentheses around the let
.
Still, where
clauses can be incorporated into case
expressions:
describeColour c = "This colour " ++ case c of Black > "is black" White > "is white" RGB red green blue > " has an average of the components of " ++ show av where av = (red + green + blue) `div` 3 ++ ", yeah?"
In this example, the indentation of the where clause sets the scope of the av variable so that it only exists as far as the RGB red green blue case is concerned. Placing it at the same indentation of the cases would make it available for all cases. Here is an example with guards:
doStuff :: Int > String doStuff x  x < 3 = report "less than three"  otherwise = report "normal" where report y = "the input is " ++ y
Note that since there is one equals sign for each guard there is no place we could put a let
expression which would be in scope of all guards, as the where
clause is. Here we have a situation in which where
is particularly convenient.
Anonymous Functions  lambdas[edit]
An alternative to creating a private named function like addStr
is to create an anonymous function, also known as a lambda function
. For example, sumStr
could have been defined like this:
sumStr = foldl (\x str > x + read str) 0.0
The expression in the parentheses is a lambda function. The backslash is used as the nearest ASCII equivalent to the Greek letter lambda (λ). This example is a lambda function with two arguments, x
and str
, which evaluates to "x + read str". So, the sumStr
presented just above is precisely the same as the one that used addStr
in a let binding.
Lambdas are handy for writing oneoff functions to be used with maps, folds and their siblings, especially where the function in question is simple  as cramming complicated expressions in a lambda can hurt readability.
Since variables are being bound in a lambda expression (to the arguments, just like in a regular function definition), pattern matching can be used in them as well. A trivial example would be redefining tail
with a lambda:
tail' = (\(_:xs) > xs)
Operators and sections[edit]
As noted in a number of occasions, operators such as the arithmetical ones can be used surrounded in parentheses and used prefix, like other functions:
2 + 4 (+) 2 4
Generalizing that point, we can now define the term "operator" clearly: as far as Haskell is concerned it's a function with two arguments and a name consisting entirely of nonalphanumeric characters. Unlike other functions, operators can be used infix straight away. We can define new operators in the usual way; just don't use any alphanumeric characters. For example, here's the setdifference definition from Data.List
:
(\\) :: (Eq a) => [a] > [a] > [a] xs \\ ys = foldl (\zs y > delete y zs) xs ys
Note that, aside from just using operators infix, you can define them infix as well. This is a point that most newcomers to Haskell miss. I.e., although one could have written:
(\\) xs ys = foldl (\zs y > delete y zs) xs ys
It's more common to define operators infix. However, do note that in type declarations, you have to write them with the parentheses.
Sections are a nifty piece of syntactical sugar that can be used with operators. An operator within parentheses and flanked by one of its arguments...
(2+) 4 (+4) 2
... is a new function in its own right. (2+)
, for instance, has the type (Num a) => a > a
. We can pass sections to other functions, e.g. map (+2) [1..4] == [3..6]
. For another example, we can add an extra flourish to the multiplyList
function we wrote back in More about lists:
multiplyList :: Integer > [Integer] > [Integer] multiplyList m = map (m*)
If you have a "normal", prefix function, and want to use it as an operator, simply surround it by backticks:
1 `elem` [1..4]
This is called making the function infix. It's normally done for readability purposes: 1 `elem` [1..4]
reads better than elem 1 [1..4]
. You can also define functions infix:
elem :: (Eq a) => a > [a] > Bool x `elem` xs = any (==x) xs
But once again notice that in the type signature you have to use the prefix style.
Sections even work with infix functions:
(1 `elem`) [1..4] (`elem` [1..4]) 1
You can only make binary functions (that is, those that take two arguments) infix. Think about the functions you use, and see which ones would read better if you used them infix.
Exercises 

