GHCi — GHC Haskell REPL: interactively execute commands
$ stack repl # you can also use 'stack ghci' to run 'ghci', or
$ cabal new-repl # from inside project
<Some logging information, bla-bla-bla>
Prelude> -- 'Prelude' prompt can be changed; slides use 'ghci>' prompt
ghci> 1 + 2 * 3
7
ghci> 3 / 5 * (7 + 1)
4.8
ghci> 2 ^ 16
65536
ghci> 1 + 1 == 3
False
ghci> 2 + 2 /= 5
True
ghci> 21 * 22 <= 20 * 23
False
ghci> 1 < 2 && 2 < 3
True
ghci> 0 > 0 || 10 >= 10
True
Basic arithmetic & boolens & comparisons
At least you can use Haskell as calculator!
Calling functions in ghci: arguments separated by space character
ghci> not True
False
ghci> div 7 3 -- integral division (7 divide by 3)
2
ghci> max 3 5
5
ghci> min 6 (10 * 2) -- not the same as 'min 6 10 * 2'
6
Personally I like space separated arguments; compare
max 1 2 // Haskell
std::max(1, 2) // C++
Math.max(1, 2) // Java
But you should think about arguments grouping
ghci> div 7 3 + 1
3
ghci> div 7 (3 + 1)
1
ghci> div 7 + 1 3
*** Compilation error!
ghci> div (7 + 1) 3
2
Infix and Prefix call syntax:
* Both — operators and functions — can be called in prefix and infix
* Wrap operator in () to call in prefix
* Wrap function in `` (bacticks, ~ on keyboard) to call in infix
ghci> 3 + 4
7
ghci> (+) 3 4
7
ghci> mod 7 3 -- 7 modulo 3
1
ghci> 7 `mod` 3
1
Assigning variables
-- Before GHC 8.0.1
ghci> let x = 3 + 5
ghci> x + 1
9
-- After GHC 8.0.1
ghci> x = 7 + 8
ghci> x * 2
30
String type
ghci> greeting = "Hello"
ghci> greeting ++ " world!" -- use ++ instead of + to concatenate strings
"Hello world!"
ghci> "DONE: say \"" ++ greeting ++ " world!\""
"DONE: say "Hello world!""
Types are important! Use `:t` command to see type in GHCi
ghci> :t 'x'
'x' :: Char
ghci> :t False
False :: Bool
ghci> :t not
not :: Bool -> Bool
ghci> :t (&&)
(&&) :: Bool -> Bool -> Bool
ghci> :t 42
42 :: Num t => t -- numeric constants are polymorphic;
-- we will get to that later
Use `:set +t` command to show types after each command
ghci> :set +t
ghci> 'x'
'x'
it :: Char
ghci> False || True
True
it :: Bool
ghci> let x = False
x :: Bool
-- This function adds first number to product of second and third
addMul :: Int -> Int -> Int -> Int -- This is type signature of 'addMul'
addMul x y z = x + y * z -- This is definition of 'addMul'
-- Btw, single-line comments start with --
greet :: String -> String
greet name = "Hello, " ++ name ++ "!"
Let's create our functions! Put next code into 'Lecture.hs' file
$ stack ghci # from folder where 'Lecture.hs' is
ghci> :l Lecture.hs -- :l is short form of :load command
ghci> addMul 1 2 3
7
ghci> greet "Haskell World"
"Hello, Haskell World!"
Reminder: arguments grouping
addMul 1 2 3 + 1
addMul 1 2 (3 + 1)
addMul 1 (1 + 1) 3
addMul 1 1 + 1 3
infixr 1 ==> -- specify associativity for 'implies' operator
(==>) :: Bool -> Bool -> Bool
a ==> b = not a || b
In Haskell you can create your own operators! It doesn't mean you should... But sometimes they are really handy.
ghci> False ==> False ==> False
True
ghci> False ==> (False ==> False)
True
ghci> (False ==> False) ==> False
False
[infix|infixl|infixr] <precedence ∈ [0..10)> [operators]
-- somewhere in 'base'
infixr 2 ||
(||) :: Bool -> Bool -> Bool
Function application — space — has highest precedence 10.
ghci> True || True ==> False
???
ghci> True || (True ==> False)
???
ghci> True || True ==> False
False
ghci> True || (True ==> False)
True
infixr 3 &&
(&&) :: Bool -> Bool -> Bool
ghci> [1 + 2, 3 + 4, 5 * 6] -- comma-separated
[3,7,30]
Linked lists: homogeneous collection of elements
ghci> let list = [2, 1, 3] -- create list variable
ghci> [5, 10] ++ list -- concatenate lists with ++ operator
[5, 10, 2, 1, 3]
ghci> 10 : list -- : operator adds element to the beginning of list
[10, 2, 1, 3]
ghci> list
[2, 1, 3]
ghci> reverse list -- this doesn't change 'list'
[3, 1, 2]
ghci> list
[2, 1, 3]
ghci> let anotherList = 5 : list -- new variable to save changes
ghci> anotherList
[5, 2, 1, 3]
ghci> list
[2, 1, 3]
All variables in Haskell are immutable by default!
emptyList :: [Int]
emptyList = []
listExample :: [Int]
listExample = [2, 1, 3] -- 2:1:3:[]
singletonList :: [Int]
singletonList = 1 : emptyList -- or simply [1]
listExample' = 5:10:listExample -- [5, 10, 2, 1, 3]
twoLists = singletonList ++ listExample -- [1, 2, 1, 3]
trinity = listExample ++ [7] ++ twoLists -- [2, 1, 3, 7, 1, 2, 1, 3]
string :: [Char] -- extremely inefficent representation of String
string = "str" -- ['s', 't', 'r']
otherString :: String -- other name for [Char]
otherString = "other " ++ string -- "other str"
ghci> "" == []
True
Java 8
IntStream.range(0, 5).toArray(); // {0, 1, 2, 3, 4};
IntStream.rangeClosed(0, 5).toArray(); // {0, 1, 2, 3, 4, 5};
IntStream.iterate(0, x -> x + 2).limit(5).toArray() // {0, 2, 4, 6, 8};
Kotlin
0..5 // 0, 1, 2, 3, 4, 5
0 until 5 // 0, 1, 2, 3, 4
0..5 step 2 // 0, 2, 4
Haskell
[0 .. 5] -- [0, 1, 2, 3, 4, 5]
[1, 3 .. 5] -- [1, 3, 5, 7]
[0..] -- [0, 1, 2, 3, ...] : infinite list
[0, 2 ..] -- [0, 2, 4, 6, ...] : all even numbers
[5, 4 .. 1] -- [5, 4, 3, 2, 1]
[5 .. 1] -- [] — empty list
Python
range(5) # 0, 1, 2, 3, 4
range(1, 5) # 1, 2, 3, 4
range(1, 5, 2) # 1, 3
ghci> let l = [2, 1, 3]
ghci> head l
2
ghci> tail l
[1, 3]
ghci> last l
3
ghci> init l
[2, 1]
Accessing elements of list
ghci> drop 2 [2, 1, 3]
[3]
ghci> [2, 1, 3] !! 2 -- l !! i ≡ l[i], O(i) time
3
Functions from Prelude
And moar: takeWhile, splitAt, iterate, reverse, lines, unlines, etc. Prelude has a lot of functions and operators to work with lists.
ghci> take 1 [2, 1, 3]
[2]
ghci> replicate 3 [1..5]
[[1,2,3,4,5], [1,2,3,4,5], [1,2,3,4,5]]
ghci> zip [1,2,3] "abc"
[(1, 'a'), (2, 'b'), (3, 'c')] -- (1, 'a') is pair of type (Int, Char)
ghci> unzip [(5, True), (10, False)]
([5, 10], [True, False])
ghci> words "Hello, Haskell \t\n\n world!"
["Hello,", "Haskell", "world!"]
ghci> unwords ["Hello,", "Haskell", "world!"]
"Hello, Haskell world!"
void f(); // function definition is statement
int random() {
return 4; // `return` is statement, 4 is expression
}
int main() {
int a = random(); // variable declaration: statement, `random()` is expression
if (a > 0) { // `if` operator is statement, `a > 0` is expression
printf("Wow, such C++"); // statement, or?...
}
}
С++
Common statements in imperative languages are expressions in Haskell
pythagoras :: Int -> Int -> Int
pythagoras x y = x^2 + y^2
let <bindings> in <expression>
Let's implement with let:
Already can do it in simple way!
With let
pythagoras :: Int -> Int -> Int
pythagoras x y = let x2 = x ^ 2 -- Alignment is EXTREMELY IMPORTANT!!!
y2 = y ^ 2 -- No tabs, only spaces!
in x2 + y2
Haskell is layout-sensitive language.
It means that ugly code won't compile.
ghci> let x = 10 -- saves variable 'x', doesn't print it
ghci> x
10
ghci> let y = 1 + 3 in y -- doesn't save variable 'y', prints result immediately
4
ghci> y
<interactive>:41:1: error: Variable not in scope: y
Believe me, there's a reason to have several ways to assign variables in ghci
pythagoras :: Double -> Double -> Double
pythagoras a b = a2 + b2
where -- details of implementation are inside 'where'
square x = x ^ 2
a2 = square a
b2 = square b
Haskell
Java
double pythagoras(double a, double b) {
class Squarer {
double eval(double x) { return x * x; }
}
final double a2 = new Squarer().eval(a);
final double b2 = new Squarer().eval(b);
return a2 + b2;
}
You want to define local functions or variables to: (1) not spoil global namespace or (2) for optimization purposes (in Haskell)
Difference between let and where?
factorial :: Integer -> Integer -- arbitrary precision integer type
factorial n = if n <= 1
then 1
else n * factorial (n - 1) -- this implementation is
-- extremely inefficient
if <predicate>
then <expression if predicate is True>
else <expression if predicate is False>
So it's more like ternary operator
Side note: use Natural from `Numeric.Natural` instead of Integer if you only mean non-negative (≥ 0) integers (like in example above)
public int collatzSum(int n) {
if (n < 0)
return 0;
else if (n == 1)
return 1;
else if (n % 2 == 0)
return n + collatzSum(n / 2);
else
return n + collatzSum(3 * n + 1);
}
Java
collatzSum :: Natural -> Natural
collatzSum n
| n == 1 = 1
| even n = n + collatzSum (n `div` 2)
| otherwise = n + collatzSum (3 * n + 1)
Haskell
otherwise :: Bool
otherwise = True
What is otherwise?
public String getFont(int fontConstant) {
String font = null;
switch (fontConstant) {
case 0: font = "PLAIN"; break;
case 1: font = "BOLD"; break;
case 2: font = "ITALIC"; break;
default: font = "UNKNOWN";
}
return font;
}
Java
Haskell
getFont :: Int -> String
getFont n = case n of
0 -> "PLAIN"
1 -> "BOLD"
2 -> "ITALIC"
_ -> "UNKNOWN"
caseOperation
:: Char -> Int -> Int -> Int
caseOperation op x y =
case op of
'+' -> x + y
'-' -> x - y
_ -> 0 -- _ should be
-- under ' and
-- not under -
case <expression> of
[<pattern> → <expression>]
inc, dec :: Int -> Int
inc x = x + 1
dec x = x - 1
Function in Haskell is a first class object. It means that you can pass functions as arguments to other functions.
changeTwiceBy :: (Int -> Int) -> Int -> Int
changeTwiceBy operation value = operation (operation value)
ghci> changeTwiceBy inc 5
7
ghci> changeTwiceBy dec 5
3
\arg1 arg2 ... argN → <expression>
ghci> changeTwiceBy (\x -> x + 1) 5
7
ghci> changeTwiceBy (\x -> x * 2) 5
20
tripleApply :: (Int -> Int -> Int) -> Int -> Int
tripleApply f x = (x `f` x) `f` (x `f` x)
ghci> tripleApply (\x y -> x ^ y) 2
256
ghci> tripleApply (^) 2 -- you can pass operators as functions
256
Without lambda
first :: a -> a -> a
first x y = x
public <T> T first(T x, T y) {
return x;
}
Java
Haskell
parametric polymorphism vs. ad-hoc polymorphism
overloading?
id :: a -> a
id x = x
fst :: (a, b) -> a
snd :: (a, b) -> b
emptyList :: [a]
emptyList = []
repeatThree :: a -> [a]
repeatThree x = [x, x, x]
ghci> repeatThree 'x'
"xxx"
it :: [Char]
ghci> repeatThree True
[True, True, True]
it :: [Bool]
ghci> tripleApply (^) 2
256
ghci> tripleApply (++) [3,1]
[3, 1, 3, 1, 3, 1, 3, 1]
tripleApply :: (a -> a -> a) -> a -> a
tripleApply f x = f (f x x) (f x x)
map :: (a -> b) -> [a] -> [b]
filter :: (a -> Bool) -> [a] -> [a]
foldr1 :: (a -> a -> a) -> [a] -> a
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
ghci> map negate [2, 1, 3]
[-2,-1,-3]
ghci> filter odd [1,2,3,4,5]
[1,3,5]
ghci> foldr1 (+) [1,2,4] -- sum [1,2,4]
7
ghci> takeWhile isUpper "HTMLXml"
"HTMLX"
ghci> zipWith max [1..5] [5, 4 .. 1]
[5,4,3,4,5]
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry f p = f (fst p) (snd p)
ghci> uncurry (+) (3, 4)
7
ghci> curry fst 3 4
3
ghci> curry snd 3 4
4
Functions in Haskell are very simple! They have only one argument and one result. Function arrow is right-associative.
bar :: (Int -> Int) -> Int -> Int
bar :: (Int -> Int) -> (Int -> Int) -- ^ these two bars are the same
evilBar :: (Int -> Int) -> Int -> Int
evilBar :: Int -> Int -> Int -> Int -- ^ and these two are not
foo :: Int -> Char -> String -> Double
foo :: Int -> (Char -> (String -> (Double))
foo, bar :: Int -> String
foo x = show x
bar = show
-- monomoprhic 'div'
div :: Int -> (Int -> Int)
Works with operators!
ghci> map (+2) [2, 1, 3]
[4, 3, 5]
ghci> filter (<3) [1..5]
[1, 2]
ghci> filter (3<) [1..5]
[4, 5]
-- div7By is partially applied div
ghci> div7By = div (7 :: Int)
div7By :: Int -> Int
ghci> div7By 2
3
ghci> div7By 3
2
ghci> (div 7) 3
2
ghci> map (div 7) [1..7]
[7,3,2,1,1,1,1]
ghci> map (5+) [1..5]
[6, 7, 8, 9, 10]
ghci> map (+5) [1..5]
[6, 7, 8, 9, 10]
You can partially apply (+) operator without problems
But you can't do the same with (-) operator because (-5) is a constant
ghci> map (5-) [1..5]
[4,3,2,1,0]
ghci> map (-5) [1..5]
• Non type-variable argument in the constraint: Num (a -> b)
(Use FlexibleContexts to permit this)
• When checking the inferred type
it :: forall a b. (Enum a, Num (a -> b), Num a) => [b]
Use `subtract` function instead
ghci> subtract 5 3
-2
ghci> map (subtract 5) [1..5]
[-4, -3, -2, -1, 0]
flip :: (a -> b -> c) -> b -> a -> c
flip f b a = f a b
When you finally understand flip
show2 :: Int -> Int -> String
show2 x y = show x ++ " and " ++ show y
showSnd, showFst, showFst'
:: Int -> String
showSnd = show2 1
showFst = flip show2 2
showFst' = (`show2` 2)
ghci> showSnd 10
"1 and 10"
ghci> showFst 10
"10 and 2"
ghci> showFst' 42
"42 and 2"
ghci> :t flip id
???
ghci> :t flip id
flip id :: b -> (b -> c) -> c
fact :: Integer -> Integer
fact 0 = 1
fact n = n * fact (n - 1)
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs -- [2, 1, 3] == 2 : 1 : 3 : []
sumList3 :: [Int] -> Int
sumList3 [x, y, z] = x + y + z
sumList3 _ = 0
puzzle :: [Int] -> [Int]
puzzle (x:xs@(y:z:_)) = if x < y && y > z then y : c else c
where
c = puzzle xs
puzzle _ = []
dropWhile :: (a -> Bool) -> [a] -> [a]
dropWhile _ [] = []
dropWhile p l@(x:xs) = if p x then dropWhile p xs else l
stringLit :: String -> String
stringLit "such" = "pattern"
stringLit "much" = "amaze"
stringLit x = "wow"
Some Haskell features are not enabled by default. They can be enabled by so-called 'language pragmas'.
-- in ghci
ghci> :set -X<NameOfPragma>
ghci> map (\x -> (42, x)) [1..5]
[(42,1), (42,2), (42,3), (42,4), (42,5)]
ghci> map (\x -> (x, 42)) [1..5]
[(1,42), (2,42), (3,42), (4,42), (5,42)]
Example: you want to pair each element of list with 42.
ghci> :set -XTupleSections
ghci> map (42,) [1..5]
[(42,1), (42,2), (42,3), (42,4), (42,5)]
ghci> map (,42) [1..5]
[(1,42), (2,42), (3,42), (4,42), (5,42)]
-- in MyModule.hs
{-# LANGUAGE NameOfPragma #-}
veryLongFunctionName :: Int -> String
veryLongFunctionName 0 = foo
veryLongFunctionName 1 = bar
veryLongFunctionName n = baz n
{-# LANGUAGE LambdaCase #-}
veryLongFunctionName :: Int -> String
veryLongFunctionName = \case
0 -> foo
1 -> bar
n -> baz n
-- syntax sugar for
veryLongFunctionName :: Int -> String
veryLongFunctionName x = case x of
0 -> foo
1 -> bar
n -> baz n
exactTwoWords :: String -> Bool
exactTwoWords s = case words s of
[_, _] -> True
_ -> False
{-# LANGUAGE ViewPatterns #-}
exactTwoWords :: String -> Bool
exactTwoWords (words -> [_, _]) = True
exactTwoWords _ = False
infixr 0 $
($) :: (a -> b) -> a -> b -- function application
f $ x = f x
In Functional programming everything is a function. Even function application — space ' ' — is function. What if...
Why? Useful to remove ()
foo, bar :: [Int] -> Int
foo list = length (filter odd (map (div 2) (filter even (map (div 7) list))))
bar list = length $ filter odd $ map (div 2) $ filter even $ map (div 7) list
ghci> length [0..5]
6
ghci> length $ [0..5]
6
ghci> let funs = [(+2), div 7, (*5)]
funs :: [Integer -> Integer]
ghci> let vals = [20, 30, 40]
vals :: [Integer]
ghci> :t zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
ghci> zipWith ($) funs vals
[22, 0, 200]
ghci> zipWith id funs vals
[22, 0, 200]
Reverse application
infixl 1 &
(&) :: a -> (a -> b) -> b -- in 'Data.Function' module
x & f = f x
($) :: (a -> b) -> a -> b
(&) :: a -> (a -> b) -> b
(&) = flip ($)
ghci> (\l -> l ++ reverse l) [2,1,3]
[2,1,3,3,1,2]
ghci> [2,1,3] & \l -> l ++ reverse l -- useful for removing parenthesis
[2,1,3,3,1,2]
infixr 9 .
(.) :: (b -> c) -> (a -> b) -> (a -> c) -- same as (b -> c) -> (a -> b) -> a -> c
f . g = \x -> f (g x)
incNegate :: Int -> Int
incNegate x = negate (x + 1)
incNegate x = negate $ x + 1
incNegate x = (negate . (+1)) x
incNegate x = negate . (+1) $ x
incNegate = negate . (+1) -- η-reduce
"outside . inside" is a composition
1. \x -> outside (inside x)
2. \x -> outside $ inside x
3. \x -> outside . inside $ x
4. outside . inside
foo, bar :: [Int] -> Int
foo patak = length $ filter odd $ map (div 2) $ filter even $ map (div 7) patak
bar = length . filter odd . map (div 2) . filter even . map (div 7)
Don't need to keep names of variables in mind
Instead of specifying what to do with variables, you specify how data should be transformed
stringsTransform :: [String] -> [String]
stringsTransform l = map (\s -> map toUpper s) (filter (\s -> length s == 5) l)
stringsTransform l = map (\s -> map toUpper s) $ filter (\s -> length s == 5) l
stringsTransform l = map (map toUpper) $ filter ((== 5) . length) l
stringsTransform = map (map toUpper) . filter ((== 5) . length)
Simplifying complex function
stringsTransform :: [String] -> [String]
stringsTransform l = map (\s -> map toUpper s) (filter (\s -> length s == 5) l)
stringsTransform l = map (\s -> map toUpper s) $ filter (\s -> length s == 5) l
stringsTransform l = map (map toUpper) $ filter ((== 5) . length) l
stringsTransform = map (map toUpper) . filter ((== 5) . length)
Simplifying complex function
ghci> [x | x <- [1..10], even x]
[2,4,6,8,10]
quickSort :: [Int] -> [Int]
quickSort [] = []
quickSort (x:xs)
= quickSort [y | y <- xs, y <= x] ++ [x] ++ quickSort [y | y <- xs, y > x]
ghci> filter even [1..10]
[2,4,6,8,10]
ghci> [if even x then "!" else "?" | x <- [1 .. 5]]
["?","!","?","!","?"]
ghci> [ x * y | x <- [1, 3, 5], y <- [2, 4, 6], x * y >= 10]
[12,18,10,20,30]
ghci> [13 | even 13] -- conditionally create singleton list
[]
ghci> [14 | even 14]
[14]
square x = x*x
square (1+2)
square (1+2)
=> (1+2)*(1+2)
(1+2)*(1+2)
=> 3*(1+2)
=> 3*3
=> 9
Evaluated (1+2) twice :(
Every expression can be represented as a graph
Every function corresponds to a reduction rule
No reduction rule for constructor
Lazy evaluation always tries to reduce the topmost function application first
No unevaluated redexes and graph represents the list 1:2:3:[].
42
(2, "hello")
\x -> (x + 1)
1 + 2
(\x -> x + 1) 2
"he" ++ "llo"
(1 + 1, 2 + 2)
10
2 : [1, 3]
'h' : ("e" ++ "llo")
[1, 2 * 2, 3 ^ 3]
[4, length undefined]
Just (2 + 7)
(1 + 2, 3 + 4)
\x -> x + 10
\zx -> foldr (+) zx [1, 2, 3]
1 + 1
1 + (2 + 3)
(\x -> x + 10) 3
length [1, 2, 3]
Just (2 + 7) >>=
\n -> Just $ n * 2
fromJust' :: Maybe a -> Int
fromJust' (Just a) = 10
ghci> fromJust' undefined
*** Exception: Prelude.undefined
first :: Int -> Int -> Int
first x _ = x
zeroF :: Int -> Int -> Int
zeroF x 0 = x
zeroF _ y = y
ghci> fromJust' $ Just undefined
10
ghci> first 10 undefined
10
ghci> zeroF 10 undefined
*** Exception: Prelude.undefined
Time: Lazy evaluation never performs more evaluation steps than eager evaluation.
Space: Memory used by an unevaluated expression may differ significantly from the memory used by its normal form
((((0 + 1) + 2) + 3) + 4)
It is called a space leak
ghci> [1..]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,
31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,
58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,
85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,
109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,
129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,
149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,
169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187, ...
Lists in Haskell can be infinite. But only required part is evaluated.
ghci> repeat 1
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, ...
ghci> take 5 [1..]
[1,2,3,4,5]
ghci> zip [0..] "abacaba"
[(0,'a'), (1,'b'), (2,'a'), (3,'c'), (4,'a'), (5,'b'), (6,'a')]
-- | @'fix' f@ is the least fixed point of the function @f@,
-- i.e. the least defined @x@ such that @f x = x@.
fix :: (a -> a) -> a
fix f = let x = f x in x
ghci> fix id
<hangs>
fix :: (a -> a ) -> a [1]
fix :: ((b -> c) -> (b -> c)) -> (b -> c) [2]
fix :: ((b -> c) -> b -> c ) -> b -> c [3]
import Data.Function (fix)
fixLen :: [a] -> Int
fixLen = fix $ \f l -> case l of
[] -> 0
(x:xs) -> 1 + f xs
ghci> fixLen [1..5]
5
Small challenge: implement fixLen using accumulator
primes :: [Int]
primes = filterPrime [2..]
where
filterPrime (p:xs) = p : filterPrime [x | x <- xs, x `mod` p /= 0]
ghci> take 15 primes
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]
fibs :: [Int]
fibs = 0 : 1 : zipWith (+) fibs (drop 1 fibs)
fib :: Int -> Int
fib n = fibs !! n
ghci> take 10 fibs
[0,1,1,2,3,5,8,13,21,34]
ghci> fib 50
12586269025
q1 = filter (even . length)
q2 = filter (odd . sum . take 5) . map (replicate 10)
q3 = length . filter id . map even -- id x = x
q4 = (. length) . (+)