**Haskell 2** # Comments - There are two kinds of comments in Haskell source code: the till-the-end-of-the-line comments and the multiline comments. Till-the-end-of-the-line comments start with `--` and end with the newline character. The multiline comments start with `{-` and end with `-}`. Multiline comments can be nested. # Pattern matching - Haskell allows us to describe the data or data structure using patterns so code can be expressed succinctly. This style of programming is found in some functional languages, logic language, and advanced text editors. Here are some example patterns in Haskell ```haskell 1 -3 'a' True False [] x:xs (a, b) _ ``` - As you can see, a pattern can be a concrete value like an Int value, a Char value, a Bool value, an empty list. But it can also be more complex like a non-empty list of any element type, a tuple, or even "any data" at all. The `x:xs` pattern matches any nonempty list and we also bind the name `x` to the head element of the list, and bind the name `xs` to its tail. The pattern `(a, b)` matches any 2-tuple, and we also bind the name `a` to the first component of the tuple, and bind `b` to the second. The pattern `_` is called an _anonymous pattern_ or _wildcard_ and it matches any value of any type. # Function definitions by pattern matching - We can write a function definition using pattern matching like this: ```haskell f :: Int -> String f 0 = "zero" f 1 = "one" f (-1) = "negative one" f _ = "something else" ``` The first line declares `f` to be the name of a function with domain `Int` and codomain `String`. `String` is a name that the Prelude declares to be equivalent to `[Char]`. The next four lines serve to define the function `f`. There are four cases. When a user applies this function `f` to some argument, Haskell will try to match the argument of `f` against each pattern, starting from top to buttom. In the very first line that gives a match, the function will return the `String` value on the right hand side of `=` on that line as a result. The anonymous pattern in the last case serves as a catch all. It will match any data successfully, so the function `f` never gives error duing run-time. - A more useful function is `length` which Haskell has already predefined for us. We'll give the function a different name so as to not have any conflict with the Prelude's `length`. ```haskell length' :: [a] -> Int length' [] = 0 length' (_:xs) = 1 + length' xs ``` The first line declares the function `length'` to have a list of element type `a` as its domain, and codomain `Int`. The name `a` is a _type variable_ that stands for any type at all, and needs to begin with a lowercase letter. # `case` expressions - A case expression is another example of Haskell code that uses pattern matching. In fact, function definition using pattern matching is just a short-hand way to write the case expression. The syntax for the case expression looks like this ``` case of -> -> ... -> ``` - You can think of the case expression as a generalization of the `if-then-else` expression. While the `if-then-else` allows two different values, `True` and `False`, to be distinguished, the case expression can distinguish at least two possible values. In fact, the expression ``` if then else ``` is just a short-hand way of writing ``` case of True -> False -> > ``` - Let's rewrite the function `f` above in its full case-expression version. ```haskell f :: Int -> String f n = case n of 0 -> "zero" 1 -> "one" -1 -> "negative one" _ -> "something else" ``` # Anonymous functions (lambda expressions) - So far when we define a function, we always give it a name. However, the essence of a function is the computational process that the name denotes. The name of the function is only important if we want to reference it later. In some situations we just want to define a function, use it, then throw it away. This is when anonymous functions are useful. - Here is an anomymous function that takes a number `x` and doubles it: ```haskell \x -> x + x ``` - Like we mentioned previously, a function is a first-class citizen. We can apply this anonymous function, or pass it as an argument to other function, or put it in some data structure, or have it returned from a function. For example, we can have the following interaction with `ghci`: ```haskell Prelude> (\x -> x + x) 3 6 ``` # Curried functions - The logician Haskell Curry discovered that we may define any function so that it takes exactly one parameter. For example, if `f` is a real-valued function taking two real parameters, then its signature is $$\mathbb{R} \times\mathbb{R} \to \mathbb{R}.$$ Curry suggested that we can view `f` as a function that takes the first real parameter, and returns another function that takes the second real parameter, and returns the same result as before. In other word, `f` can be viewed as having the signature $$\mathbb{R} \to (\mathbb{R} \to \mathbb{R}).$$ This method is called _currying_ and functions using this idea is called _curried functions_. - Here is a trivial example ```haskell add :: Int -> Int -> Int add x = \y -> x + y ``` where we define the add function that takes an Int parameter `x`, and returns a function that takes another parameter `y` and return the sum of `x` and `y`. In fact, Haskell has a short special syntax for defining curried function. Instead of the above, we can also write ```haskell add :: Int -> Int -> Int add = \x -> \y -> x + y ``` or even shorter ```haskell add :: Int -> Int -> Int add = \x y -> x + y ``` or even shorter still ```haskell add :: Int -> Int -> Int add x y = x + y ``` - An interesting aspect of a curried function is that we can apply it partially and get another useful function out of it. For example, after defining `add` we can define a function that takes an Int parameter and returns its successor like this: ```haskell inc :: Int -> Int inc = add 1 ``` # `let` expressions and `where` clauses - A _let expression_ allows you to have local bindings to be used in your expression. For example, ```haskell area :: Double -> Double area r = let pi = 3.14 circumference = 2 * pi * r in 0.5 * circumference * r ``` - Another mechanism for writing local bindings is the _where clause_. The where clause is not an expression but part of a function definition, or a case expression. Here is an example of a where clause ```haskell volume :: Double -> Double volume r = (4 / 3) * area r * r where area x = 3.14 * x * x ``` # Higher order functions - A function that takes some other functions as parameters or returns another function as a result is called a _higher order function_. Haskell predefines many higher order functions. We will look at two of them: `map` and `filter`. All these builtin functions are curried. - First, let's check the type of `map`: ```haskell Prelude> :t map map :: (a -> b) -> [a] -> [b] ``` When we write `map f list`, it applies the function `f` to all elements of `list`, collects the results into another list, and returns that. For example, ```haskell Prelude> map (\x -> x + x) [1, 2, 3] [2, 4, 6] ``` - Now let's look at the type of `filter` ```haskell Prelude> :t filter filter :: (a -> Bool) -> [a] -> [a] ``` When we write `filter f list`, it applies the boolean function `f` to each element of `list` and collects only the ones that give a `True` result into a list, and returns it. For example, ```haskell Prelude> filter odd [1, 20, 3, 14] [1, 3] ``` _---San Skulrattanakulchai_