PROGRAMMING IN HASKELL
description
Transcript of PROGRAMMING IN HASKELL
![Page 1: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/1.jpg)
1
PROGRAMMING IN HASKELL
Based on lecture notes by Graham HuttonThe book “Learn You a Haskell for Great Good”
(and a few other sources)
Modules
![Page 2: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/2.jpg)
2
Type Declarations
In Haskell, a new name for an existing type can be defined using a type declaration.
type String = [Char]
String is a synonym for the type [Char].
![Page 3: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/3.jpg)
3
Type declarations can be used to make other types easier to read. For example, given
origin :: Posorigin = (0,0)
left :: Pos Posleft (x,y) = (x-1,y)
type Pos = (Int,Int)
we can define:
![Page 4: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/4.jpg)
4
Like function definitions, type declarations can also have parameters. For example, given
type Pair a = (a,a)
we can define:
mult :: Pair Int Intmult (m,n) = m*n
copy :: a Pair acopy x = (x,x)
![Page 5: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/5.jpg)
5
Type declarations can be nested:
type Pos = (Int,Int)
type Trans = Pos Pos
However, they cannot be recursive:
type Tree = (Int,[Tree])
![Page 6: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/6.jpg)
6
Data Declarations
A completely new type can be defined by specifying its values using a data declaration.
data Bool = False | True
Bool is a new type, with two new values False
and True.
![Page 7: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/7.jpg)
7
Note:
The two values False and True are called the constructors for the type Bool.
Type and constructor names must begin with an upper-case letter.
Data declarations are similar to context free grammars. The former specifies the values of a type, the latter the sentences of a language.
![Page 8: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/8.jpg)
8
answers :: [Answer]answers = [Yes,No,Unknown]
flip :: Answer Answerflip Yes = Noflip No = Yesflip Unknown = Unknown
data Answer = Yes | No | Unknown
we can define:
Values of new types can be used in the same ways as those of built in types. For example, given
![Page 9: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/9.jpg)
9
The constructors in a data declaration can also have parameters. For example, given
data Shape = Circle Float | Rect Float Float
square :: Float Shapesquare n = Rect n n
area :: Shape Floatarea (Circle r) = pi * r^2area (Rect x y) = x * y
we can define:
![Page 10: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/10.jpg)
10
Note:
Shape has values of the form Circle r where r is a float, and Rect x y where x and y are floats.
Circle and Rect can be viewed as functions that construct values of type Shape:
Circle :: Float Shape
Rect :: Float Float Shape
![Page 11: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/11.jpg)
11
Recursive Types
In Haskell, new types can be declared in terms of themselves. That is, types can be recursive.
data Nat = Zero | Succ Nat
Nat is a new type, with constructors Zero :: Nat and
Succ :: Nat Nat.
![Page 12: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/12.jpg)
12
Note:
A value of type Nat is either Zero, or of the form Succ n where n :: Nat. That is, Nat contains the following infinite sequence of values:
Zero
Succ Zero
Succ (Succ Zero)
![Page 13: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/13.jpg)
13
We can think of values of type Nat as natural numbers, where Zero represents 0, and Succ represents the successor function 1+.
For example, the value
Succ (Succ (Succ Zero))
represents the natural number
1 + (1 + (1 + 0)) 3=
![Page 14: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/14.jpg)
14
Using recursion, it is easy to define functions that convert between values of type Nat and Int:
nat2int :: Nat Int
nat2int Zero = 0
nat2int (Succ n) = 1 + nat2int n
int2nat :: Int Nat
int2nat 0 = Zero
int2nat (n+1) = Succ (int2nat n)
![Page 15: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/15.jpg)
15
Two naturals can be added by converting them to integers, adding, and then converting back:
However, using recursion the function add can be defined without the need for conversions:
add :: Nat Nat Nat
add m n = int2nat (nat2int m + nat2int n)
add Zero n = n
add (Succ m) n = Succ (add m n)
![Page 16: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/16.jpg)
16
For example:
add (Succ (Succ Zero)) (Succ Zero)
Succ (add (Succ Zero) (Succ Zero))=
Succ (Succ (add Zero (Succ Zero))=
Succ (Succ (Succ Zero))=
Note:
The recursive definition for add corresponds to the laws 0+n = n and (1+m)+n = 1+(m+n).
![Page 17: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/17.jpg)
17
Arithmetic Expressions
Consider a simple form of expressions built up from integers using addition and multiplication.
1
+
32
![Page 18: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/18.jpg)
18
Using recursion, a suitable new type to represent such expressions can be declared by:
For example, the expression on the previous slide would be represented as follows:
data Expr = Val Int | Add Expr Expr | Mul Expr Expr
Add (Val 1) (Mul (Val 2) (Val 3))
![Page 19: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/19.jpg)
19
Using recursion, it is now easy to define functions that process expressions. For example:
size :: Expr Int
size (Val n) = 1
size (Add x y) = size x + size y
size (Mul x y) = size x + size y
eval :: Expr Int
eval (Val n) = n
eval (Add x y) = eval x + eval y
eval (Mul x y) = eval x * eval y
![Page 20: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/20.jpg)
20
Note:
The three constructors have types:
Val :: Int ExprAdd :: Expr Expr ExprMul :: Expr Expr Expr
Many functions on expressions can be defined by replacing the constructors by other functions using a suitable fold function. For example:
eval = fold id (+) (*)
![Page 21: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/21.jpg)
21
Binary Trees
In computing, it is often useful to store data in a two-way branching structure or binary tree.
5
7
96
3
41
![Page 22: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/22.jpg)
22
Using recursion, a suitable new type to represent such binary trees can be declared by:
For example, the tree on the previous slide would be represented as follows:
data Tree = Leaf Int | Node Tree Int Tree
Node (Node (Leaf 1) 3 (Leaf 4)) 5 (Node (Leaf 6) 7 (Leaf 9))
![Page 23: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/23.jpg)
23
We can now define a function that decides if a given integer occurs in a binary tree:
occurs :: Int Tree Booloccurs m (Leaf n) = m==noccurs m (Node l n r) = m==n || occurs m l || occurs m r
But… in the worst case, when the integer does not occur, this function traverses the entire tree.
![Page 24: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/24.jpg)
24
Now consider the function flatten that returns the list of all the integers contained in a tree:
flatten :: Tree [Int]flatten (Leaf n) = [n]flatten (Node l n r) = flatten l ++ [n] ++ flatten r
A tree is a search tree if it flattens to a list that is ordered. Our example tree is a search tree, as it flattens to the ordered list [1,3,4,5,6,7,9].
![Page 25: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/25.jpg)
25
Search trees have the important property that when trying to find a value in a tree we can always decide which of the two sub-trees it may occur in:
This new definition is more efficient, because it only traverses one path down the tree.
occurs m (Leaf n) = m==n
occurs m (Node l n r) | m==n = True
| m<n = occurs m l
| m>n = occurs m r
![Page 26: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/26.jpg)
26
Exercise
A binary tree is complete if the two sub-trees of every node are of equal size. Define a function that decides if a binary tree is complete.data Tree = Leaf Int
| Node Tree Int Tree
Node (Node (Leaf 1) 3 (Leaf 4)) 5 (Node (Leaf 6) 7 (Leaf 9))
occurs :: Int Tree Booloccurs m (Leaf n) = m==noccurs m (Node l n r) = m==n || occurs m l || occurs m r
![Page 27: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/27.jpg)
27
ModulesSo far, we’ve been using built-in functions provided in the Haskell prelude. This is a subset of a larger library that is provided with any installation of Haskell. (Google for Hoogle to see a handy search engine for these.)
Examples of other modules: - lists - concurrent programming - complex numbers - char - sets - …
![Page 28: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/28.jpg)
28
Example: Data.List
To load a module, we need to import it:
numUniques :: (Eq a) => [a] -> Int numUniques = length . nub
import Data.List
All the functions in this module are immediately available:
This is a function in Data.List that removes duplicates from a list.
function concatenatio
n
![Page 29: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/29.jpg)
29
You can also load modules from the command prompt:
ghci> :m + Data.List
Or several at once:
import Data.List (nub, sort) import Data.List hiding (nub)
ghci> :m + Data.List Data.Map Data.Set
Or import only some, or all but some:
![Page 30: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/30.jpg)
30
If duplication of names is an issue, can extend the namespace:
import qualified Data.Map
When the Data.Map gets a bit long, we can provide an alias:
import qualified Data.Map as M
And now we can just type M.filter, and the normal list filter will just be filter.
This imports the functions, but we have to use Data.Map to use them – like Data.Map.filter.
![Page 31: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/31.jpg)
31
Data.List has a lot more functionality than we’ve seen. A few examples:
ghci> intersperse '.' "MONKEY" "M.O.N.K.E.Y" ghci> intersperse 0 [1,2,3,4,5,6] [1,0,2,0,3,0,4,0,5,0,6]
ghci> intercalate " " ["hey","there","guys"] "hey there guys" ghci> intercalate [0,0,0] [[1,2,3],[4,5,6],
[7,8,9]]
[1,2,3,0,0,0,4,5,6,0,0,0,7,8,9]
![Page 32: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/32.jpg)
32
And even more:
ghci> transpose [[1,2,3],[4,5,6],[7,8,9]]
[[1,4,7],[2,5,8],[3,6,9]] ghci> transpose ["hey","there","guys"] ["htg","ehu","yey","rs","e"]
ghci> concat ["foo","bar","car"] "foobarcar" ghci> concat [[3,4,5],[2,3,4],[2,1,1]] [3,4,5,2,3,4,2,1,1]
![Page 33: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/33.jpg)
33
And even more:
ghci> and $ map (>4) [5,6,7,8] True ghci> and $ map (==4) [4,4,4,3,4] False
ghci> any (==4) [2,3,5,6,1,4] True ghci> all (>4) [6,9,10] True
![Page 34: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/34.jpg)
34
A nice example: adding functions
Functions are often represented as vectors: 8x^3 + 5x^2 + x - 1 is [8,5,1,-1].
So we can easily use List functions to add these vectors:
ghci> map sum $ transpose [[0,3,5,9],[10,0,0,9],[8,5,1,-1]]
[18,8,6,17]
![Page 35: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/35.jpg)
35
There are a ton of these functions, so I could spend all semester covering just lists.
More examples: group, sort, dropWhile, takeWhile, partition, isPrefixOf, find, findIndex, delete, words, insert,…
Instead, I’ll make sure to post a link to a good overview of lists on the webpage, in case you need them.
In essence, if it’s a useful thing to do to a list, Haskell probably supports it!
![Page 36: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/36.jpg)
36
The Data.Char module: includes a lot of useful functions that will look similar to python, actually.
Examples: isAlpha, isLower, isSpace, isDigit, isPunctuation,…
ghci> all isAlphaNum "bobby283" True ghci> all isAlphaNum "eddy the fish!"False ghci> groupBy ((==) `on` isSpace)
"hey guys its me" ["hey"," ","guys"," ","its"," ","me"]
![Page 37: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/37.jpg)
37
The Data.Char module has a datatype that is a set of comparisons on characters. There is a function called generalCategory that returns the information. (This is a bit like the Ordering type for numbers, which returns LT, EQ, or GT.)ghci> generalCategory ' ' Space ghci> generalCategory 'A' UppercaseLetter ghci> generalCategory 'a' LowercaseLetter ghci> generalCategory '.' OtherPunctuation ghci> generalCategory '9' DecimalNumber ghci> map generalCategory " ¥t¥nA9?|" [Space,Control,Control,UppercaseLetter,DecimalNumber,OtherPunctuation,MathSymbol] ]
![Page 38: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/38.jpg)
38
There are also functions that can convert between Ints and Chars:
ghci> map digitToInt "FF85AB" [15,15,8,5,10,11]ghci> intToDigit 15 'f' ghci> intToDigit 5 '5' ghci> chr 97 'a' ghci> map ord "abcdefgh" [97,98,99,100,101,102,103,104]
![Page 39: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/39.jpg)
39
Neat application: Ceasar ciphersA primitive encryption cipher which encodes messages by shifted them a fixed amount in the alphabet.
Example: hello with shift of 3
encode :: Int -> String -> String encode shift msg = let ords = map ord msg shifted = map (+ shift) ords in map chr shifted
![Page 40: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/40.jpg)
40
Now to use it:
ghci> encode 3 "Heeeeey" "Khhhhh|" ghci> encode 4 "Heeeeey" "Liiiii}" ghci> encode 1 "abcd" "bcde" ghci> encode 5 "Marry Christmas! Ho ho ho!”"Rfww~%Hmwnxyrfx&%Mt%mt%mt&"
![Page 41: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/41.jpg)
41
Decoding just reverses the encoding:
decode :: Int -> String -> String decode shift msg =
encode (negate shift) msg
ghci> encode 3 "Im a little teapot" "Lp#d#olwwoh#whdsrw" ghci> decode 3 "Lp#d#olwwoh#whdsrw" "Im a little teapot" ghci> decode 5 . encode 5 $ "This is a sentence" "This is a sentence"
![Page 42: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/42.jpg)
42
Making our own modules
We specify our own modules at the beginning of a file. For example, if we had a set of geometry functions:
module Geometry ( sphereVolume , sphereArea , cubeVolume , cubeArea , cuboidArea , cuboidVolume ) where
![Page 43: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/43.jpg)
43
Then, we put the functions that the module uses:sphereVolume :: Float -> Float sphereVolume radius = (4.0 / 3.0) * pi *
(radius ^ 3)
sphereArea :: Float -> Float sphereArea radius = 4 * pi * (radius ^ 2)
cubeVolume :: Float -> Float cubeVolume side = cuboidVolume side side side …
![Page 44: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/44.jpg)
44
Note that we can have “private” helper functions, also:
cuboidVolume :: Float -> Float -> Float -> Float
cuboidVolume a b c = rectangleArea a b * c
cuboidArea :: Float -> Float -> Float -> Float
cuboidArea a b c = rectangleArea a b * 2 + rectangleArea a c * 2 + rectangleArea c b * 2
rectangleArea :: Float -> Float -> Float rectangleArea a b = a * b
![Page 45: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/45.jpg)
45
Can also nest these. Make a folder called Geometry, with 3 files inside it:•Sphere.hs•Cubiod.hs•Cube.hsEach will hold a separate group of functions.
To load:
import Geometry.Sphere
Or (if functions have same names):import qualified Geometry.Sphere as Sphere
![Page 46: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/46.jpg)
46
The modules:
module Geometry.Sphere ( volume , area ) where
volume :: Float -> Float volume radius = (4.0 / 3.0) * pi * (radius ^ 3) area :: Float -> Float area radius = 4 * pi * (radius ^ 2)
![Page 47: PROGRAMMING IN HASKELL](https://reader035.fdocuments.in/reader035/viewer/2022062323/568157c4550346895dc54a7f/html5/thumbnails/47.jpg)
47
module Geometry.Cuboid ( volume , area ) where
volume :: Float -> Float -> Float -> Float volume a b c = rectangleArea a b * c
…