Jump to content

Haskell features: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
m Layout: Updated F# link so it goes straight to the article about the programming language
 
(231 intermediate revisions by 39 users not shown)
Line 1: Line 1:
{{original research|date=September 2018}}
This article describes the features in [[Haskell (programming language)|'''Haskell98''']].
This article describes the features in the [[programming language]] '''[[Haskell]]'''.



== Examples ==
== Examples ==

=== Factorial ===
=== Factorial ===
A simple example that is often used to demonstrate the syntax of [[functional language]]s is the [[factorial]] function for non-negative integers, shown in Haskell:
A simple example that is often used to demonstrate the [[Syntax (programming languages)|syntax]] of [[functional language]]s is the [[factorial]] function for non-negative integers, shown in Haskell:


<source lang="haskell">
<syntaxhighlight lang="haskell">
factorial :: Integer -> Integer
factorial :: Integer -> Integer
factorial 0 = 1
factorial 0 = 1
factorial n | n > 0 = n * factorial (n-1)
factorial n = n * factorial (n-1)
</syntaxhighlight>
</source>


Or in one line:
Or in one line:
<source lang="haskell">
<syntaxhighlight lang="haskell">
factorial n = if n > 0 then n * factorial (n-1) else 1
factorial n = if n > 1 then n * factorial (n-1) else 1
</syntaxhighlight>
</source>


This describes the factorial as a recursive function, with one terminating base case. It is similar to the descriptions of factorials found in mathematics textbooks. Much of Haskell code is similar to standard [[mathematical notation]] in facility and syntax.
This describes the factorial as a recursive function, with one terminating base case. It is similar to the descriptions of factorials found in mathematics textbooks. Much of Haskell code is similar to standard [[mathematical notation]] in facility and syntax.


