Differences

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

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
pp:syntax [2020/03/12 18:29]
pdmatei
pp:syntax [2020/03/12 23:18] (current)
pdmatei
Line 41: Line 41:
 <code haskell> f 1 2 </​code>​ <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 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. the code more legible and avoids typing bugs.
Line 54: Line 55:
 (f . g) (h x y) (f . g) (h x y)
 </​code>​ </​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''​+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 ====== ===== Basic datatypes ======
Line 68: Line 106:
  
 where ''​a''​ and ''​b''​ are type variables. 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''​.
 +