String name
int age
double weight
String upcase(String)
int fac(int)
fac(0) = 1
fac(1) = 1
fac(2) = 2
fac(3) = 6
...
name: String
age: ing
weight: double
fac: int -> int
upcase: String -> String
A // Set
A ⊹ A : A // Addition
zero: A
a ⊹ b = (a + b) % 12
zero = 12
Monoid laws
(a ⊹ b) ⊹ c = a ⊹ (b ⊹ c)
zero ⊹ a = a ⊹ zero = a
Monoid examples
Monoid ~ composition
f: A -> A
g: A -> A
c : A -> A
c x = f (g x)
// c x = g(f x)
∘: (A -> A) -> (A -> A) -> (A -> A)
c = g ∘ f
c x = g (f x)
// Think Unix pipes
> :t upcase
upcase :: String -> String
> :t stripSpace
stripSpace :: String -> String
> let upcaseStripped = upcase . stripSpace
> upcaseStripped "hello world"
"HELLOWORLD"
> :t upcaseStripped
upcaseStripped :: String -> String
(A -> A) ∘ (A -> A) == (A -> A)
zero = id
id: A -> A
id x = x
f: A -> B
g: B -> C
c = g ∘ f
(B -> C) ∘ (A -> B) -> (A -> C)
> :t digitToInt
digitToInt :: Char -> Int
> :t head
head :: String -> Char -- Not it's real type
> let firstDigitToInt = digitToInt . head
> :t firstDigitToInt
firstDigitToInt :: String -> Int
> firstDigitToInt "1sadfsdaf"
1
Functions have monoids
Objects don't
ListSetFutureMaybeParser// Tons of other
f: A -> M A
g: A -> M A
// They don't compose
// c = g ∘ f
> :t splitByComma
splitByComma :: String -> [String]
> :t words
words :: String -> [String]
> let coolSplit = splitByComma . words
...
Expected type: String -> String
Actual type: String -> [String]
...
f: A -> M A g: A -> M A
c = f >=> g c : A -> M A // f gets called first, unlike (f . g)
> let splitBySpaceAndComma =
splitByComma >=> words
> :t splitBySpaceAndComma
splitBySpaceAndComma :: String -> [String]
> splitBySpaceAndComma "h,el,lo w,orl,d,"
["h","el","lo","w","orl","d"]
zero = return // Awful name!!!
zero = wrap // is it any better?
wrap: A -> M A
M -- container type (>=>): (A -> M A) -> (A -> M A)
-> (A -> M A) wrap: A -> M A
(f >=> g) >=> h === f >=> (g >=> h)
f >=> wrap === wrap >=> f === f
f: A -> M B g: B -> M C h = f >=> g h: A -> M C
val: M B
newVal = val >>= g
newVal: M C
(A -> M B) >=> (B -> M C) === A -> M C
M B >>= (B -> M C) === M C
x >>= f = (\_ -> x) >=> f $ ()
g >=> f = \x -> (g x) >>= g
> ["123","456"] >>= stringToInts
[1,2,3,4,5,6]
> :t stringToInts
stringToInts :: String -> [Int]
main = do
print "What is your name?"
name <- getLine
print ("Hello " ++ name ++ "!")
val purchase = for {
usd <- usdQuote
chf <- chfQuote
if isProfitable(usd, chf)
} yield connection.buy(amount, chf)
var res = from n in TryReadInt()
from m in TryReadInt()
select n + m;