The first line of the factorial function describes the ''type'' of this function; while it is optional, it is considered to be good style<ref>HaskellWiki: [http://www.haskell.org/haskellwiki/Type_signatures_as_good_style Type signatures as good style]</ref> to include it. It can be read as ''the function factorial'' (<tt>factorial</tt>) ''has type'' (<tt>::</tt>) ''from integer to integer'' (<tt>Integer -> Integer</tt>). That is, it takes an integer as an argument, and returns another integer. The type of a definition is inferred automatically if the programmer didn't supply a type annotation.
The first line of the factorial function describes the ''type'' of this function; while it is optional, it is considered to be good style<ref>HaskellWiki: [http://www.haskell.org/haskellwiki/Type_signatures_as_good_style Type signatures as good style]</ref> to include it. It can be read as ''the function factorial'' (<code>factorial</code>) ''has type'' (<code>::</code>) ''from integer to integer'' (<code>Integer -> Integer</code>). That is, it takes an integer as an argument, and returns another integer. The type of a definition is [[type inference|inferred]] automatically if no type annotation is given.

The second line relies on [[pattern matching]], an important feature of Haskell. Note that parameters of a function are not in parentheses but separated by spaces. When the function's argument is 0 (zero) it will return the integer 1 (one). For all other cases the third line is tried. This is the [[recursion]], and executes the function again until the base case is reached.


The second line relies on [[pattern matching]], an important feature of Haskell. Note that parameters of a function are not in parentheses but separated by spaces. When the function's argument is 0 (zero) it will return the integer 1 (one). For all other cases the third line is tried. This is the [[recursion]], and executes the function again until the base case is reached.
A [[guard (computing)|guard]] protects the third line from negative numbers for which a factorial is undefined. Without the guard this function would, if called with a negative number, recurse through all negative numbers without ever reaching the base case of 0. As it is, the pattern matching is not complete: if a negative integer is passed to the factorial function as an argument, the program will fail with a runtime error. A final case could check for this error condition and print an appropriate error message instead.


Using the <tt>product</tt> function from the Prelude, a number of small functions analogous to [[C (programming language)|C]]'s [[C standard library|standard library]], and using the Haskell syntax for arithmetic sequences, the factorial function can be expressed in Haskell as follows:
Using the <code>product</code> function from the Prelude, a number of small functions analogous to [[C (programming language)|C]]'s [[C standard library|standard library]], and using the Haskell syntax for arithmetic sequences, the factorial function can be expressed in Haskell as follows:


<source lang="haskell">
<syntaxhighlight lang="haskell">
factorial n = product [1..n]
factorial n = product [1..n]
</syntaxhighlight>
</source>


Here <tt><nowiki>[1..n]</nowiki></tt> denotes the arithmetic sequence {{nowrap|1, 2, …, ''n''}} in list form. Using the Prelude function <tt>enumFromTo</tt>, the expression <tt><nowiki>[1..n]</nowiki></tt> can be written as <tt>enumFromTo 1 n</tt>, allowing the factorial function to be expressed as
Here <code><nowiki>[1..n]</nowiki></code> denotes the arithmetic sequence {{nowrap|1, 2, …, ''n''}} in list form. Using the Prelude function <code>enumFromTo</code>, the expression <code><nowiki>[1..n]</nowiki></code> can be written as <code>enumFromTo 1 n</code>, allowing the factorial function to be expressed as
<source lang="haskell">
<syntaxhighlight lang="haskell">
factorial n = product (enumFromTo 1 n)
factorial n = product (enumFromTo 1 n)
</syntaxhighlight>
</source>


which, using the [[function composition operator]] (expressed as a dot in Haskell) to compose the product function with the [[currying|curried]] enumeration function can be rewritten in [[point-free programming|point-free style]]:<ref>HaskellWiki: [http://haskell.org/haskellwiki/Pointfree Pointfree]</ref>
which, using the [[function composition operator]] (expressed as a dot in Haskell) to compose the product function with the [[currying|curried]] enumeration function can be rewritten in [[point-free programming|point-free style]]:<ref>HaskellWiki: [http://haskell.org/haskellwiki/Pointfree Pointfree]</ref>


<source lang="haskell">
<syntaxhighlight lang="haskell">
factorial = product . enumFromTo 1
factorial = product . enumFromTo 1
</syntaxhighlight>
</source>


In the Hugs interpreter, one often needs to define the function and use it on the same line separated by a <tt>where</tt> or <tt>let</tt>..<tt>in</tt>. For example, to test the above examples and see the output <tt>120</tt>:
In the Hugs interpreter, one often needs to define the function and use it on the same line separated by a <code>where</code> or <code>let</code>..<code>in</code>. For example, to test the above examples and see the output <code>120</code>:


<source lang="haskell">
<syntaxhighlight lang="haskell">
let { factorial n | n > 0 = n * factorial (n-1); factorial _ = 1 } in factorial 5
let { factorial n | n > 0 = n * factorial (n-1); factorial _ = 1 } in factorial 5
</syntaxhighlight>
</source>


or
or


<source lang="haskell">
<syntaxhighlight lang="haskell">
factorial 5 where factorial = product . enumFromTo 1
factorial 5 where factorial = product . enumFromTo 1
</syntaxhighlight>
</source>


The GHCi interpreter doesn't have this restriction and function definitions can be entered on one line and referenced later.
The [[GHCi]] interpreter doesn't have this restriction and function definitions can be entered on one line (with the <code>'''let'''</code> syntax without the <code>'''in'''</code> part), and referenced later.


=== More complex examples ===
=== More complex examples ===
==== Calculator ====
In the Haskell source immediately below, "::" can be read as "has type"; "a —> b" can be read as "is a function from a to b". (Thus the Haskell "calc :: String —> [Float]" can be read as "<tt>calc</tt> has type of function from Strings to lists of Floats".)
In the second line "calc = ... " the equals sign can be read as "can be"; thus multiple lines with "calc = ... " can be read as multiple possible values for <tt>calc</tt>, depending on the circumstance detailed in each line.
In the Haskell source immediately below, <code>::</code> can be read as "has type"; <code>a -> b</code> can be read as "is a function from a to b". (Thus the Haskell <code>calc :: String -> [Float]</code> can be read as "<code>calc</code> has type of a function from Strings to lists of Floats".)
In the second line <code>calc = ...</code> the equals sign can be read as "can be"; thus multiple lines with <code>calc = ...</code> can be read as multiple possible values for <code>calc</code>, depending on the circumstance detailed in each line.


A simple [[Reverse Polish notation]] calculator expressed with the [[higher-order function]] <code>[[foldl]]</code> whose argument ''f'' is defined in a ''where'' clause using [[pattern matching]] and the [[type class]] ''Read'':
A simple [[Reverse Polish notation]] calculator expressed with the [[higher-order function]] <code>[[foldl]]</code> whose argument ''f'' is defined in a ''where'' clause using [[pattern matching]] and the [[type class]] ''Read'':


<source lang="haskell">
<syntaxhighlight lang="haskell">
calc :: String -> [Float]
calc :: String -> [Float]
calc = foldl f [] . words
calc = foldl f [] . words
Line 73: Line 71:
f (x:y:zs) "*" = (y * x):zs
f (x:y:zs) "*" = (y * x):zs
f (x:y:zs) "/" = (y / x):zs
f (x:y:zs) "/" = (y / x):zs
f xs y = read y : xs
f (x:y:zs) "FLIP" = y:x:zs
f zs w = read w : zs
</source>
</syntaxhighlight>


The empty list is the initial state, and ''f'' [[Interpreter (computing)|interpret]]s one word at a time, either matching two numbers from the head of the list and pushing the result back in, or parsing the word as a [[floating-point number]] and prepending it to the list.
The empty list is the initial state, and ''f'' [[Interpreter (computing)|interpret]]s one word at a time, either as a function name, taking two numbers from the head of the list and pushing the result back in, or parsing the word as a [[floating-point number]] and prepending it to the list.


==== Fibonacci sequence ====
The following definition produces the list of [[Fibonacci numbers]] in linear time:
The following definition produces the list of [[Fibonacci numbers]] in linear time:
<syntaxhighlight lang="haskell">

<source lang="haskell">
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
</syntaxhighlight>
</source>

The infinite list is produced by [[corecursion]] — the latter values of the list are computed on demand starting from the initial two items 0 and 1. This kind of a definition relies on [[lazy evaluation]], an important feature of Haskell programming. For an example of how the evaluation evolves, the following illustrates the values of ''fibs'' and ''tail fibs'' after the computation of six items and shows how ''zipWith (+)'' has produced four items and proceeds to produce the next item:
The infinite list is produced by [[corecursion]] — the latter values of the list are computed on demand starting from the initial two items 0 and 1. This kind of a definition relies on [[lazy evaluation]], an important feature of Haskell programming. For an example of how the evaluation evolves, the following illustrates the values of ''fibs'' and ''tail fibs'' after the computation of six items and shows how ''zipWith (+)'' has produced four items and proceeds to produce the next item:


fibs = 0 : 1 : 1 : 2 : 3 : 5 : ...
fibs = 0 : 1 : 1 : 2 : 3 : 5 : ...
+ + + + + +
&nbsp; + + + + + +
tail fibs = 1 : 1 : 2 : 3 : 5 : ...
tail fibs = 1 : 1 : 2 : 3 : 5 : ...
= = = = = =
&nbsp; = = = = = =
zipWith ... = 1 : 2 : 3 : 5 : '''8''' : ...
zipWith ... = 1 : 2 : 3 : 5 : '''''8''''' : ...
fibs = 0 : 1 : 1 : 2 : 3 : 5 : '''8''' : ...
fibs = 0 : 1 : 1 : 2 : 3 : 5 : '''''8''''' : ...


The same function, written using GHC's [[parallel list comprehension]] syntax (GHC extensions must be enabled using a special command-line flag '-fglasgow-exts'; see GHC's manual for more):
The same function, written using [[Glasgow Haskell Compiler]]'s [[parallel list comprehension]] syntax (GHC extensions must be enabled using a special command-line flag, here ''-XParallelListComp'', or by starting the source file with <code>{-#&nbsp;LANGUAGE ParallelListComp&nbsp;#-}</code>):
<syntaxhighlight lang="haskell">

<source lang="haskell">
fibs = 0 : 1 : [ a+b | a <- fibs | b <- tail fibs ]
fibs = 0 : 1 : [ a+b | a <- fibs | b <- tail fibs ]
</syntaxhighlight>
</source>
or with regular [[list comprehension]]s:
<syntaxhighlight lang="haskell">
fibs = 0 : 1 : [ a+b | (a,b) <- zip fibs (tail fibs) ]
</syntaxhighlight>
or directly self-referencing:
<syntaxhighlight lang="haskell">
fibs = 0 : 1 : next fibs where next (a : t@(b:_)) = (a+b) : next t
</syntaxhighlight>
With [[State (computer science)|state]]ful [[Generator (computer programming)|generating]] function:
<syntaxhighlight lang="haskell">
fibs = next (0,1) where next (a,b) = a : next (b, a+b)
</syntaxhighlight>
or with <code>unfoldr</code>:
<syntaxhighlight lang="haskell">
fibs = unfoldr (\(a,b) -> Just (a, (b, a+b))) (0, 1)
</syntaxhighlight>
or <code>scanl</code>:
<syntaxhighlight lang="haskell">
fibs = 0 : scanl (+) 1 fibs
</syntaxhighlight>
Using data recursion with Haskell's predefined [[fixpoint combinator]]:
<syntaxhighlight lang="haskell">
fibs = fix (\xs -> 0 : 1 : zipWith (+) xs (tail xs)) -- zipWith version
= fix ((0:) . (1:) . (zipWith (+) <*> tail)) -- same as above, pointfree
= fix ((0:) . scanl (+) 1) -- scanl version
</syntaxhighlight>


==== Factorial ====
The factorial we saw previously can be written as a sequence of functions:
The factorial we saw previously can be written as a sequence of functions:


<source lang="haskell">
<syntaxhighlight lang="haskell">
factorial n = (foldr (.) id [\x -> x*k | k <- [1..n]]) 1
factorial n = foldr ((.) . (*)) id [1..n] $ 1
-- factorial 5 == ((1*) .) ( ((2*) .) ( ((3*) .) ( ((4*) .) ( ((5*) .) id )))) 1
</source>
-- == (1*) . (2*) . (3*) . (4*) . (5*) . id $ 1
-- == 1* ( 2* ( 3* ( 4* ( 5* ( id 1 )))))


factorial n = foldr ((.) . (*)) (const 1) [1..n] $ ()
-- factorial 5 == ((1*) .) ( ((2*) .) ( ((3*) .) ( ((4*) .) ( ((5*) .) (const 1) )))) ()
-- == (1*) . (2*) . (3*) . (4*) . (5*) . const 1 $ ()
-- == 1* ( 2* ( 3* ( 4* ( 5* ( const 1 () )))))

factorial n = foldr (($) . (*)) 1 [1..n] = foldr ($) 1 $ map (*) [1..n]
-- factorial 5 == ((1*) $) ( ((2*) $) ( ((3*) $) ( ((4*) $) ( ((5*) $) 1 ))))
-- == (1*) $ (2*) $ (3*) $ (4*) $ (5*) $ 1
-- == 1* ( 2* ( 3* ( 4* ( 5* 1 ))))
</syntaxhighlight>

=== More examples ===
==== Hamming numbers ====
A remarkably concise function that returns the list of [[Hamming numbers]] in order:
A remarkably concise function that returns the list of [[Hamming numbers]] in order:


<source lang="haskell">
<syntaxhighlight lang="haskell">
hamming = 1 : map (2*) hamming `merge`
hamming = 1 : map (2*) hamming `union` map (3*) hamming
map (3*) hamming `merge` map (5*) hamming
`union` map (5*) hamming
</syntaxhighlight>
where merge (x:xs) (y:ys)

| x < y = x : xs `merge` (y:ys)
Like the various <code>fibs</code> solutions displayed above, this uses corecursion to produce a list of numbers on demand, starting from the base case of 1 and building new items based on the preceding part of the list.
| x > y = y : (x:xs) `merge` ys

| otherwise = x : xs `merge` ys
{{anchor|minus}}
</source>
{{anchor|union}}Here the function <code>union</code> is used as an operator by enclosing it in back-quotes. <!-- Apart from the different application syntax, operators are like functions whose name consists of symbols instead of letters.
-->Its <code>case</code> clauses define how it [[Union (set theory)|merges]] two ascending lists into one ascending list without duplicate items, representing [[Set (mathematics)|sets]] as ordered lists. Its companion function <code>minus</code> implements [[Complement (set theory)#Relative complement|set difference]]:


<!-- source lang="haskell"
Like the various <code>fibs</code> solutions displayed above, this uses corecursion to produce a list of numbers on demand,
union (x:xs) (y:ys) = minus (x:xs) (y:ys) =
starting from the base case of 1 and building new items based on the preceding part of the list.
case compare x y of case compare x y of
LT -> x : union xs (y:ys) LT -> x : minus xs (y:ys)
EQ -> x : union xs ys EQ -> minus xs ys
GT -> y : union (x:xs) ys GT -> minus (x:xs) ys
union xs [] = xs minus xs _ = xs
union [] ys = ys
/source -->
{|
|
<syntaxhighlight lang="haskell">
union (x:xs) (y:ys) = case compare x y of
LT -> x : union xs (y:ys)
EQ -> x : union xs ys
GT -> y : union (x:xs) ys
union xs [] = xs
union [] ys = ys
</syntaxhighlight>
||
<syntaxhighlight lang="haskell">
minus (x:xs) (y:ys) = case compare x y of
LT -> x : minus xs (y:ys)
EQ -> minus xs ys
GT -> minus (x:xs) ys
minus xs _ = xs
--
</syntaxhighlight>
|}


It is possible to generate only the unique multiples, for more efficient operation. Since there are no duplicates, there's no need to remove them:
In this case the producer <code>merge</code> is defined in a <code>where</code> clause and used as an operator by enclosing it in back-quotes.
<!-- Apart from the different application syntax, operators are like functions whose name consists of symbols instead of letters.
Each vertical bar <code>|</code> starts a guard clause with a guard before the equals sign and the corresponding definition after the equals sign.
-->
The branches of the guards define how <code>merge</code> merges two ascending lists into one ascending list without duplicate items.


<syntaxhighlight lang="haskell">
== Syntax ==
smooth235 = 1 : foldr (\p s -> fix $ mergeBy (<) s . map (p*) . (1:)) [] [2,3,5]
where
fix f = x where x = f x -- fixpoint combinator, with sharing
</syntaxhighlight>
This uses the more efficient function <code>merge</code> which doesn't concern itself with the duplicates (also used in the following next function, <code>mergesort</code> ):
<syntaxhighlight lang="haskell">
mergeBy less xs ys = merge xs ys where
merge xs [] = xs
merge [] ys = ys
merge (x:xs) (y:ys) | less y x = y : merge (x:xs) ys
| otherwise = x : merge xs (y:ys)
</syntaxhighlight>
Each vertical bar ( <code>|</code> ) starts a [[guard (computer science)|guard]] clause with a ''guard expression'' before the <code>=</code> sign and the corresponding definition after it, that is evaluated if the guard is true.


=== Layout ===
==== Mergesort ====
Here is a bottom-up [[merge sort]], defined using the [[higher-order function]] <code>until</code>:
<syntaxhighlight lang="haskell">
mergesortBy less [] = []
mergesortBy less xs = head $
until (null . tail) (pairwise $ mergeBy less) [[x] | x <- xs]


pairwise f (a:b:t) = f a b : pairwise f t
Haskell allows indentation to be used to indicate the beginning of a
pairwise f t = t
new declaration. For example, in a ''where'' clause:
</syntaxhighlight>


==== Prime numbers ====
<source lang="haskell">
The mathematical definition of [[Prime numbers|primes]] can be translated pretty much word for word into Haskell:
<syntaxhighlight lang="haskell">
-- "Integers above 1 that cannot be divided by a smaller integer above 1"
-- primes = { n ∈ [2..] | ~ ∃ d ∈ [2..n-1] ⇒ rem n d = 0 }
-- = { n ∈ [2..] | ∀ d ∈ [2..n-1] ⇒ rem n d ≠ 0 }

primes = [ n | n <- [2..], all (\d -> rem n d /= 0) [2..(n-1)] ]
</syntaxhighlight>
This finds primes by [[trial division]]. Note that it is not optimized for efficiency and has very poor performance. Slightly faster (but still very slow)<ref name="hawiki">{{cite web|url=http://www.haskell.org/haskellwiki/Prime_numbers#Turner.27s_sieve_-_Trial_division|title=Prime numbers - HaskellWiki|website=www.haskell.org}}</ref> is this code by [[David Turner (computer scientist)|David Turner]]:
<syntaxhighlight lang="haskell">
primes = sieve [2..] where
sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]
</syntaxhighlight>

Much faster is the optimal trial division algorithm
<syntaxhighlight lang="haskell">
primes = 2 : [ n | n <- [3..], all ((> 0) . rem n) $
takeWhile ((<= n) . (^2)) primes]
</syntaxhighlight>
{{anchor|Sieve of Eratosthenes}}or an unbounded [[sieve of Eratosthenes]] with postponed sieving in stages,<ref>{{cite web|url=http://www.haskell.org/haskellwiki/Prime_numbers#Postponed|title=Prime numbers - HaskellWiki|website=www.haskell.org}}</ref>
<syntaxhighlight lang="haskell">
primes = 2 : sieve primes [3..] where
sieve (p:ps) (span (< p*p) -> (h, t)) =
h ++ sieve ps (minus t [p*p, p*p+p..])
</syntaxhighlight>

or the combined sieve implementation by [[Richard Bird (computer scientist)|Richard Bird]],<ref name="ONeill">O'Neill, Melissa E., [http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf "The Genuine Sieve of Eratosthenes"], [[Journal of Functional Programming]], Published online by Cambridge University Press 9 October 2008 {{doi|10.1017/S0956796808007004}}, pp. 10, 11.</ref>

<syntaxhighlight lang="haskell">
-- "Integers above 1 without any composite numbers which
-- are found by enumeration of each prime's multiples"
primes = 2 : minus [3..]
(foldr (\(m:ms) r -> m : union ms r) []
[[p*p, p*p+p ..] | p <- primes])
</syntaxhighlight>

or an even faster [[Fold (higher-order function)#Tree-like folds|tree-like folding]] variant<ref>{{cite web|url=http://www.haskell.org/haskellwiki/Prime_numbers#Tree_merging|title=Prime numbers - HaskellWiki|website=www.haskell.org}}</ref> with nearly optimal (for a list-based code) time complexity and very low space complexity achieved through telescoping multistage recursive production of primes:
<syntaxhighlight lang="haskell">
primes = 2 : _Y ((3 :) . minus [5,7..] . _U
. map (\p -> [p*p, p*p+2*p..]))
where
-- non-sharing Y combinator:
_Y g = g (_Y g) -- (g (g (g (g (...)))))
-- big union ~= nub.sort.concat
_U ((x:xs):t) = x : (union xs . _U . pairwise union) t
</syntaxhighlight>
Working on arrays by segments between consecutive squares of primes, it's
<syntaxhighlight lang="haskell">
import Data.Array
import Data.List (tails, inits)

primes = 2 : [ n |
(r:q:_, px) <- zip (tails (2 : [p*p | p <- primes]))
(inits primes),
(n, True) <- assocs ( accumArray (\_ _ -> False) True
(r+1,q-1)
[ (m,()) | p <- px
, s <- [ div (r+p) p * p]
, m <- [s,s+p..q-1] ] ) ]
</syntaxhighlight>
The shortest possible code is probably&nbsp; <code>nubBy (((>1) .) . gcd) [2..]</code>. &nbsp;It is quite slow.

== Syntax ==
=== Layout ===
Haskell allows [[Indentation style|indentation]] to be used to indicate the beginning of a new declaration. For example, in a ''where'' clause:

<syntaxhighlight lang="haskell">
product xs = prod xs 1
product xs = prod xs 1
where
where
prod [] a = a
prod [] a = a
prod (x:xs) a = prod xs (a*x)
prod (x:xs) a = prod xs (a*x)
</syntaxhighlight>
</source>


The two equations for the [[nested function]] <code>prod</code> are aligned vertically, which allows the semi-colon separator to be omitted. In Haskell, indentation can be used in several syntactic constructs, including <code>do</code>, <code>let</code>, <code>case</code>, <code>class</code>, and <code>instance</code>.
The two equations for the nested function <tt>prod</tt> are aligned
vertically, which allows the semi-colon separator to be omitted. In
Haskell, indentation can be used in several syntactic constructs,
including <tt>do</tt>, <tt>let</tt>, <tt>case</tt>, <tt>class</tt>,
and <tt>instance</tt>.


The use of indentation to indicate program structure originates in [[Peter J. Landin]]'s [[ISWIM]] language, where it was called the [[off-side rule]]. This was later adopted by [[Miranda (programming language)|Miranda]], and Haskell adopted a similar (but rather more complex) version of Miranda's off-side rule, which is called "layout". Other languages to adopt [[whitespace character]]-sensitive syntax include [[Python (programming language)|Python]] and [[F Sharp (programming language)|F#]].
The use of indentation to indicate program structure
originates in [[Peter_J._Landin|Landin]]'s [[ISWIM]] language, where it was called the
[[off-side rule]]. This was later adopted by [[Miranda_(programming_language)|Miranda]], and Haskell
adopted a similar (but rather more complicated) version of Miranda's
off-side rule, which it called "layout". Other languages to adopt whitespace-sensitive syntax
include [[Python (programming language)|Python]] and [[F Sharp (programming language)|F#]].


The use of layout in Haskell is optional. For example, the function <tt>product</tt> above can also be written:
The use of layout in Haskell is optional. For example, the function <code>product</code> above can also be written:


<source lang="haskell">
<syntaxhighlight lang="haskell">
product xs = prod xs 1
product xs = prod xs 1
where { prod [] a = a; prod (x:xs) a = prod xs (a*x) }
where { prod [] a = a; prod (x:xs) a = prod xs (a*x) }
</syntaxhighlight>
</source>


The explicit open brace after the <code>where</code> keyword indicates that separate declarations will use explicit semi-colons, and the declaration-list will be terminated by an explicit closing brace. One reason for wanting support for explicit delimiters is that it makes automatic generation of Haskell [[source code]] easier.
The explicit open brace after the <tt>where</tt> keyword indicates
that the programmer has opted to use explicit semi-colons to separate
declarations, and that the declaration-list will be terminated by an
explicit closing brace. One reason for wanting support for explicit
delimiters is that it makes automatic generation of Haskell source
code easier.


Haskell's layout rule has been criticised for its complexity. In particular, the definition states that if the parser encounters a parse error during processing of a layout section, then it should try inserting a close brace (the "parse error" rule). Implementing this rule in a traditional ''[[parsing]]'' and ''[[lexical analysis]]'' combination requires two-way cooperation between the parser and lexical analyser, whereas in most languages, these two phases can be considered independently.
Haskell's layout rule has been criticised for its complexity. In
particular, the definition states that if the parser encounters a
parse error during processing of a layout section, then it should try
inserting a close brace (the "parse error" rule). Implementing this
rule in a traditional [[parsing]]/[[Lexical_analysis|lexical-analysis]] combination requires
two-way cooperation between the parser and lexical analyser, whereas
in most languages these two phases can be considered independently.


=== Function calls ===
=== Function calls ===
Applying a function <code>f</code> to a value <code>x</code> is expressed as simply <code>f x</code>.

Applying a function <tt>f</tt> to a value <tt>x</tt> is expressed as simply <tt>f x</tt>.


Haskell distinguishes function calls from infix operators syntactically, but not semantically. Function names which are composed of punctuation characters can be used as operators, as can other function names if surrounded with backticks; and operators can be used in prefix notation if surrounded with parentheses.
Haskell distinguishes function calls from infix operators syntactically, but not semantically. Function names which are composed of punctuation characters can be used as operators, as can other function names if surrounded with backticks; and operators can be used in prefix notation if surrounded with parentheses.
Line 182: Line 311:
This example shows the ways that functions can be called:
This example shows the ways that functions can be called:


<source lang="haskell">
<syntaxhighlight lang="haskell">
add a b = a + b
add a b = a + b


ten1 = 5 + 5
ten1 = 5 + 5
ten2 = (+) 5 5
ten2 = (+) 5 5
ten3 = add 5 5
ten3 = add 5 5
ten4 = 5 `add` 5
ten4 = 5 `add` 5
</syntaxhighlight>
</source>


Functions which are defined as taking several parameters can always be partially applied. Binary operators can be partially applied using ''section'' notation:
Functions which are defined as taking several parameters can always be partially applied. Binary operators can be partially applied using ''section'' notation:


<source lang="haskell">
<syntaxhighlight lang="haskell">
ten5 = (+ 5) 5
ten5 = (+ 5) 5
ten6 = (5 +) 5
ten6 = (5 +) 5
addfive = (5 +)
addfive = (5 +)
ten7 = addfive 5
ten7 = addfive 5
</syntaxhighlight>
</source>


=== List comprehensions ===
=== List comprehensions ===
See [[List_comprehension#Overview]] for the Haskell example.
See [[List comprehension#Overview]] for the Haskell example.



=== Pattern matching ===
=== Pattern matching ===
[[Pattern matching]] is used to match on the different constructors of algebraic data types. Here are some functions, each using pattern matching on each of the types below:


<syntaxhighlight lang="haskell">
[[Pattern matching]] is used to match on the different constructors of algebraic data types. Here are some functions, each using pattern matching on each of the types above:

<source lang="haskell">
-- This type signature says that empty takes a list containing any type, and returns a Bool
-- This type signature says that empty takes a list containing any type, and returns a Bool
empty :: [a] -> Bool
empty :: [a] -> Bool
Line 232: Line 359:
getAge :: Person -> Int
getAge :: Person -> Int
getAge (Person _ _ age) = age
getAge (Person _ _ age) = age
</syntaxhighlight>
</source>


Using the above functions, along with the [[Map (higher-order function)|<code>map</code>]] function, we can apply them to each element of a list, to see their results:
Using the above functions, along with the [[Map (higher-order function)|<code>map</code>]] function, we can apply them to each element of a list, to see their results:


<source lang="haskell">
<syntaxhighlight lang="haskell">


map empty [[1,2,3],[],[2],[1..]]
map empty [[1,2,3],[],[2],[1..]]
Line 250: Line 377:
-- returns ["Sarah", "Alex", "Tom"], using the definition for tom above
-- returns ["Sarah", "Alex", "Tom"], using the definition for tom above


</syntaxhighlight>
</source>


* Abstract Types
* Abstract Types

* Lists
* Lists


=== Tuples ===
=== Tuples ===
[[Tuple (computer science)|Tuples]] in haskell can be used to hold a fixed number of elements. They are used to group pieces of data of differing types:


<syntaxhighlight lang="haskell">
Tuples in haskell can be used to hold a fixed number of elements. They are used to group pieces of data of differing types:
account :: (String, Integer, Double) -- The type of a three-tuple, representing

-- a name, balance, and interest rate
<source lang="haskell">
account :: (String, Integer, Double) -- The type of a three-tuple, representing a name, balance, interest rate
account = ("John Smith",102894,5.25)
account = ("John Smith",102894,5.25)
</syntaxhighlight>
</source>


Tuples are commonly used in the zip* functions to place adjacent elements in separate lists together in tuples (zip4 to zip7 are provided in the Data.List module):
Tuples are commonly used in the zip* functions to place adjacent elements in separate lists together in tuples (zip4 to zip7 are provided in the Data.List module):


<source lang="haskell">
<syntaxhighlight lang="haskell">
-- The definition of the zip function. Other zip* functions are defined similarly
-- The definition of the zip function. Other zip* functions are defined similarly
zip :: [x] -> [y] -> [(x,y)]
zip :: [x] -> [y] -> [(x,y)]
Line 281: Line 407:
-- and has type [(Integer,Char,Bool)]
-- and has type [(Integer,Char,Bool)]


</syntaxhighlight>
</source>


In the GHC compiler, tuples are defined with sizes from 2 elements up to 62 elements.
In the GHC compiler, tuples are defined with sizes from 2 elements up to 62 elements.


* Records
* [[Record (computer science)|Records]]


== Namespaces ==
== Namespaces ==
In the [[#More_complex_examples]] section above, <tt>calc</tt> is used in two senses, showing that there is a Haskell type class namespace and also a namespace for values:
In the {{slink||More complex examples}} section above, <code>calc</code> is used in two senses, showing that there is a Haskell type class namespace and also a namespace for values:
#a Haskell [[type class]] for <tt>calc</tt>. The [[Domain of a function|domain]] and [[Range (mathematics)|range]] can be explicitly denoted in a Haskell type class.
#a Haskell [[type class]] for <code>calc</code>. The [[Domain of a function|domain]] and [[Range of a function|range]] can be explicitly denoted in a Haskell type class.
#a Haskell value, formula, or expression for <tt>calc</tt>.
#a Haskell value, formula, or expression for <code>calc</code>.


== Typeclasses and polymorphism ==
== Typeclasses and polymorphism ==

=== Algebraic data types ===
=== Algebraic data types ===
{{Expand section|date=December 2009}}
{{Expand section|date=December 2009}}
Line 299: Line 424:
[[Algebraic data types]] are used extensively in Haskell. Some examples of these are the built in list, <code>Maybe</code> and <code>Either</code> types:
[[Algebraic data types]] are used extensively in Haskell. Some examples of these are the built in list, <code>Maybe</code> and <code>Either</code> types:


<source lang="haskell">
<syntaxhighlight lang="haskell">
-- A list of a's ([a]) is either an a consed (:) onto another list of a's, or an empty list ([])
-- A list of a's ([a]) is either an a consed (:) onto another list of a's, or an empty list ([])
data [a] = a : [a] | []
data [a] = a : [a] | []
Line 306: Line 431:
-- Something of type Either atype btype is either a Left atype, or a Right btype
-- Something of type Either atype btype is either a Left atype, or a Right btype
data Either a b = Left a | Right b
data Either a b = Left a | Right b
</syntaxhighlight>
</source>


Users of the language can also define their own [[abstract data type]]s. An example of an ADT used to represent a person's name, sex and age might look like:
Users of the language can also define their own [[abstract data type]]s. An example of an ADT used to represent a person's name, sex and age might look like:


<source lang="haskell">
<syntaxhighlight lang="haskell">
data Sex = Male | Female
data Sex = Male | Female
data Person = Person String Sex Int -- Notice that Person is both a constructor and a type
data Person = Person String Sex Int -- Notice that Person is both a constructor and a type
Line 317: Line 442:
tom :: Person
tom :: Person
tom = Person "Tom" Male 27
tom = Person "Tom" Male 27
</syntaxhighlight>
</source>



=== Type system ===
=== Type system ===

{{Expand section|date=December 2009}}
{{Expand section|date=December 2009}}

* [[Type class]]es
* [[Type class]]es
* Type defaulting
* Type defaulting
* Overloaded Literals
* Overloaded literals
* Higher Kinded Polymorphism
* Higher kinded polymorphism
* Multi-Parameter Type Classes
* Multi-parameter type classes
* Functional Dependencies
* Functional dependencies


== Monads and input/output ==
== Monads and input/output ==
{{Expand section|date=December 2009}}
{{Expand section|date=December 2009}}
* Overview of the [[Monad (functional programming)|monad]] framework:

* [[Monad (functional programming)|Overview of the monad framework]]
* Applications
* Applications

** Monadic IO
** Monadic IO
** Do-notation
** Do-notation
Line 343: Line 463:


=== ST monad ===
=== ST monad ===
The ST monad allows writing [[imperative programming]] algorithms in Haskell, using mutable variables (STRefs) and mutable arrays (STArrays and STUArrays). The advantage of the ST monad is that it allows writing code that has internal side effects, such as destructively updating mutable variables and arrays, while containing these effects inside the monad. The result of this is that functions written using the ST monad appear pure to the rest of the program. This allows using imperative code where it may be impractical to write functional code, while still keeping all the safety that pure code provides.

The ST monad allows programmers to write imperative algorithms in Haskell, using mutable variables (STRef's) and mutable arrays (STArrays and STUArrays). The advantage of the ST monad is that it allows programmers to write code that has internal side effects, such as destructively updating mutable variables and arrays, while containing these effects inside the monad. The result of this is that functions written using the ST monad appear completely pure to the rest of the program. This allows programmers to produce imperative code where it may be impractical to write functional code, while still keeping all the safety that pure code provides.


Here is an example program (taken from the Haskell wiki page on the [http://haskell.org/haskellwiki/Monad/ST ST monad]) that takes a list of numbers, and sums them, using a mutable variable:
Here is an example program (taken from the Haskell wiki page on the [http://haskell.org/haskellwiki/Monad/ST ST monad]) that takes a list of numbers, and sums them, using a mutable variable:


<source lang="haskell">
<syntaxhighlight lang="haskell">
import Control.Monad.ST
import Control.Monad.ST
import Data.STRef
import Data.STRef
Line 361: Line 480:


readSTRef summed -- read the value of n, which will be returned by the runST above.
readSTRef summed -- read the value of n, which will be returned by the runST above.
</syntaxhighlight>
</source>


=== STM monad ===
=== STM monad ===
{{main|Concurrent Haskell}}
{{main|Concurrent Haskell}}
The STM monad is an implementation of [[Software Transactional Memory]] in Haskell. It is implemented in the GHC compiler, and allows for mutable variables to be modified in [[Database_transaction|transactions]].
The STM monad is an implementation of [[Software Transactional Memory]] in Haskell. It is implemented in the GHC compiler, and allows for mutable variables to be modified in [[Database transaction|transactions]].



=== Arrows ===
=== Arrows ===
Line 372: Line 490:
* Arrows
* Arrows


As Haskell is a pure functional language, functions cannot have side effects. Being non-strict, it also does not have a well-defined evaluation order. This is a challenge for real programs, which among other things need to interact with an environment. Haskell solves this with ''[[monad (functional programming)|monadic types]]'' that leverage the type system to ensure the proper sequencing of imperative constructs. The typical example is I/O, but monads are useful for many other purposes, including mutable state, concurrency and transactional memory, exception handling, and error propagation.
As Haskell is a pure functional language, functions cannot have side effects. Being non-strict, it also does not have a well-defined evaluation order. This is a challenge for real programs, which among other things need to interact with an environment. Haskell solves this with ''[[Monad (functional programming)|monadic types]]'' that leverage the type system to ensure the proper sequencing of imperative constructs. The typical example is [[input/output]] (I/O), but monads are useful for many other purposes, including mutable state, concurrency and transactional memory, exception handling, and error propagation.


Haskell provides a special syntax for monadic expressions, so that side-effecting programs can be written in a style similar to current imperative programming languages; no knowledge of the [[Monad (category theory)|mathematics behind monadic I/O]] is required for this. The following program reads a name from the command line and outputs a greeting message:
Haskell provides a special syntax for monadic expressions, so that side-effecting programs can be written in a style similar to current imperative programming languages; no knowledge of the [[Monad (category theory)|mathematics behind monadic I/O]] is required for this. The following program reads a name from the command line and outputs a greeting message:


<source lang="haskell">
<syntaxhighlight lang="haskell">
main = do putStrLn "What's your name?"
main = do putStrLn "What's your name?"
name <- getLine
name <- getLine
putStr ("Hello, " ++ name ++ "!\n")
putStr ("Hello, " ++ name ++ "!\n")
</syntaxhighlight>
</source>


The do-notation eases working with monads. This do-expression is equivalent to, but (arguably) easier to write and understand than, the [[desugared|de-sugared]] version employing the monadic operators directly:
The do-notation eases working with monads. This do-expression is equivalent to, but (arguably) easier to write and understand than, the [[desugared|de-sugared]] version employing the monadic operators directly:


<source lang="haskell">
<syntaxhighlight lang="haskell">
main = putStrLn "What's your name?" >> getLine >>= \ name -> putStr ("Hello, " ++ name ++ "!\n")
main = putStrLn "What's your name?" >> getLine >>= \ name -> putStr ("Hello, " ++ name ++ "!\n")
</syntaxhighlight>
</source>


: ''See also [[wikibooks:Transwiki:List of hello world programs#Haskell]] for another example that prints text.''
: ''See also [[wikibooks:Transwiki:List of hello world programs#Haskell]] for another example that prints text.''


== Concurrency ==
== Concurrency ==
The Haskell language definition includes neither [[Concurrency (computer science)|concurrency]] nor [[Parallel computing|parallelism]], although GHC supports both.

The Haskell language definition itself does not include either
[[Concurrency (computer science)|concurrency]] or [[Parallel computing|parallelism]], although GHC supports both.

{{main|Concurrent Haskell}}
{{main|Concurrent Haskell}}
[[Concurrent Haskell]] is an extension to Haskell that supports [[Thread (computing)|threads]] and [[Synchronization (computer science)|synchronization]].<ref>Simon Peyton Jones, Andrew Gordon, and Sigbjorn Finne. [http://www.haskell.org/ghc/docs/papers/concurrent-haskell.ps.gz Concurrent Haskell]. ''ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (PoPL).'' 1996. (Some sections are out of date with respect to the current implementation.)</ref> GHC's implementation of Concurrent Haskell is based on multiplexing lightweight Haskell threads onto a few heavyweight [[operating system]] (OS) threads,<ref name="marlow2009">[http://www.haskell.org/~simonmar/papers/multicore-ghc.pdf Runtime Support for Multicore Haskell] {{Webarchive|url=https://web.archive.org/web/20100705223412/http://www.haskell.org/~simonmar/papers/multicore-ghc.pdf |date=2010-07-05}} (Simon Marlow, Simon Peyton Jones, Satnam Singh) ICFP '09: Proceedings of the 14th ACM SIGPLAN international conference on Functional programming, Edinburgh, Scotland, August 2009</ref> so that Concurrent Haskell programs run in parallel via [[symmetric multiprocessing]]. The runtime can support millions of simultaneous threads.<ref name="dons-multicore">{{cite web |url=http://donsbot.wordpress.com/2009/09/05/defun-2009-multicore-programming-in-haskell-now/ |title=DEFUN 2009: Multicore Programming in Haskell Now! |date=5 September 2009}}</ref>


The GHC implementation employs a dynamic pool of OS threads, allowing a Haskell thread to make a blocking system call without blocking other running Haskell threads.<ref name="marlow2004">[http://www.haskell.org/~simonmar/papers/conc-ffi.pdf Extending the Haskell Foreign Function Interface with Concurrency] {{Webarchive|url=https://web.archive.org/web/20100703070838/http://www.haskell.org/~simonmar/papers/conc-ffi.pdf |date=2010-07-03}} (Simon Marlow, Simon Peyton Jones, Wolfgang Thaller) Proceedings of the ACM SIGPLAN workshop on Haskell, pages 57--68, Snowbird, Utah, USA, September 2004</ref> Hence the lightweight Haskell threads have the characteristics of heavyweight OS threads, and a programmer can be unaware of the implementation details.
[[Concurrent Haskell]] is an extension to Haskell that provides
support for threads and synchronization.<ref>Simon Peyton Jones, Andrew Gordon, and Sigbjorn Finne. [http://www.haskell.org/ghc/docs/papers/concurrent-haskell.ps.gz Concurrent Haskell]. ''ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (PoPL).'' 1996. (Some sections are out of date with respect to the current implementation.)</ref> GHC's
implementation of Concurrent Haskell is based on multiplexing
lightweight Haskell threads onto a few heavyweight OS
threads,<ref name="marlow2009">[http://www.haskell.org/~simonmar/papers/multicore-ghc.pdf Runtime Support for Multicore Haskell] (Simon Marlow, Simon Peyton Jones, Satnam Singh) ICFP '09: Proceeding of the 14th ACM SIGPLAN international conference on Functional programming, Edinburgh, Scotland, August 2009</ref> so that Concurrent Haskell programs run in
parallel on a [[Symmetric multiprocessing|multiprocessor]]. The runtime can support millions of simultaneous threads.<ref name="dons-multicore">http://donsbot.wordpress.com/2009/09/05/defun-2009-multicore-programming-in-haskell-now/</ref>


Recently,{{when|date=June 2018}} Concurrent Haskell has been extended with support for ''[[software transactional memory]]'' (STM), which is a concurrency abstraction in which compound operations on shared data are performed atomically, as transactions.<ref name="stm">{{cite conference |last1=Harris |first1=Tim |last2=Marlow |first2=Simon |author2-link=Simon Marlow |last3=Peyton Jones |first3=Simon |author3-link=Simon Peyton Jones |last4=Herlihy |first4=Maurice |year=2005 |title=Composable memory transactions |book-title=Proceedings of the tenth ACM SIGPLAN symposium on Principles and practice of parallel programming |citeseerx=10.1.1.67.3686}}</ref> GHC's STM implementation is the only STM implementation to date to provide a static compile-time guarantee preventing non-transactional operations from being performed within a transaction. The Haskell STM library also provides two operations not found in other STMs: <code>retry</code> and <code>orElse</code>, which together allow blocking operations to be defined in a [[Software transactional memory#Composable operations|modular and composable fashion]].
The GHC implementation employs a dynamic pool of OS threads, allowing
a Haskell thread to make a blocking system call without
blocking other running Haskell threads.<ref name="marlow2004">[http://www.haskell.org/~simonmar/papers/conc-ffi.pdf Extending the Haskell Foreign Function Interface with Concurrency] (Simon Marlow, Simon Peyton Jones, Wolfgang Thaller) Proceedings of the ACM SIGPLAN workshop on Haskell, pages 57--68, Snowbird, Utah, USA, September 2004</ref> Hence the
lightweight Haskell threads have the characteristics of heavyweight OS
threads, and the programmer is unaware of the implementation details.

Recently, Concurrent Haskell has been extended with support for [[Software transactional memory|Software Transactional Memory]] (STM), which is a concurrency abstraction in which compound operations on shared data are performed atomically, as transactions.<ref name="stm">Tim Harris, Simon Marlow, Simon Peyton Jones, Maurice Herlihy "[http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.67.3686&rep=rep1&type=pdf Composable memory transactions]" ''Proceedings of the tenth ACM SIGPLAN symposium on Principles and practice of parallel programming'', 2005</ref> GHC's STM implementation is the only STM implementation to date to provide a static compile-time guarantee preventing non-transactional operations from being performed within a transaction. The Haskell STM library also provides two operations not found in other STMs: <tt>retry</tt> and <tt>orElse</tt>, which together allow blocking operations to be defined in a [[Software_transactional_memory#Composable_operations|modular and composable fashion]].


== References ==
== References ==
{{Reflist}}
<references />

{{Haskell programming}}


[[Category:Haskell_programming_language_family]]
[[Category:Haskell programming language family]]
[[Category:Articles_with_example_Haskell_code]]
[[Category:Articles with example Haskell code]]

Latest revision as of 04:24, 27 February 2024

This article describes the features in the programming language Haskell.

Examples

[edit]

Factorial

[edit]

A simple example that is often used to demonstrate the syntax of functional languages is the factorial function for non-negative integers, shown in Haskell:

factorial :: Integer -> Integer
factorial 0 = 1
factorial n = n * factorial (n-1)

Or in one line:

factorial n = if n > 1 then n * factorial (n-1) else 1

This describes the factorial as a recursive function, with one terminating base case. It is similar to the descriptions of factorials found in mathematics textbooks. Much of Haskell code is similar to standard mathematical notation in facility and syntax.

The first line of the factorial function describes the type of this function; while it is optional, it is considered to be good style[1] to include it. It can be read as the function factorial (factorial) has type (::) from integer to integer (Integer -> Integer). That is, it takes an integer as an argument, and returns another integer. The type of a definition is inferred automatically if no type annotation is given.

The second line relies on pattern matching, an important feature of Haskell. Note that parameters of a function are not in parentheses but separated by spaces. When the function's argument is 0 (zero) it will return the integer 1 (one). For all other cases the third line is tried. This is the recursion, and executes the function again until the base case is reached.

Using the product function from the Prelude, a number of small functions analogous to C's standard library, and using the Haskell syntax for arithmetic sequences, the factorial function can be expressed in Haskell as follows:

factorial n = product [1..n]

Here [1..n] denotes the arithmetic sequence 1, 2, …, n in list form. Using the Prelude function enumFromTo, the expression [1..n] can be written as enumFromTo 1 n, allowing the factorial function to be expressed as

factorial n = product (enumFromTo 1 n)

which, using the function composition operator (expressed as a dot in Haskell) to compose the product function with the curried enumeration function can be rewritten in point-free style:[2]

factorial = product . enumFromTo 1

In the Hugs interpreter, one often needs to define the function and use it on the same line separated by a where or let..in. For example, to test the above examples and see the output 120:

let { factorial n | n > 0 = n * factorial (n-1); factorial _ = 1 } in factorial 5

or

factorial 5 where factorial = product . enumFromTo 1

The GHCi interpreter doesn't have this restriction and function definitions can be entered on one line (with the let syntax without the in part), and referenced later.

More complex examples

[edit]

Calculator

[edit]

In the Haskell source immediately below, :: can be read as "has type"; a -> b can be read as "is a function from a to b". (Thus the Haskell calc :: String -> [Float] can be read as "calc has type of a function from Strings to lists of Floats".) In the second line calc = ... the equals sign can be read as "can be"; thus multiple lines with calc = ... can be read as multiple possible values for calc, depending on the circumstance detailed in each line.

A simple Reverse Polish notation calculator expressed with the higher-order function foldl whose argument f is defined in a where clause using pattern matching and the type class Read:

calc :: String -> [Float]
calc = foldl f [] . words
  where 
    f (x:y:zs) "+" = (y + x):zs
    f (x:y:zs) "-" = (y - x):zs
    f (x:y:zs) "*" = (y * x):zs
    f (x:y:zs) "/" = (y / x):zs
    f (x:y:zs) "FLIP" =  y:x:zs
    f zs w = read w : zs

The empty list is the initial state, and f interprets one word at a time, either as a function name, taking two numbers from the head of the list and pushing the result back in, or parsing the word as a floating-point number and prepending it to the list.

Fibonacci sequence

[edit]

The following definition produces the list of Fibonacci numbers in linear time:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

The infinite list is produced by corecursion — the latter values of the list are computed on demand starting from the initial two items 0 and 1. This kind of a definition relies on lazy evaluation, an important feature of Haskell programming. For an example of how the evaluation evolves, the following illustrates the values of fibs and tail fibs after the computation of six items and shows how zipWith (+) has produced four items and proceeds to produce the next item:

fibs         = 0 : 1 : 1 : 2 : 3 : 5 : ...
               +   +   +   +   +   +
tail fibs    = 1 : 1 : 2 : 3 : 5 : ...
               =   =   =   =   =   =
zipWith ...  = 1 : 2 : 3 : 5 : 8 : ...
fibs = 0 : 1 : 1 : 2 : 3 : 5 : 8 : ...

The same function, written using Glasgow Haskell Compiler's parallel list comprehension syntax (GHC extensions must be enabled using a special command-line flag, here -XParallelListComp, or by starting the source file with {-# LANGUAGE ParallelListComp #-}):

fibs = 0 : 1 : [ a+b | a <- fibs | b <- tail fibs ]

or with regular list comprehensions:

fibs = 0 : 1 : [ a+b | (a,b) <- zip fibs (tail fibs) ]

or directly self-referencing:

fibs = 0 : 1 : next fibs where next (a : t@(b:_)) = (a+b) : next t

With stateful generating function:

fibs = next (0,1) where next (a,b) = a : next (b, a+b)

or with unfoldr:

fibs = unfoldr (\(a,b) -> Just (a, (b, a+b))) (0, 1)

or scanl:

fibs = 0 : scanl (+) 1 fibs

Using data recursion with Haskell's predefined fixpoint combinator:

fibs = fix (\xs -> 0 : 1 : zipWith (+) xs (tail xs))   -- zipWith version
     = fix ((0:) . (1:) . (zipWith (+) <*> tail))      -- same as above, pointfree
     = fix ((0:) . scanl (+) 1)                        -- scanl version

Factorial

[edit]

The factorial we saw previously can be written as a sequence of functions:

factorial n = foldr ((.) . (*)) id [1..n] $ 1
-- factorial 5 == ((1*) .) ( ((2*) .) ( ((3*) .) ( ((4*) .) ( ((5*) .) id )))) 1
--             == (1*) . (2*) . (3*) . (4*) . (5*) . id $ 1
--             ==  1*  (  2*  (  3*  (  4*  (  5*  ( id   1 )))))

factorial n = foldr ((.) . (*)) (const 1) [1..n] $ ()
-- factorial 5 == ((1*) .) ( ((2*) .) ( ((3*) .) ( ((4*) .) ( ((5*) .) (const 1) )))) ()
--             == (1*) . (2*) . (3*) . (4*) . (5*) . const 1 $ ()
--             ==  1*  (  2*  (  3*  (  4*  (  5*  ( const 1   () )))))

factorial n = foldr (($) . (*)) 1 [1..n] = foldr ($) 1 $ map (*) [1..n]
-- factorial 5 == ((1*) $) ( ((2*) $) ( ((3*) $) ( ((4*) $) ( ((5*) $) 1 ))))
--             == (1*) $ (2*) $ (3*) $ (4*) $ (5*) $ 1
--             ==  1*  (  2*  (  3*  (  4*  (  5*    1 ))))

More examples

[edit]

Hamming numbers

[edit]

A remarkably concise function that returns the list of Hamming numbers in order:

hamming = 1 : map (2*) hamming `union` map (3*) hamming 
                                 `union` map (5*) hamming

Like the various fibs solutions displayed above, this uses corecursion to produce a list of numbers on demand, starting from the base case of 1 and building new items based on the preceding part of the list.

Here the function union is used as an operator by enclosing it in back-quotes. Its case clauses define how it merges two ascending lists into one ascending list without duplicate items, representing sets as ordered lists. Its companion function minus implements set difference:

union (x:xs) (y:ys) = case compare x y of
    LT -> x : union  xs (y:ys)  
    EQ -> x : union  xs    ys  
    GT -> y : union (x:xs) ys  
union  xs  []  = xs  
union  []  ys  = ys
minus (x:xs) (y:ys) = case compare x y of 
    LT -> x : minus  xs (y:ys)
    EQ ->     minus  xs    ys 
    GT ->     minus (x:xs) ys
minus  xs  _  = xs
--

It is possible to generate only the unique multiples, for more efficient operation. Since there are no duplicates, there's no need to remove them:

smooth235 = 1 : foldr (\p s -> fix $ mergeBy (<) s . map (p*) . (1:)) [] [2,3,5]
  where
    fix f = x  where x = f x         -- fixpoint combinator, with sharing

This uses the more efficient function merge which doesn't concern itself with the duplicates (also used in the following next function, mergesort ):

mergeBy less xs ys = merge xs ys  where
  merge  xs     []  = xs 
  merge  []     ys  = ys
  merge (x:xs) (y:ys) | less y x  = y : merge (x:xs) ys
                      | otherwise = x : merge xs (y:ys)

Each vertical bar ( | ) starts a guard clause with a guard expression before the = sign and the corresponding definition after it, that is evaluated if the guard is true.

Mergesort

[edit]

Here is a bottom-up merge sort, defined using the higher-order function until:

mergesortBy less [] = []
mergesortBy less xs = head $
      until (null . tail) (pairwise $ mergeBy less) [[x] | x <- xs]

pairwise f (a:b:t) = f a b : pairwise f t
pairwise f      t  = t

Prime numbers

[edit]

The mathematical definition of primes can be translated pretty much word for word into Haskell:

-- "Integers above 1 that cannot be divided by a smaller integer above 1"
-- primes = { n ∈ [2..] | ~ ∃ d ∈ [2..n-1] ⇒ rem n d = 0  }
--        = { n ∈ [2..] |   ∀ d ∈ [2..n-1] ⇒ rem n d ≠ 0  }

primes = [ n | n <- [2..], all (\d -> rem n d /= 0) [2..(n-1)] ]

This finds primes by trial division. Note that it is not optimized for efficiency and has very poor performance. Slightly faster (but still very slow)[3] is this code by David Turner:

primes = sieve [2..]  where 
         sieve (p:xs) = p : sieve [x | x <- xs, rem x p /= 0]

Much faster is the optimal trial division algorithm

primes = 2 : [ n | n <- [3..], all ((> 0) . rem n) $ 
                     takeWhile ((<= n) . (^2)) primes]

or an unbounded sieve of Eratosthenes with postponed sieving in stages,[4]

primes = 2 : sieve primes [3..]  where
             sieve (p:ps) (span (< p*p) -> (h, t)) = 
                   h ++ sieve ps (minus t [p*p, p*p+p..])

or the combined sieve implementation by Richard Bird,[5]

-- "Integers above 1 without any composite numbers which
--  are found by enumeration of each prime's multiples"
primes = 2 : minus [3..]
               (foldr (\(m:ms) r -> m : union ms r) [] 
                      [[p*p, p*p+p ..] | p <- primes])

or an even faster tree-like folding variant[6] with nearly optimal (for a list-based code) time complexity and very low space complexity achieved through telescoping multistage recursive production of primes:

primes = 2 : _Y ((3 :) . minus [5,7..] . _U 
                       . map (\p -> [p*p, p*p+2*p..]))
  where
    -- non-sharing Y combinator:
    _Y g = g (_Y g)     -- (g (g (g (g (...)))))
    -- big union   ~= nub.sort.concat
    _U ((x:xs):t) = x : (union xs . _U . pairwise union) t

Working on arrays by segments between consecutive squares of primes, it's

import Data.Array
import Data.List (tails, inits)

primes = 2 : [ n |
   (r:q:_, px) <- zip (tails (2 : [p*p | p <- primes]))
                      (inits primes),
   (n, True)   <- assocs ( accumArray (\_ _ -> False) True
                     (r+1,q-1)
                     [ (m,()) | p <- px
                              , s <- [ div (r+p) p * p]
                              , m <- [s,s+p..q-1] ] ) ]

The shortest possible code is probably  nubBy (((>1) .) . gcd) [2..].  It is quite slow.

Syntax

[edit]

Layout

[edit]

Haskell allows indentation to be used to indicate the beginning of a new declaration. For example, in a where clause:

product xs = prod xs 1
  where
    prod []     a = a
    prod (x:xs) a = prod xs (a*x)

The two equations for the nested function prod are aligned vertically, which allows the semi-colon separator to be omitted. In Haskell, indentation can be used in several syntactic constructs, including do, let, case, class, and instance.

The use of indentation to indicate program structure originates in Peter J. Landin's ISWIM language, where it was called the off-side rule. This was later adopted by Miranda, and Haskell adopted a similar (but rather more complex) version of Miranda's off-side rule, which is called "layout". Other languages to adopt whitespace character-sensitive syntax include Python and F#.

The use of layout in Haskell is optional. For example, the function product above can also be written:

product xs = prod xs 1
  where { prod [] a = a; prod (x:xs) a = prod xs (a*x) }

The explicit open brace after the where keyword indicates that separate declarations will use explicit semi-colons, and the declaration-list will be terminated by an explicit closing brace. One reason for wanting support for explicit delimiters is that it makes automatic generation of Haskell source code easier.

Haskell's layout rule has been criticised for its complexity. In particular, the definition states that if the parser encounters a parse error during processing of a layout section, then it should try inserting a close brace (the "parse error" rule). Implementing this rule in a traditional parsing and lexical analysis combination requires two-way cooperation between the parser and lexical analyser, whereas in most languages, these two phases can be considered independently.

Function calls

[edit]

Applying a function f to a value x is expressed as simply f x.

Haskell distinguishes function calls from infix operators syntactically, but not semantically. Function names which are composed of punctuation characters can be used as operators, as can other function names if surrounded with backticks; and operators can be used in prefix notation if surrounded with parentheses.

This example shows the ways that functions can be called:

add a b = a + b

ten1 = 5 + 5
ten2 = (+) 5 5
ten3 = add 5 5
ten4 = 5 `add` 5

Functions which are defined as taking several parameters can always be partially applied. Binary operators can be partially applied using section notation:

ten5 = (+ 5) 5
ten6 = (5 +) 5
  
addfive = (5 +)
ten7 = addfive 5

List comprehensions

[edit]

See List comprehension#Overview for the Haskell example.

Pattern matching

[edit]

Pattern matching is used to match on the different constructors of algebraic data types. Here are some functions, each using pattern matching on each of the types below:

-- This type signature says that empty takes a list containing any type, and returns a Bool
empty :: [a] -> Bool
empty (x:xs) = False
empty [] = True

-- Will return a value from a Maybe a, given a default value in case a Nothing is encountered
fromMaybe :: a -> Maybe a -> a
fromMaybe x (Just y) = y
fromMaybe x Nothing  = x

isRight :: Either a b -> Bool
isRight (Right _) = True
isRight (Left _)  = False

getName :: Person -> String
getName (Person name _ _) = name

getSex :: Person -> Sex
getSex (Person _ sex _) = sex

getAge :: Person -> Int
getAge (Person _ _ age) = age

Using the above functions, along with the map function, we can apply them to each element of a list, to see their results:

map empty [[1,2,3],[],[2],[1..]]
-- returns [False,True,False,False]

map (fromMaybe 0) [Just 2,Nothing,Just 109238, Nothing]
-- returns [2,0,109238,0]

map isRight [Left "hello", Right 6, Right 23, Left "world"]
-- returns [False, True, True, False]

map getName [Person "Sarah" Female 20, Person "Alex" Male 20, tom]
-- returns ["Sarah", "Alex", "Tom"], using the definition for tom above
  • Abstract Types
  • Lists

Tuples

[edit]

Tuples in haskell can be used to hold a fixed number of elements. They are used to group pieces of data of differing types:

account :: (String, Integer, Double) -- The type of a three-tuple, representing 
                                     --   a name, balance, and interest rate
account = ("John Smith",102894,5.25)

Tuples are commonly used in the zip* functions to place adjacent elements in separate lists together in tuples (zip4 to zip7 are provided in the Data.List module):

-- The definition of the zip function. Other zip* functions are defined similarly
zip :: [x] -> [y] -> [(x,y)]
zip (x:xs) (y:ys) = (x,y) : zip xs ys
zip _      _      = []

zip [1..5] "hello"
-- returns [(1,'h'),(2,'e'),(3,'l'),(4,'l'),(5,'o')]
-- and has type [(Integer, Char)]

zip3 [1..5] "hello" [False, True, False, False, True]
-- returns [(1,'h',False),(2,'e',True),(3,'l',False),(4,'l',False),(5,'o',True)]
-- and has type [(Integer,Char,Bool)]

In the GHC compiler, tuples are defined with sizes from 2 elements up to 62 elements.

Namespaces

[edit]

In the § More complex examples section above, calc is used in two senses, showing that there is a Haskell type class namespace and also a namespace for values:

  1. a Haskell type class for calc. The domain and range can be explicitly denoted in a Haskell type class.
  2. a Haskell value, formula, or expression for calc.

Typeclasses and polymorphism

[edit]

Algebraic data types

[edit]

Algebraic data types are used extensively in Haskell. Some examples of these are the built in list, Maybe and Either types:

-- A list of a's ([a]) is either an a consed (:) onto another list of a's, or an empty list ([])
data [a] = a : [a] | []
-- Something of type Maybe a is either Just something, or Nothing
data Maybe a = Just a | Nothing
-- Something of type Either atype btype is either a Left atype, or a Right btype
data Either a b = Left a | Right b

Users of the language can also define their own abstract data types. An example of an ADT used to represent a person's name, sex and age might look like:

data Sex = Male | Female
data Person = Person String Sex Int -- Notice that Person is both a constructor and a type

-- An example of creating something of type Person
tom :: Person
tom = Person "Tom" Male 27

Type system

[edit]
  • Type classes
  • Type defaulting
  • Overloaded literals
  • Higher kinded polymorphism
  • Multi-parameter type classes
  • Functional dependencies

Monads and input/output

[edit]
  • Overview of the monad framework:
  • Applications
    • Monadic IO
    • Do-notation
    • References
    • Exceptions

ST monad

[edit]

The ST monad allows writing imperative programming algorithms in Haskell, using mutable variables (STRefs) and mutable arrays (STArrays and STUArrays). The advantage of the ST monad is that it allows writing code that has internal side effects, such as destructively updating mutable variables and arrays, while containing these effects inside the monad. The result of this is that functions written using the ST monad appear pure to the rest of the program. This allows using imperative code where it may be impractical to write functional code, while still keeping all the safety that pure code provides.

Here is an example program (taken from the Haskell wiki page on the ST monad) that takes a list of numbers, and sums them, using a mutable variable:

import Control.Monad.ST
import Data.STRef
import Control.Monad

sumST :: Num a => [a] -> a
sumST xs = runST $ do            -- runST takes stateful ST code and makes it pure.
    summed <- newSTRef 0         -- Create an STRef (a mutable variable)

    forM_ xs $ \x -> do          -- For each element of the argument list xs ..
        modifySTRef summed (+x)  -- add it to what we have in n.

    readSTRef summed             -- read the value of n, which will be returned by the runST above.

STM monad

[edit]

The STM monad is an implementation of Software Transactional Memory in Haskell. It is implemented in the GHC compiler, and allows for mutable variables to be modified in transactions.

Arrows

[edit]
  • Applicative Functors
  • Arrows

As Haskell is a pure functional language, functions cannot have side effects. Being non-strict, it also does not have a well-defined evaluation order. This is a challenge for real programs, which among other things need to interact with an environment. Haskell solves this with monadic types that leverage the type system to ensure the proper sequencing of imperative constructs. The typical example is input/output (I/O), but monads are useful for many other purposes, including mutable state, concurrency and transactional memory, exception handling, and error propagation.

Haskell provides a special syntax for monadic expressions, so that side-effecting programs can be written in a style similar to current imperative programming languages; no knowledge of the mathematics behind monadic I/O is required for this. The following program reads a name from the command line and outputs a greeting message:

main = do putStrLn "What's your name?"
          name <- getLine
          putStr ("Hello, " ++ name ++ "!\n")

The do-notation eases working with monads. This do-expression is equivalent to, but (arguably) easier to write and understand than, the de-sugared version employing the monadic operators directly:

main = putStrLn "What's your name?" >> getLine >>= \ name -> putStr ("Hello, " ++ name ++ "!\n")
See also wikibooks:Transwiki:List of hello world programs#Haskell for another example that prints text.

Concurrency

[edit]

The Haskell language definition includes neither concurrency nor parallelism, although GHC supports both.

Concurrent Haskell is an extension to Haskell that supports threads and synchronization.[7] GHC's implementation of Concurrent Haskell is based on multiplexing lightweight Haskell threads onto a few heavyweight operating system (OS) threads,[8] so that Concurrent Haskell programs run in parallel via symmetric multiprocessing. The runtime can support millions of simultaneous threads.[9]

The GHC implementation employs a dynamic pool of OS threads, allowing a Haskell thread to make a blocking system call without blocking other running Haskell threads.[10] Hence the lightweight Haskell threads have the characteristics of heavyweight OS threads, and a programmer can be unaware of the implementation details.

Recently,[when?] Concurrent Haskell has been extended with support for software transactional memory (STM), which is a concurrency abstraction in which compound operations on shared data are performed atomically, as transactions.[11] GHC's STM implementation is the only STM implementation to date to provide a static compile-time guarantee preventing non-transactional operations from being performed within a transaction. The Haskell STM library also provides two operations not found in other STMs: retry and orElse, which together allow blocking operations to be defined in a modular and composable fashion.

References

[edit]
  1. ^ HaskellWiki: Type signatures as good style
  2. ^ HaskellWiki: Pointfree
  3. ^ "Prime numbers - HaskellWiki". www.haskell.org.
  4. ^ "Prime numbers - HaskellWiki". www.haskell.org.
  5. ^ O'Neill, Melissa E., "The Genuine Sieve of Eratosthenes", Journal of Functional Programming, Published online by Cambridge University Press 9 October 2008 doi:10.1017/S0956796808007004, pp. 10, 11.
  6. ^ "Prime numbers - HaskellWiki". www.haskell.org.
  7. ^ Simon Peyton Jones, Andrew Gordon, and Sigbjorn Finne. Concurrent Haskell. ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (PoPL). 1996. (Some sections are out of date with respect to the current implementation.)
  8. ^ Runtime Support for Multicore Haskell Archived 2010-07-05 at the Wayback Machine (Simon Marlow, Simon Peyton Jones, Satnam Singh) ICFP '09: Proceedings of the 14th ACM SIGPLAN international conference on Functional programming, Edinburgh, Scotland, August 2009
  9. ^ "DEFUN 2009: Multicore Programming in Haskell Now!". 5 September 2009.
  10. ^ Extending the Haskell Foreign Function Interface with Concurrency Archived 2010-07-03 at the Wayback Machine (Simon Marlow, Simon Peyton Jones, Wolfgang Thaller) Proceedings of the ACM SIGPLAN workshop on Haskell, pages 57--68, Snowbird, Utah, USA, September 2004
  11. ^ Harris, Tim; Marlow, Simon; Peyton Jones, Simon; Herlihy, Maurice (2005). "Composable memory transactions". Proceedings of the tenth ACM SIGPLAN symposium on Principles and practice of parallel programming. CiteSeerX 10.1.1.67.3686.