TBC
Find pattern -> Define the rules
Pure function is purely mathematic function just map things to things
Are you functional thinking ?
2 layer of algorithm
- function High level for human comunication
- step as Low level for machine state
Step
- validate given string is a palindrome
- generate palindorme from string
- determine how many unique word are given sentence
- determine if two string are anagram
** palindorme คือ อูยองอู
Example : A → B
"this bat" "this cat" "this rat"
Solution
A → A1 → B1 → B
A → A1 as step1
B1 → B as step2
B1 -> B to count word
exactly we have -> [this, cat, bat, rat]
A1 -> B1 to unique
result -> [this, bat, this, cat, this, rat]
A -> A1
["this bat", "this cat", "this rat"]
Live Coding in Haskell
Example
> swap (A, B) this is pattern
> (B, A)
Let get started!
> count ["this", "bat", "cat", "rat"] => 4
> unique ["this, "bat", "cat", "rat"] => ["this, "bat", "cat", "rat"]
> count (unique ["this, "bat", "cat", "rat"]) => 4
state B1 -> B is now complete by above code!
> split "this bat this cat this rat" = ["this", "bat","this", "cat", "this","rat"]
so then
> count (unique (split "this bat this cat this rat")) = 4
then define function
countUniqueWord -> count . unique . split
count
> count = length
> count "this" = 4
unique we would like to sort or order or grouping
> unique = nub
> words " this is a cat"
> countUniqueWord -> count . unique . words
> countUniqueWord " this is a bat this is a cat this is a rat"
> 6
Warp-up to haskell thing
> code demo.hs
import Data.List
countUniqueWord = count . unique . words
where
count = length
unique = nub
support : มี user บางคน มีปัญหา
me : id user อะไรครับ (this is exactly)
Recap
Functional programming consist of probelm solving with pure function and computation of pattern and rewriting
But why does it matter ???
Introducing
"The worst pice of code you'll ever encounter"
= the code that we don't know what it solving
> if( a == 'a' || a == 'e' || a == 'i' || a == 'o' || a == 'u') {
count ++
}
เราเดาได้ว่า เช็คสระ แต่ถามว่าถูกไหม aren't vowels which this is low-level?
replace this with
if(isVowels(a)){
count++;
}
boolean isVowels(string a) {
a.toLowerCase();
return a == 'a' || a == 'e' || a == 'i' || a == 'i' || a == 'o' || a == 'u';
}
isVowels(a) function can be determine what we would like to solve and it is high level code to comunication
why we lowercase a in isVowels()
because we need to specific char 1 to 1 checking, so when we need to test is vowel we can easily assert isVowels(A) == 1
Functional thinking lead to
- Readable
- Reasonable
- Testable
- Well-factorized
Why does pure function matter ?
"Simple to reason with it"
Suppose we have a function
f: int -> int
f will result only int
** Avoid hidden dependencies
Side effects example
double monte(int n) {
int a = random()
int b = random()
//call random() something -> which it works using side effect, it depend on external seed value
//logging
logger.info("a =", a, "b = ", b)
return a * b
}
Can we tell any of that w/ just this?
No way
Purler function version
double pure_monte(a, b) {
return a * b
}
Why pure function is matter ?
-
ยกตัวอย่างการดึงค่าจาก cahce ใน monte() จะไม่เกิด log ถ้าดึง value จาก cahce
-
แล้วถ้าcode depend on random number มึงจะ assert ยังไงวะครับ
-
error logs: monte จะ reproduce ยังไง
"Everything is a member of a set"
eg. boolean [true, false] , int [(n, n-1), 0,(n, n+1)] and so on ...
But in computer programming SET usaually mean data structure or specific container
- Types
Saying e is Type T === e is element of T
- type inference
> type true
> boolean
> type 'A'
> char
//type is equal to set
Do functions have type ?
> type not
> boolean -> boolean
//means set of boolean to boolean
//we call this function type
bool function() {
}
//boolean is type of return value not function type
f: Domain -> Co-domain
Domain -> Co-Domain
> not (not true)
will be
> not false
it chan-able if domain differ to co-domain
> not (not ( not ( not false)))
but long function chain would be leadious to write, espeacially the "()"
- Unary function
function with one arguments
> true || false
> false
is it an operator ? No
- 4 kinds of function notation
- Prefix
- Infix
- Postfix
- Uniquly specific
"programming languages" can express mathematical function into formal form
e.g. double sin(double a, double b)
to prove it's' function, we can check type
- Curries function
"Every function only takes one arguement" revisit function from high school
this is only valid function form
f: Domain -> Codomain
ง่ายๆคือ Domain หรือ Codomain contain มากกว่า 1 function เช่น
int [5, 7, 11, 17]
char [a]
int x char [5a 7a 11a 17a]
this is tuple
//Domain can contain int x char (tuple)
> type (True, 'a')
> (True, 'a') :: Bool -> Char
เราเรียกว่า Cartersian product/ simply product
พอกลับมาดู function ที่เราเขียนในโค้ด
เช่น
login("username", "password")
("username", "password") มันก็คือ tuple ตัวนึง
แต่ถ้ามันอ่าน Tuple ไม่ได้ ทำไง
Example
ต้องเป็น Curry
add: aInt -> bInt -> cInt
มันก็คือ
aInt -> bInt -> cInt
ยุบรวม
add': aInt -> (bInt -> cInt)
> type add
> add :: int -> int -> int
> type add 5
> add 5 :: int -> int
> add 5 7
// มันคือ function add 5 ที่รับ argument 7
// (add 5) 7
> 12
> type filter
> filter :: (char -> bool) -> string -> string
OOP in functional perspective
> void doWork() {...
Reason this . . .
No, We can't
these are not showed in doWork()
- type
- value
- name
void -> void is not a functions
OOP (Alan kay definition) should have fixed above probelm
"System of biological cells, communicateing with chemical substance"
biological cells become object chemical substance become message
and so, object will response the message with its methods
ตัวอย่างที่ใกล้เคียงสุดคือ http request ไปหา internal server แต่ไม่ใช่ระดับของ OOP มันเป็นระดับ architecture
dog.bark()
มีกี่ arguement ?
one
in OOP language -> object.method(arg) which equivalent to method(object, arg)
ดังนั้น [1,2,3,4].filter(isEven) ก็คือ
> filter([1,2,3,4], isEven)
> filter([int], [int -> bool])
which call Higher-order function
meme
ซัก :: ผ้าใส่แล้ว -> ผักซักแล้ว
ตาก :: ผ้าซักแล้ว -> ผ้าแห้ง
รีด :: ผ้าแห้ง -> ผ้าเรียบ
เก็บ :: ผ้าเรียบ -> ผ้าในตู้
"ผ้ากองนี้.ซัก().ตาก().รีด().เก็บ() ด้วยนะคะ" = map(เก็บ.รีด.ตาก.ซัก)[ผ้ากองนี้]
Recap curried function
- All functions take one arguement and can be transfom from Cartersian
- Basically function constructor
- Partially apply exist function
- Applied argrument will be cloesed argument inside function frozen from any change
We call this "Closure"
Let create a function
catById: catId -> Cat
> List[catId]domain -> List[cat] codomain
start with db connector
> getCatFormDB :: DB -> catID -> Cat
> catById = getCatFormDB(myDB)
> type catById
> catById :: catId -> cat
what about API
> getCatFormAPI :: API -> catID -> Cat
> catById = getCatFormAPI(request)
> type catById
> catById :: catId -> cat
generalize this
> catById(DB, 17)
> catById(API, 18)
> catById(Mock, 19)
> catById :: (datasource -> id) -> cat
- Generic function
domain restriction
example
> type filter
> filter :: (a->bool)-> a -> a
> type filter isDigit
//isDigit :: char-> bool
> filter :: (char) -> char
map
mini quiz
> aaabbc => 3a2b1c
> map(count, char) :: (count->char) -> char
> aaa => '3a'
> 'A':(show 3)
> "A3"
> reverse $ 'A':(show 3)
> "3A"
> reverse $ head 'AAA':(show (length "AAA"))
> compressOne $ = reverse $ head 'AAA':(show (length "AAA"))
> "3A"
what if "AAABBCCAA"
> type group
> group :: Eq a => [a] -> [[a]]
> "AAABBCCAA"
> group it
> ["AAA", "BB", "CC", "AA"]
> map compressOne it
> ["3A", "2B", "2C", "2A"]
> concat it
> "3A2B2C2A"
- List comprehension
set comprehension
A = {a | a ∈ N}
list comprehension
A = [a | a <- N]
- Recursive
break it down
you will see the same probelm
Key to solve Recursion: find the way to solve (n-1) -> (n)
"if function can solve sub probelm it also can solve super probelm"
zip
** Popular recursion probelm**
- prime number
2 3 4 5 6 7 8 9 10 11 ... 100
start with 2 if member of list can be divided with current number we pop it out
3/2 = 1 do nothing
4/2 = 0 pop 4
and then continue to start with 3 and so on ...
- permutation
abc -> abc acb bac bca cab cba
start with small probelm ab -> ba
abc -> a[bc] a[cb] permute bc with a and so on ...
permute :: (Eq a) -> [a] -> [[a]]
permute [] = [[]]
permute xs = [x:ys | x <- xs, ys <- permute (delete x xs)]
- tower of hanoi
hanoi :: Int -> [(Int, Int)]
hanoi n = hanoi' n 1 2 3
hanoi' 0 _ _ _ =[]
hanoi' n beg tmp dest = tops_to_tmp