Lecture 4
#SyntaxSwag
F12, then click ConsoleF12, then click ConsoleCtrl+Shift+k↓, PgDn, n, j |
next slide |
↑, PgUp, p, k |
prev slide |
Esc |
enables ctrl+f globally |
|
Haskell is
|
Data looks like
|
Lists and Tuples are useful data structures
|
List [1,2,3]
|
Tuple (1, "one")
|
Everything in Haskell has a Type
Here are some Type declarations.These are your greatest weapons.
head :: [a] -> a -- gets the first element of a list
tail :: [a] -> [a] -- gets everything but the first element
last :: [a] -> a -- gets the last element of a list
init :: [a] -> [a] -- gets everything but the last element
(++) :: [a] -> [a] -> [a] -- concatenates two lists together
(:) :: a -> [a] -> [a] -- prepends an element to a list
fst :: (a,b) -> a -- gets the first element of a tuple
snd :: (a,b) -> b -- gets the second element of a tuple
-- This example uses 'succ' to get next letter
cipher :: String -> Int-> String
cipher "" n = ""
cipher str n = rotate (head str) n : cipher (tail str) n
rotate :: Char -> Int -> Char
rotate c 0 = c
rotate c n = rotate (next c) (n-1)
next :: Char -> Char
next c = if c=='z' then 'a' else succ c
-- Importing a really useful library
-- designed by Preetam C. Jinka
import Data.Char
cipher :: [Char] -> Int -> [Char]
cipher [] _ = []
cipher (s:ss) n = (rotate s n) : (cipher ss n)
rotate :: Char -> Int -> Char
rotate c 0 = c
rotate c n = int2letter ( mod ((letter2int c) + n) 26 )
letter2int c = ord c - 97
int2letter n = chr (n + 97)
-- Here's a one-line solution
-- designed by James C. Sun
import Data.Char
cipher :: [Char] -> Int -> [Char]
cipher s n = map (\c -> ([c..'z'] ++ ['a'..c]) !! mod n 26) s
-- designed by Matthias pall Gissurarson
import Data.List
import Data.Maybe
alphabet:: [Char]
alphabet = cycle ['a'..'z']
rotate:: Int -> Char -> Char
rotate k a = alphabet !! (k + ( fromJust ( elemIndex a alphabet)))
cipher:: [Char] -> Int -> [Char]
cipher str k = map (rotate k) str
A function can have multiple patterns
Almost like overloading methods in Java or C++
guess :: Int -> [Char]
guess 42 = "correct!"
guess x = "wrong guess!"
Each pattern has the same type declaration
Patterns are matched in order, top-down
Only the first matched pattern is evaluated
The patterns must exhaust the entire domain
fib :: Int -> Int
fib n = fib(n-1) + fib(n-2)
fib 0 = 1
fib 1 = 1
The base case is never hit.
The first pattern eats up everything!
∞ loop
You can even match lists using Construct
head (firstItem : everythingElse) = firstItem
tail (x:xs) = xs
Write a function to detect if a list is a palindrome
isPal :: Eq a => [a] -> Bool
isPal :: Eq a => [a] -> Bool
isPal [x] = True
isPal [x,y] = x == y
isPal (x:xs) = (x == (last xs)) && isPal (init xs)
(clear answer)
(show answer)
We can define fst with pattern matching
fst :: (a,b) -> a
fst (x,y) = x
Try defining head with pattern matching
head :: [a] -> a
head :: [a] -> a
head (x:xs) = x
head [x] = x
head [] = error "empty list"
(clear answer)
(show answer)
We can specify when a value is unused.
The "_" symbol is called a wildcard in Haskell.
This is how it's used:
head (x:_) = x
tail (_:xs) = xs
When GHCi is angry, it produces error messages through the error function.
error :: [Char] -> a
The official implementation of head is
head :: [a] -> a
head (x:_) = x
head [] = error "Prelude.head: empty list"
Guards are clean if statements.
Just like with pattern matching, order matters.
A guard is introduced by the | symbol.
And it's followed by a Bool expression.
Then followed by the function body
guessMyNumber x
| x > 27 = "Too high!"
| x < 27 = "Too low!"
| otherwise = "Correct!"
otherwise is just a fancy word for True
Guards are very powerful.
Anything done with pattern matching can be done with guards.
head' :: [a] -> a
head' xs
| null xs = error "list is empty"
| otherwise = xs !! 0
!! is a function that gives an element at an index
These are not like your typical Java variables
In Java or C++, you can redefine variables:
x = 1;
...
x = 2;
Mathematically, this makes no sense.
1=2 Preposterous!
Haskell variables are immutable.
Once defined, they can't change.
They can be used with the let keyword.
slope (x1,y1) (x2,y2) = let dy = y2-y1
dx = x2-x1
in dy/dx
Or with the where keyword.
slope (x1,y1) (x2,y2) = dy/dx
where dy = y2-y1
dx = x2-x1
In Haskell, indentation matters.
Code which is part of some expression should be indented further in than the beginning of that expression*
Level-1
Level-2
Level-3
Level-3
Level-3
Level-2
Level-3
Level-3
Level-1
Level-2
Level-2
Level-1
Don't use tab. Use spaces ' '.
Convert between metric and imperial.
convert :: (Double, [Char]) -> (Double, [Char])
Prelude> convert (1, "m")
(1.09361, "yd")
Prelude> convert (1, "L")
(0.264172, "gal")
Prelude> convert (1, "kg")
(2.20462, "lb")