Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
pp:syntax [2020/03/12 18:03]
pdmatei created
pp:syntax [2020/03/12 23:18] (current)
pdmatei
Line 1: Line 1:
 ======= Crash course into Haskell'​s syntax ====== ======= Crash course into Haskell'​s syntax ======
  
-====== Haskell in the Programming Paradigms lecture =======+===== Haskell in the Programming Paradigms lecture ===== 
 + 
 +We use Haskell at PP in order to illustrate some functional programming concepts (or functional programming design patterns) which can be used in any functional or multi-paradigm lecture. These are: 
 +  * programming with side-effect-free (or pure) functions 
 +  * programming with higher-order functions 
 +  * programming with Abstract (or Algebraic) Datatypes 
 +  * programming with lazy evaluation 
 + 
 +With this in mind, we point out that this is not a course about the Haskell language - although we will quite a few of its particular aspects (with IO being a distinguished omission). In this page you will find the subset of programming constructs which are used during the lecture. 
 + 
 +===== Functions in Haskell ===== 
 +Functions are defined as follows: 
 +<​code>​ 
 +<​function name> <​param1>​ ... <param n> = <body expression>​ 
 +</​code>​ 
 + 
 +For instance: 
 +<code haskell>​ 
 +f x y = x + y 
 +</​code>​ 
 + 
 +Anonymous functions can be defined as follows: 
 +<​code>​ 
 +\<​param1>​ ... <param n> -> <body expression>​ 
 +</​code>​ 
 + 
 +For instance: 
 +<code haskell>​ 
 +\x y -> x + y 
 +</​code>​ 
 + 
 +Function calls are of the form: 
 +<​code>​ 
 +<​function name> <v1> ... <​vn>​ 
 +</​code>​ 
 +for a function with **at least** n parameters. 
 + 
 +For instance: 
 +<code haskell> f 1 2 </​code>​ 
 + 
 +==== Parentheses and $ ==== 
 +It is a good practice (**although not always necessary**) to enclose a function call in parentheses,​ e.g. ''​(f 1 2)''​ instead of ''​f 1 2''​. This actually makes 
 +the code more legible and avoids typing bugs. 
 + 
 +To avoid cluttering of nested function calls, e.g. ''​f (g (h x y))'',​ the function application operator ''​$''​ can be used. The type of ''​$''​ is ''​(a->​b)->​a->​b'',​ that is, it takes a function and an argument and applies the latter on the function. The previous call can be rewritten as:  
 +<code haskell>​ 
 +f $ g $ h x y 
 +</​code>​ 
 +You can also interpret ''​$''​ as a means for enforcing precedence (i.e. first ''​h''​ is called, then ''​g''​ then ''​f''​). 
 + 
 +Functional composition is often a good alternative to ''​$''​. For instance, the previous function call can be written as: 
 +<code haskell>​ 
 +(f . g) (h x y) 
 +</​code>​ 
 +Meaning that function ''​(f . g)''​ is called with argument ''​(h x y)''​. Note that ''​(f . g . h) x y''​ is not equivalent, and signifies the call of ''​f . g . h''​ with arguments ''​x''​ and ''​y''​. 
 + 
 +==== Infix and prefix ==== 
 + 
 +Usually (although not mandatory), functions are defined in //prefix// form (as seen in the previous examples). Some Haskell functions are infix (e.g. ''​+'',​ ''​.''​ or ''​$''​). We can //turn// an infix function into a prefix one using parentheses. E.g. '':​t ($)''​ or ''​(+) 1 2''​. Similarly, we can //turn// an prefix function into an infix, using quasiquotes,​ e.g. ''​1 `f` 2''​ where ''​f x y = x + y''​.  
 + 
 +==== where ==== 
 + 
 +Often we would like to define auxiliary functions whose scope (visibility) is limited to our function definition. We can do this using ''​where''​. We illustrate it on several examples: 
 + 
 +<code haskell>​ 
 +f x y = (inc x) + y 
 +          where inc v = v + 1 
 +</​code>​ 
 + 
 +<code haskell>​ 
 +f x y = (inc x) + (dec y) 
 +          where inc v = v + 1 
 +                dec v = v - 1 
 +</​code>​ 
 + 
 +<code haskell>​ 
 +f x y = (inc x) + (dec y) 
 +          where inc v = (g v) + 1 
 +                      where g 0 = 0 
 +                            g _ = 1 
 +                dec v = v - 1 
 +</​code>​ 
 + 
 +<code haskell>​ 
 +f x y = (inc x) + (dec y) 
 +          where inc v = (g v) + 1 
 +                g 0 = 0 
 +                g _ = 1 
 +                dec v = v - 1 
 +</​code>​ 
 + 
 +The last two examples construct functions ''​f''​ with the same behaviour, however they are not identical. In the latter example, the function ''​g''​ is visible in the entire ''​where''​ body, thus other functions defined in the same scope could employ it. 
 + 
 +===== Basic datatypes ====== 
 +The basic datatypes used in the PP lecture are: 
 +  * integers and floats (''​Integer''​ and ''​Float''​) 
 +  * booleans (''​Bool''​) 
 +  * char (''​Char''​) 
 + 
 +The container types are: 
 +  * lists (''​[a]''​) 
 +  * pairs (''​(a,​b)''​) 
 +  * functions (''​a -> b''​) 
 + 
 +where ''​a''​ and ''​b''​ are type variables. 
 + 
 +The base constructors for lists are: 
 +  * ''​[] :: [a]'' ​  (the empty list) 
 +  * ''​(:​) :: a -> [a] -> [a]'' ​   (//​cons//​) 
 + 
 +The list observers are: 
 +  * ''​head :: [a] -> a''​ 
 +  * ''​tail :: [a] -> [a]''​ 
 + 
 +Other distinguished operators are: 
 +  * ''​(++) :: [a] -> [a] -> [a]'' ​ (//​appending two lists//) 
 +   
 +The base constructor pairs is: 
 +  * ''​(,​) :: a -> b -> (a,​b)''​ 
 + 
 +Pair observers are: 
 +  * ''​fst :: (a,b) -> a''​ 
 +  * ''​snd :: (a,b) -> b''​ 
 + 
 +The type ''​String''​ in Haskell is an alias for ''​[Char]''​. 
 + 
 +===== Pattern matching ====== 
 + 
 +A powerful mechanism in Haskell is pattern matching, which allows defining function body-expressions based on how a value is constructed. In a pattern, only base constructors can be used. The simplest example is: 
 + 
 +<code haskell>​ 
 +f [] = ... 
 +f (x:xs) = ... 
 +</​code>​ 
 + 
 +which defines two body expressions,​ one for an argument equal to the empty list, and one for a list constructed via the //cons// operator. Here, ''​x''​ is the first element of the list and ''​xs''​ is the rest of the list. 
 + 
 +Patterns can be combined liberally to express more complicated arguments such as: 
 +  * ''​(x:​y:​xs)''​ - a list of at least two elements 
 +  * ''​(1:​xs)''​ - a list which contains ''​1''​ as its first element 
 +  * ''​[1,​2]''​ - the list ''​[1,​2]''​  
 +  * ''​(1:​2:​[])''​ - same as above 
 +  * ''​(x,​y)''​ - a pair where ''​x''​ is the first element and ''​y''​ is the second 
 +  * ''​( (x:​xs),​(y:​ys) )''​ - a pair where both the first and the second elements are lists of at least one element 
 +  * ''​_''​ - //​anything//​ - or an anonymous value 
 + 
 +Pattern matching in Haskell is not limited to function definitions,​ but can also be used in the body expression of a function, using ''​case''​ expressions:​ 
 +<code haskell>​ 
 +case <​expression>​ of 
 +   <​pattern 1> -> <body expression 1> 
 +   ... 
 +   <​pattern n> -> <body expression n> 
 +</​code>​ 
 + 
 +The ''<​expression>''​ is evaluated to a value, and the value is hence checked to see if it satisfies each pattern in turn. When a pattern is found, the case expression is evaluated to the pattern'​s respective body expression. 
 + 
 +Example: 
 +<code haskell>​ 
 +case foldr (:) [] [1,2,3] of 
 +  [] -> 1 
 +  (x:xs) -> 2 
 +  (x:y:xs) -> 3 
 +  _ -> 4 
 +</​code>​ 
 + 
 +In the previous example, ''​foldr (:) [] [1,​2,​3]''​ evaluates to ''​[1,​2,​3]''​. The first pattern is not satisfied, however the second one is, thus the case expression will return ''​2''​. The third pattern is more particular but occurs after the first satisfying pattern. 
 + 
 +===== Guards ===== 
 + 
 +Instead of relying on how values are constructed,​ a programmer may want to define a function'​s body expression in terms of boolean conditions. This can be done using **guards**, as follows: 
 + 
 +<code haskell>​ 
 +<​function name> <​param1>​ ... <param n> 
 +   | <boolean condition 1> = <body expression 1> 
 +   ... 
 +   | <boolean condition n> = <body expression n> 
 +   | otherwise = <body expression (n+1)> 
 +</​code>​ 
 + 
 +Example: 
 + 
 +<code haskell>​ 
 +f x y 
 +   | x + 5 > y = 1 
 +   | x == y = 2 
 +   | x == head (sort [x,y]) = 3 
 +</​code>​ 
 + 
 +In the previous example, ''​f 1 5''​ will return ''​1''​ while ''​f 4 5''​ will return ''​3''​. 
 +