SlideShare a Scribd company logo
1 of 86
Haskell 進階運算元件介紹
snowmantw @gmail.com
20120714
Functional Programming SIG
http://goo.gl/VInp9
MS PowerPoint 2007 PDF
http://goo.gl/TiiMY
本著作係採用創用 CC 姓名標示-非商業性-相同方式分享 2.0 台灣 授權條款授權.
Snowmantw
: Vimmer
/ Linux User
λ Haskell Learner
G Self-Studier
$ Javascript Developer
@ snowmantw at gmail.com
✍ Master's Degree Student
→ Dept. of Computer Science, NCCU snowmantw.github.com
C C+
+
PHP JS Haskell Java
Outline
• YAMI – Yet Another Monad Introduction
• Monad vs. Arrow
• Other Type Classes in Typeclassopedia
• Beyond Haskell – Patterns in Functional Programming
Yet Another Monad
Introduction
What is a Monad ?
What is a Monad ?
getLine :: IO String
putStrLn:: String -> IO ()
(>>) :: Monad m => m a -> m b -> m b
(>>=) :: Monad m => m a -> (a -> m b) -> m b
main = getLine
>>=  name -> putStrLn “Hello :”++name
>> putStrLn “World !”
這大概是為何大部分的 Haskell “Hello World” 都是
從費式級數開始講起…
Tears of a Haskell Newbie
Monad,單元(unit)的拉丁語,來自範疇
論的一種技術,其已經被採用作為處理在功
能性程序設計語言中…
In functional programming, a monad is a
structure that represents computations.
In category theory, a branch of mathematics, a monad,
Kleisli triple, or triple is an (endo-)functor, together with two
natural transformations.
A monad is an "amplifier" of types that obeys certain rules
and which has certain operations provided.
單子(monad,也譯單體)是函數式編程中的一種抽象
數據類型,其特別之處在於,它是用來表示計算而不是
數據的。在以函數式風格編寫的程序中,單子可以用來
組織包含有序操作的過程,或者用來定義任意的控制流
Monad,單元(unit)的拉丁語,來自範疇
論的一種技術,其已經被採用作為處理在功
能性程序設計語言中…
In functional programming, a monad is a
structure that represents computations.
In category theory, a branch of mathematics, a monad,
Kleisli triple, or triple is an (endo-)functor, together with two
natural transformations.
A monad is an "amplifier" of types that obeys certain rules
and which has certain operations provided.
單子(monad,也譯單體)是函數式編程中的一種抽象
數據類型,其特別之處在於,它是用來表示計算而不是
數據的。在以函數式風格編寫的程序中,單子可以用來
組織包含有序操作的過程,或者用來定義任意的控制流
Tears of a Haskell Newbie
Monad everywhere and not a piece
to understand…
Tears of a Haskell Newbie
There is no royal road to Haskell.
—Euclid*
Tears of a Haskell Newbie
*from “typeclassopedia”
“Typeclassopedia” in
Monad.Reader # 13
http://www.haskell.org/wikiupload/8/85/TMR-Issue13.pdf
Begin from Pure Functions
Begin from Pure Functions
fn:: a -> b
gn:: b -> c
gfn:: a -> c
gfn a = gn ( fn ( a ) )
We can use “definition” to make new functions.
But that’s not so “functional”.
Composition in Functional Language
(.):: (b -> c)->(a -> b)-> a -> c
fngn 。 gfn
Functional Language ( at least, in Haskell ) :
Compose Everything !
Composition in Functional Language
大的函式可由許多小函式合成而成
zn . yn . xn …. cn . bn . an
Problem: Data in a Nutshell
Problem: Data in a Nutshell
(+4).(+5):: Int -> Int
Int: 4 Int: 12
((+4).(+5)) 4 == 12
+4 +5
When Int: 4 ~> [Int: 4]
Problem: Data in a Nutshell
(+4).(+5):: Int -> Int
[Int]: [4]
((+4).(+5)) [4] -- Error !
+4 +5 X
函式無法處理帶 context 性質的值
每種 context 都有其意義
Problem: Data in a Nutshell
• Maybe a:: 代表不確定性運算
• Either e a:: 代表有可能會例外的運算
• [a]:: 代表不確定性運算 -- 可能性更多
• IO a:: 代表會對 RealWorld 做出影響
常見的 Context
使用 context 觀點會比容器觀點更加適切
Problem: Data in a Nutshell
(+4).(+5):: Int -> Int
Solution #1
plus45 = (+4).(+5)
plus45Special [ x ] = plus45 x -- use pattern matching
為該函式定義一特別的 “unwrap” 版本
有多少 context 就要定義多少版本…
Problem: Data in a Nutshell
(+4).(+5):: Int -> Int
Solution #1
plus45 = (+4).(+5)
plus45Special [ x ] = plus45 x
plus45SpMaybe (Just x) = plus45 x
plus45SpIO (IO x) = plus45 x
……..
Problem: Data in a Nutshell
(+4).(+5):: Int -> Int
Solution #1
plus45 = (+4).(+5)
plus45Special [ x ] = plus45 x
plus45SpMaybe (Just x) = plus45 x
plus45SpIO (IO x) = plus45 x
……..
pure
with context
實際上分為處理 context 與運算兩部分
Problem: Data in a Nutshell
(+4).(+5):: Int -> Int
Solution #2
每種 context 定義出自己的包裹函式
代為處理包裹與「解包」的問題
(+4).(+5)
[ 4 ] 4 12 [ 12 ]
fmap:: (a->b)->f a -> f b
Problem: Data in a Nutshell
(+4).(+5):: Int -> Int
Solution #2
重用:不用更改原本的運算函式
解耦:將運算與 context 處理分開
靈活:組合而非定義生成新的運算方式
fmap:: (a->b)->f a -> f b
Type Class: Functor
Abstract Structure with fmap
Type Class: Functor
from Typeclassopedia, Haskell Wiki
http://www.haskell.org/haskellwiki/Typeclassopedia
Type Class: Functor
class Functor f where
fmap:: ( a -> b ) -> f a -> f b
帶有 fmap 函式定義的 context
fmap 的定義要懂得包裹與解包
fmap = map -- Functor [ ]
fmap _ Nothing = Nothing
fmap f ( Just a ) = Just ( f a ) -- Functor Maybe
fmap f x = x >>= ( return . f) -- * Functor IO
From Functor to Monad
Functor 定義了如何讓普通函式「轉成」
特定 context 下的函式
fmap:: (a->b)->f a -> f b
(.):: (b -> c)->(a -> b)-> a -> c
Compose 定義了如何串出更大的運算
結合兩者可做出更大的 context 運算
From Functor to Monad
從一個普通值帶到某 context 運算
4 → [ 4 ] [ 21 ]
(+4).(+5
)
(+4).(+5
)
(+4).(+5
)
值一但被包裹理論上就不會被解包(特例)
這整條運算:a -> m a ( m :: Context )
可稱為 action ( from IO Monad )
fmap AND (.)
From Functor to Monad
還缺少把值變成 context 值的抽象函式
4 → [ 4 ] [ 21 ]
(+4).(+5
)
(+4).(+5
)
(+4).(+5
)
return:: a -> m a
* 這個名字很不幸與許多程式語言的保留關鍵字相同,然而應該
注意其意義幾乎完全不同!
* return 幾乎就等於 Data Constructor 了,例如 Just a
[ a ] -> [ c ]
From Functor to Monad
不僅僅是 [ ] :抽象概念互通
4 → [ 4 ] [ 31 ]
(+4).(+5
)
(+4).(+5
)
(+4).(+5
)
4 → Maybe 4 Maybe 31
4 → IO 4 IO 31
m a -> m c
都是從一個值 -> 運算後且帶 context 的值
From Functor to Monad
我們用 fmap (.) 與 return 建出單個 context 運算
(+4).(+5
)
(+4).(+5
)
(+4).(+5
)
理論上這樣的運算,應該要像函式可以組合
。( ) ( )
From Functor to Monad
阻礙:型別不通
。( ) ( )
[ c ] c -> [ d ]
(>>=):: m a -> (a -> m b ) -> m b
這個奇怪的 bind 運算子幫我們搭了橋
From Functor to Monad
有了 bind 運算子我們可以任意組合同型 context 運算
。( ) ( )
[ c ] c -> [ d ]
(>>=):: m a -> (a -> m b ) -> m b
效果:把前一個 context 值私下解包後,傳給下個運算
From Functor to Monad
。( ) ( )
[ c ] c -> [ d ]
(>>=):: m a -> (a -> m b ) -> m b
find even [1,2] >>= return . ((!!) [1,2,4]) -- Maybe
[‘3’,’4’,’5’]>>= digitToInt >>= return . even -- [ ]
getLine >>= putStr.((++) “Hi, user [”) >> putStrLn “] !” -- IO
From Functor to Monad
(>>=):: m a -> (a -> m b ) -> m b
find even [1,2] >>= return . ((!!) [1,2,4])
找到為偶數的值:Just 2 找到 index#2 的值,並包裝之
find:: (a->Bool)->[a]->Maybe a
even:: Integral a => a -> Bool
(!!):: [a]->Int->a ; (!!) [1,2,4] :: Int -> a
return:: a -> m a ; return . ( (!!) [1,2,4] ) :: Int -> m b
return 夠抽象,所以可以視其正在
哪個 context 中用不同的 instance
From Functor to Monad
(>>=):: m a -> (a -> m b ) -> m b
[‘3’,’4’,’5’]>>= return . digitToInt >>= return . even
( 為了方便示範 ) 各字元轉換成整數 各奇偶數轉成 Bool
getLine >>= putStr.((++) “Hi, user [”) >> putStrLn “] !”
從 IO 取得一行 組合傳入字串並從 IO 輸出 不管前面結果而印出
抽象:注意每個 context 對 bind 詮釋都不同,但用法都相同
bind 表現的效果之一是不用管傳值,只要專注把運算組合即可
(>>):: m a -> m b -> m b -- 不管前面結果,自己執行出 m b
From Functor to Monad
Functor -- fn -> context fn
fmap:: (a -> b) -> f a -> f b
Monad -- computation under m
return:: a -> m a
(>>=):: m a-> (a->m b)-> m b
理論上所有 Monad 都要同時也是 Functor ,但並非 Haskell 現狀
Monad Laws
Left identity: return a >>= f ≡ f a
Right identity: m >>= return ≡ m
Associativity: (m >>= f) >>= g ≡ m >>= (x -> f x >>= g)
主要是確保組合小運算成大運算的過程中,不會因組合先後不同而出錯
http://www.haskell.org/haskellwiki/Monad_Laws
Monad 與 Pure
• Pure: 函式無副作用 → 輸入只能根據輸出唯一決定
openFile:: FilePath -> IOMode -> IO Handle
In what sense is the IO monad pure ?
id 3 == 3
id 3 == 3
id 3 == 3
id 3 = 3
id 3 = 3
id 3 = 4
Hidden State !
Monad 與 Pure: IO Monad
openFile:: FilePath -> IOMode -> IO Handle
In what sense is the IO monad pure ?
modify = openFile "/tmp/test" WriteMode >>=
(h -> hPutStrLn h “watch#2: Hello World !" >> hClose h)
watch = openFile "/tmp/test" ReadMode >>=
(h-> hGetLine h >>= putStrLn >> hClose h)
f = watch >> modify >> watch
----
watch#1: Original Content
watch#2: Hello World !
兩次 watch 呼叫參數都一樣
,但是輸出卻不同!
Monad 與 Pure: IO Monad
fn:: a -> a’ ; gn:: a’ -> a’’ ; hn:: a’’ -> a’’’
hgfn:: a ~> a’ ~> a’’~> a’’’ :: a -> a’’’
Pure 函式本身不能存有狀態,但是狀態可以
用傳遞的方式給予
Haskell ( GHC ) 底層偷偷在 IO Monad 中間
加入傳遞 #RealWorld 的動作
→ modify:: #RealWorld -> #RealWorld’
→ watch:: #RealWorld
“Problem ?”
Monad 與 Pure: IO Monad
watch >> modify >> watch -- 將變成類似於(非實際實做!)
watch #RealWorld ~> modify #RealWorld ~> watch #RealWorld ’
Pure 函式本身不能存有狀態,但是狀態可以
用傳遞的方式給予
所以兩次 watch 的「參數」已經不同,故表面
上看來具有副作用的 watch 實際上也是 Pure
→ 不過我們可解釋 Pure 為:有副作用者,如檔
案內容這種值,不能直接「污染」Pure 函式
→ 也就是 Pure Function 與 Action 不能混用
Monad 與 Pure: IO Monad
[a] -> a --:: head, tail, foldl, maximum, minimum …
Maybe a -> a --:: fromJust, fromMaybe defaultValue …
----
IO a -> a --:: ( NO SUCH FUNCTION !! )
Haskell 利用 context 概念永久包住帶
「副作用」的 IO 值: a -> IO a -> …… IO z
一般 Monad 多少都有 unwrap function,也就
是在該 context 內部可以是 Impure 的處理。但
離開 context 的值必須只能是 Pure : m a -> a
→ 一入 IO ,永為 IO :因沒有 unwrapper,
所有要處理 IO 者都必須嵌入該 context 內
Monad 小結
Pure Function
。
with Context
value wrapper :: a -> m a
>>=( ) ( )
[ c ] c -> [ d ]
Monad 小結
• Monad 就是符合規則且實作 return 、>>= 等的抽
象結構 ( Type Class)
• 這個抽象結構允許透過組合,產生出新的 action
• action: 允許將純值包裹進某個 context ,並進行
一連串變換的運算
• Monad 提供工具將帶 context 運算組合再一起。
包括帶真正 Side-Effect 的 IO 也可以此達到 pure
補充:In what sense is the IO monad pure ?
http://stackoverflow.com/questions/4063778/in-what-sense-is-the-io-
monad-pure
Monad vs. Arrow
Arrow 介紹
from Typeclassopedia, Haskell Wiki
http://www.haskell.org/haskellwiki/Typeclassopedia
How to make an Arrow
This is a normal function…
fn:: a -> b
… and this is an Arrow
fn::(->) a b
Just like any other data type
Maybe[ ] Int
Book Id Price
- 這個 Arrow -
接收:a
給出:b
Tip: 可以表達運
算與可以執行運
算是兩件事
From Monad to Arrow
getLine :: IO String
putStr, putStrLn :: IO ()
main :: IO ()
main = getLine >>= putStr.((++) “Hi, user [”) >> putStrLn “] !”
Monad 型別意義:m a 代表「這個 monad 會產生 a 型別的值
」因此,Monad 封裝出完整、不依賴外部的 operation ( 所以叫「單子」 )
持有一個 Monad a: 持有一個「值」 ( 內部一連串運算得出)
Arrow 型別意義:a b c 代表「這個 arrow 接收 b 傳出 c」
因此,Arrow 封裝的是一個 transformation ( 有接受端)
持有一個 Arrow b c: 持有一個「會從 b 到 c 的變換」
→ 若以 `b` Apply 此 Arrow,就等於 ( M b ) ( Arrow 不一定都可 Apply)
Monad 把資料連同運算封裝,模糊了 object 與 transformation
Arrow 只封裝運算,並提供了「針對運算的運算」
From Monad to Arrow
一如 Monad 有抽象的 return 代替實際的建構式,Arrow 中
arr:: Arrow a => (b -> c) -> a b c
如何將一個普通的函式封成其 context 下一個 transformation
實做視其 context (運算種類)不同而異
幾個常見的 Arrow
ordinary functions : (->) b c
Kleisli arrows : Monad m => (->) b m c
stream transformers : (-> ) (Stream b) (Stream c)
return:: a -> m a
對比於 Monad 的 return function
將值,而非運算轉換
Arrows: A General Interface to Computation
如果我們有一堆的 Arrow
a b c
我們可以針對他們進行一些組合動作
a b d a c d
a b c >>> a c d :: a b d
(c -> d)。(b -> c):: (->) b d
ordinary functions: 就是普通的函式合成
Kleisli: 用 g b >>= f 去作組合
Arrows: A General Interface to Computation
基本的 Arrow 函式
http://www.soi.city.ac.uk/~ross/papers/fop.html
Arrows: A General Interface to Computation
使用 Arrow 組合出整個程式
http://www.soi.city.ac.uk/~ross/papers/fop.html
使用 Arrow ,整
個程式的邏輯單
元就可以像電路
一樣被組合
Arrow vs. Monad
Monad 的「中間環節」可脫離型別掌握
m a >>= (a -> m b) >>= ( b -> m c )
並無法確認 (a -> m b) 這個 Action 處理中保持在同樣的 context 裡
a m b
n c ?
只認頭與尾
無法控管中間
Arrow vs. Monad
Arrow 的組合函式會確保 context 相同
a b c >>> a c d >>> a d e >>> a e f
a c d 只能再次由 >>> 構成:
a c z >>> a z y >>> a y x >>> a x d
a z y 只能再次由 >>> 構成:
a z w >>> a w v >>> a v u >>> a u y
Arrow vs. Monad
Arrow 的組合函式會確保 context 相同
a b c >>> a c d >>> a d e >>> a e f
a c z >>> a z y >>> a y x >>> a x d
a z w >>> a w v >>> a v u >>> a u y
組合中所有子 Arrow 都在 a 這個 context 內
Arrow vs. Monad
Arrow 的組合函式會確保 context 相同
Every time we sequence two monadic
computations,we have an opportunity to run
arbitrary Haskell code in between them.
Monad
But in the case of arrows, in contrast, the second
argument of (>>>) is just an arrow…
Arrow
from “Programming with Arrows”; John Hughes
Other Type Classes in
Typeclassopedia
其他運算元件介紹
from Typeclassopedia, Haskell Wiki
http://www.haskell.org/haskellwiki/Typeclassopedia
Applicative
Applicative
Functor : 可以讓一個函式被「context 化」
(+4).(+5)
[ 4 ] 4 12 [ 12 ]
fmap:: (a->b)->f a -> f b
但是僅限於只有一個參數的函式
Applicative
fmap 的函式如何給予一個以上的參數?
(+):: Int -> (Int -> Int)
fmap (+) :: f a -> f (Int -> Int)
fn = fmap (+) -- 假設以 [] 為 context
fn:: [ ] Integer -> [ Integer -> Integer ]
fn [4] :: [Integer -> Integer] -- 無法進一步 apply [5] 給 (+)
fn [4] [5] -- Error ! ( fn [4] 「滿了」,已經無法再給參數)
Applicative
Applicative 提供了如何 apply 的解決方式
pure :: a -> f a
(<*>) :: f (a -> b) -> f a -> f b
fn = fmap (+) -- 假設以 [] 為 context
fn:: [ ] Integer -> [ Integer -> Integer ]
fn [4] :: [Integer -> Integer] -- 無法進一步 apply [5] 給 (+)
(<*>) (fn [4]) :: [ ] Integer -> [ ] Integer -- 可以給予參數了!
fmap (+) [4] <*> [5] -- [9]
將被放在 context 內的變換轉出來,變成可給予的參數
Applicative
根據 Applicative Laws ,fmap 可換成
fmap g x = pure g <*> x
fn :: a -> b -> c -> d -> e -> f … -> z -- 很多參數
fn a b c d e … -- 一般的 function apply
pure fn <*> f a <*> f b <*> f c <*> f d <*> f e … -- 就如同往常的 function apply
fmap fn f a <*> f b <*> f c <*> f d <*> f e … -- fmap 會幫忙帶第一個參數
因此一般來說 Applicate 使用起來會長得像是
給定第一個參數
Monoid
Monoid
Monoid: 可以作「加法」的類別
mzero :: m a -- [ ] ,Nothing
mplus :: m a -> m a -> m a -- (++)
Nothing `mplus` Nothing = Nothing -- 0 solutions + 0 solutions = 0 solutions
Just x `mplus` Nothing = Just x -- 1 solution + 0 solutions = 1 solution
Nothing `mplus` Just x = Just x -- 0 solutions + 1 solution = 1 solution
Just x `mplus` Just y = Just x -- 1 solution + 1 solution = 2 solutions,
Maybe 的 mplus 定義有點繁瑣
http://stackoverflow.com/questions/4504489/monadplus-definition-for-haskell-io
* 「為何 IO 不是 MonadPlus ? 」->
‘mzero’ would necessarily represent an IO computation that never returns.
Foldable
Foldable
Foldable :可以從一個結構 -> 「加」成一個值
fold :: Monoid m => t m -> m
Prelude> foldr (x y -> concat ["(",x,"+",y,")"]) "0" (map show [1..13])
"(1+(2+(3+(4+(5+(6+(7+(8+(9+(10+(11+(12+(13+0)))))))))))))"
Prelude> foldl (x y -> concat ["(",x,"+",y,")"]) "0" (map show [1..13])
"(((((((((((((0+1)+2)+3)+4)+5)+6)+7)+8)+9)+10)+11)+12)+13)"
Traversable
Traversable
Foldable 會改變最終結果的結構,與原本不同
Traversable 可以給出「保持結構的變化」
traverse :: Applicative f => (a -> f b) -> t a -> f (t b)
instance Traversable Tree where
traverse g Empty = pure Empty
traverse g (Leaf x) = Leaf <$> g x
traverse g (Node l x r) = Node <$> traverse g l
<*> g x
<*> traverse g r
如何把一個改變的函式 apply 到一個結構,及其子結構內?
A
B
C
traverse (+1)
A
+
1
B
+
1
C
+
1
~>
Comonad
Comonad
前面說過一般而言 Monad 是「包裹」用
return :: a -> f a
return a ~> f a ~> f b ~> f c
具有反向「解包」者稱為 Comonad
extract :: f a -> a
可以從一個 Monad 中解出 pure 的值
Comonad
除此之外還有「反向的」bind ( >>= )
extend :: ( w a -> b) -> w a -> w b
(>>=):: m a -> ( a -> m b ) -> m b
More on…
http://www.haskell.org/haskellwiki/Typeclassopedia
Beyond Haskell
Patterns in Functional Programming
Beyond Haskell
• Type Class, (.), Monad, Foldable, Traversable…
• 這些概念並非只存在於 Haskell 這個語言中
• 甚至並非僅存在於 Functional Programming 的世界中
First-Class Function
class Add {
int _a;
public:
Add(int a): _a(a){}
int operator()(int b){
return _a + b;
}
};
Add a = Add(3); a(4)
a = (+) 3
a 4
Beyond Haskell
• Type Class, (.), Monad, Foldable, Traversable…
• 這些概念並非只存在於 Haskell 這個語言中
• 甚至並非僅存在於 Functional Programming 的世界中
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
public interface Eq<A>{
public Boolean eq( A a );
public Boolean neq( A a );
}
instance Eq Integer where
x == y = x `integerEq` y
public class Integer implements Eq
{
//…
}
Type Class
Beyond Haskell
• Type Class, (.), Monad, Foldable, Traversable…
• 這些概念並非只存在於 Haskell 這個語言中
• 甚至並非僅存在於 Functional Programming 的世界中
hn = fn . gn
Composition
Command + Compoisite pattern
Beyond Haskell
• Type Class, (.), Monad, Foldable, Traversable…
• 這些概念並非只存在於 Haskell 這個語言中
• 甚至並非僅存在於 Functional Programming 的世界中
Monad
main = getLine >>=
putStr.((++) “Hi, user [”) >>
putStrLn “] !”
$(dom).find(‘.subdom’)
.hide()
.append(some_dom)
.addClass(‘show’);
.fadeIn()
http://importantshock.wordpress.com/2009/01/18/jquery-is-a-monad/
“jQuery is a monad”
…OR any fluent interface +
context computation
http://en.wikipedia.org/wiki/Fluent_interface
Beyond Haskell
• Type Class, (.), Monad, Foldable, Traversable…
• 這些概念並非只存在於 Haskell 這個語言中
• 甚至並非僅存在於 Functional Programming 的世界中
Monad
main = getLine >>=
putStr.((++) “Hi, user [”) >>
putStrLn “] !”
“Monad in Scala”
“Monad in F#”
“Monad in Java”
(some terrible codes )
“Monad in C++”
(with C++11 lambda)
“Monad in Ruby”
(lambda, again)
“Monad in Python”
(「with-nice-syntax」)
Beyond Haskell
• 反過來說,很多所謂 Design Pattern 都是為了 OOP 的概
念或語言而設計的
• 有些 pattern 到了 Haskell 或 FP 就不見得需要,或變得
是語言自然的一部分
Pattern in Haskell
Strategy First class functions and lambdas
Factory Method
Template Method
Higher-order functions
Abstract Factory
Builder
Bridge
Type classes and smart constructors
Adapter
Decorator
Chain of Responsibility.
Composition and lifting ( like fmap )
http://blog.ezyang.com/2010/05/design-patterns-in-haskel/
Beyond Haskell
• 反過來說,很多所謂 Design Pattern 都是為了 OOP 的概
念或語言而設計的
• 有些 pattern 到了 Haskell 或 FP 就不見得需要,或變得
是語言自然的一部分
Pattern in Haskell
Visitor Equational functions; Foldable.
Interpreter
Functions; DSEL; ADT provides a nice way to
construct the AST of your language.
Command Monads ( computation )
Iterator Lazy lists
Prototype Immutability
Flyweight Memoising and constant applicative forms
(CAF)
http://blog.ezyang.com/2010/05/design-patterns-in-haskel/
Beyond Haskell
• 反過來說,很多所謂 Design Pattern 都是為了 OOP 的概
念或語言而設計的
• 有些 pattern 到了 Haskell 或 FP 就不見得需要,或變得
是語言自然的一部分
Pattern in Haskell
State
Memento
Unnecessary ( LOL ); Undo Monad
Singleton Unnecessary ( again )
Facade Functions
Observer STM, Mvar, Channel
functional reactive programming
Proxy Wrapped data types, laziness and garbage
collector
Mediator Monad stack
Thanks for your attention.

More Related Content

What's hot

竞赛中C++语言拾遗
竞赛中C++语言拾遗竞赛中C++语言拾遗
竞赛中C++语言拾遗乐群 陈
 
Return to dlresolve
Return to dlresolveReturn to dlresolve
Return to dlresolveAngel Boy
 
Python学习笔记
Python学习笔记Python学习笔记
Python学习笔记Lingfei Kong
 
Lua 语言介绍
Lua 语言介绍Lua 语言介绍
Lua 语言介绍gowell
 
C python 原始碼解析 投影片
C python 原始碼解析 投影片C python 原始碼解析 投影片
C python 原始碼解析 投影片kao kuo-tung
 
Intro to C++ Basic
Intro to C++ BasicIntro to C++ Basic
Intro to C++ BasicShih Chi Lin
 
C語言 第4章 基本輸出與輸入功能
C語言 第4章 基本輸出與輸入功能C語言 第4章 基本輸出與輸入功能
C語言 第4章 基本輸出與輸入功能shademoon
 
Python速成指南
Python速成指南Python速成指南
Python速成指南March Liu
 
10 檔案說明與處理
10 檔案說明與處理10 檔案說明與處理
10 檔案說明與處理shademoon
 
ES5 introduction
ES5 introductionES5 introduction
ES5 introductionotakustay
 

What's hot (20)

竞赛中C++语言拾遗
竞赛中C++语言拾遗竞赛中C++语言拾遗
竞赛中C++语言拾遗
 
Ch10 範例
Ch10 範例Ch10 範例
Ch10 範例
 
Return to dlresolve
Return to dlresolveReturn to dlresolve
Return to dlresolve
 
Ch10 教學
Ch10 教學Ch10 教學
Ch10 教學
 
Python学习笔记
Python学习笔记Python学习笔记
Python学习笔记
 
Execution
ExecutionExecution
Execution
 
Ch8 教學
Ch8 教學Ch8 教學
Ch8 教學
 
Ch7 教學
Ch7 教學Ch7 教學
Ch7 教學
 
Ch4 教學
Ch4 教學Ch4 教學
Ch4 教學
 
Lua 语言介绍
Lua 语言介绍Lua 语言介绍
Lua 语言介绍
 
C python 原始碼解析 投影片
C python 原始碼解析 投影片C python 原始碼解析 投影片
C python 原始碼解析 投影片
 
Intro to C++ Basic
Intro to C++ BasicIntro to C++ Basic
Intro to C++ Basic
 
C語言 第4章 基本輸出與輸入功能
C語言 第4章 基本輸出與輸入功能C語言 第4章 基本輸出與輸入功能
C語言 第4章 基本輸出與輸入功能
 
Python速成指南
Python速成指南Python速成指南
Python速成指南
 
Ch5 教學
Ch5 教學Ch5 教學
Ch5 教學
 
Appendix B 教學
Appendix B 教學Appendix B 教學
Appendix B 教學
 
Hi Haskell
Hi HaskellHi Haskell
Hi Haskell
 
10 檔案說明與處理
10 檔案說明與處理10 檔案說明與處理
10 檔案說明與處理
 
ES5 introduction
ES5 introductionES5 introduction
ES5 introduction
 
Fp
FpFp
Fp
 

Similar to Introduction to Basic Haskell Components (In Chinese)

论 Python 与设计模式。
论 Python 与设计模式。论 Python 与设计模式。
论 Python 与设计模式。勇浩 赖
 
C++工程实践
C++工程实践C++工程实践
C++工程实践Shuo Chen
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)jeffz
 
Groovy Introduction for Java Programmer
Groovy Introduction for Java ProgrammerGroovy Introduction for Java Programmer
Groovy Introduction for Java ProgrammerLi Ding
 
走马观花— Haskell Web 开发
走马观花— Haskell Web 开发走马观花— Haskell Web 开发
走马观花— Haskell Web 开发Gump Law
 
Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍dennis zhuang
 
在開始工作以前,我以為我會寫扣。
在開始工作以前,我以為我會寫扣。在開始工作以前,我以為我會寫扣。
在開始工作以前,我以為我會寫扣。Chih-Hsuan Kuo
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计yiming he
 
程式人雜誌 -- 2015 年5月號
程式人雜誌 -- 2015 年5月號程式人雜誌 -- 2015 年5月號
程式人雜誌 -- 2015 年5月號鍾誠 陳鍾誠
 
程式人雜誌 2015年五月
程式人雜誌 2015年五月程式人雜誌 2015年五月
程式人雜誌 2015年五月鍾誠 陳鍾誠
 
深入理解Andorid重难点
深入理解Andorid重难点深入理解Andorid重难点
深入理解Andorid重难点Bin Shao
 
Ptyhon 教學 003 函數
Ptyhon 教學 003 函數Ptyhon 教學 003 函數
Ptyhon 教學 003 函數信宏 陳
 
Js is js(程劭非) (1)
Js is js(程劭非) (1)Js is js(程劭非) (1)
Js is js(程劭非) (1)looneyren
 
Learning python in the motion picture industry by will zhou
Learning python in the motion picture industry   by will zhouLearning python in the motion picture industry   by will zhou
Learning python in the motion picture industry by will zhouWill Zhou
 

Similar to Introduction to Basic Haskell Components (In Chinese) (20)

论 Python 与设计模式。
论 Python 与设计模式。论 Python 与设计模式。
论 Python 与设计模式。
 
C++工程实践
C++工程实践C++工程实践
C++工程实践
 
The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)The Evolution of Async Programming (GZ TechParty C#)
The Evolution of Async Programming (GZ TechParty C#)
 
Groovy Introduction for Java Programmer
Groovy Introduction for Java ProgrammerGroovy Introduction for Java Programmer
Groovy Introduction for Java Programmer
 
nodeMCU IOT教學02 - Lua語言
nodeMCU IOT教學02 - Lua語言nodeMCU IOT教學02 - Lua語言
nodeMCU IOT教學02 - Lua語言
 
nodeMCU IOT教學02 - Lua語言
nodeMCU IOT教學02 - Lua語言nodeMCU IOT教學02 - Lua語言
nodeMCU IOT教學02 - Lua語言
 
走马观花— Haskell Web 开发
走马观花— Haskell Web 开发走马观花— Haskell Web 开发
走马观花— Haskell Web 开发
 
Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍
 
getPDF.aspx
getPDF.aspxgetPDF.aspx
getPDF.aspx
 
getPDF.aspx
getPDF.aspxgetPDF.aspx
getPDF.aspx
 
在開始工作以前,我以為我會寫扣。
在開始工作以前,我以為我會寫扣。在開始工作以前,我以為我會寫扣。
在開始工作以前,我以為我會寫扣。
 
Sym py edu
Sym py eduSym py edu
Sym py edu
 
Kissy editor开发与设计
Kissy editor开发与设计Kissy editor开发与设计
Kissy editor开发与设计
 
程式人雜誌 -- 2015 年5月號
程式人雜誌 -- 2015 年5月號程式人雜誌 -- 2015 年5月號
程式人雜誌 -- 2015 年5月號
 
程式人雜誌 2015年五月
程式人雜誌 2015年五月程式人雜誌 2015年五月
程式人雜誌 2015年五月
 
深入理解Andorid重难点
深入理解Andorid重难点深入理解Andorid重难点
深入理解Andorid重难点
 
Ptyhon 教學 003 函數
Ptyhon 教學 003 函數Ptyhon 教學 003 函數
Ptyhon 教學 003 函數
 
Js is js(程劭非) (1)
Js is js(程劭非) (1)Js is js(程劭非) (1)
Js is js(程劭非) (1)
 
Ch 8
Ch 8Ch 8
Ch 8
 
Learning python in the motion picture industry by will zhou
Learning python in the motion picture industry   by will zhouLearning python in the motion picture industry   by will zhou
Learning python in the motion picture industry by will zhou
 

More from ChengHui Weng

Rust + python: lessons learnt from building a toy filesystem
Rust + python: lessons learnt from building a toy filesystemRust + python: lessons learnt from building a toy filesystem
Rust + python: lessons learnt from building a toy filesystemChengHui Weng
 
12 Monkeys Inside JS Engine
12 Monkeys Inside JS Engine12 Monkeys Inside JS Engine
12 Monkeys Inside JS EngineChengHui Weng
 
Gatekeeper: API gateway
Gatekeeper: API gatewayGatekeeper: API gateway
Gatekeeper: API gatewayChengHui Weng
 
Catch a spider monkey
Catch a spider monkeyCatch a spider monkey
Catch a spider monkeyChengHui Weng
 
Even more java script best practices
Even more java script best practicesEven more java script best practices
Even more java script best practicesChengHui Weng
 
JavaScript Best Pratices
JavaScript Best PraticesJavaScript Best Pratices
JavaScript Best PraticesChengHui Weng
 
Yampa AFRP Introduction
Yampa AFRP IntroductionYampa AFRP Introduction
Yampa AFRP IntroductionChengHui Weng
 
JSDC 2014 - functional java script, why or why not
JSDC 2014 - functional java script, why or why notJSDC 2014 - functional java script, why or why not
JSDC 2014 - functional java script, why or why notChengHui Weng
 
Things about Functional JavaScript
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScriptChengHui Weng
 

More from ChengHui Weng (9)

Rust + python: lessons learnt from building a toy filesystem
Rust + python: lessons learnt from building a toy filesystemRust + python: lessons learnt from building a toy filesystem
Rust + python: lessons learnt from building a toy filesystem
 
12 Monkeys Inside JS Engine
12 Monkeys Inside JS Engine12 Monkeys Inside JS Engine
12 Monkeys Inside JS Engine
 
Gatekeeper: API gateway
Gatekeeper: API gatewayGatekeeper: API gateway
Gatekeeper: API gateway
 
Catch a spider monkey
Catch a spider monkeyCatch a spider monkey
Catch a spider monkey
 
Even more java script best practices
Even more java script best practicesEven more java script best practices
Even more java script best practices
 
JavaScript Best Pratices
JavaScript Best PraticesJavaScript Best Pratices
JavaScript Best Pratices
 
Yampa AFRP Introduction
Yampa AFRP IntroductionYampa AFRP Introduction
Yampa AFRP Introduction
 
JSDC 2014 - functional java script, why or why not
JSDC 2014 - functional java script, why or why notJSDC 2014 - functional java script, why or why not
JSDC 2014 - functional java script, why or why not
 
Things about Functional JavaScript
Things about Functional JavaScriptThings about Functional JavaScript
Things about Functional JavaScript
 

Introduction to Basic Haskell Components (In Chinese)

  • 2. http://goo.gl/VInp9 MS PowerPoint 2007 PDF http://goo.gl/TiiMY 本著作係採用創用 CC 姓名標示-非商業性-相同方式分享 2.0 台灣 授權條款授權.
  • 3. Snowmantw : Vimmer / Linux User λ Haskell Learner G Self-Studier $ Javascript Developer @ snowmantw at gmail.com ✍ Master's Degree Student → Dept. of Computer Science, NCCU snowmantw.github.com C C+ + PHP JS Haskell Java
  • 4. Outline • YAMI – Yet Another Monad Introduction • Monad vs. Arrow • Other Type Classes in Typeclassopedia • Beyond Haskell – Patterns in Functional Programming
  • 6. What is a Monad ?
  • 7. What is a Monad ? getLine :: IO String putStrLn:: String -> IO () (>>) :: Monad m => m a -> m b -> m b (>>=) :: Monad m => m a -> (a -> m b) -> m b main = getLine >>= name -> putStrLn “Hello :”++name >> putStrLn “World !” 這大概是為何大部分的 Haskell “Hello World” 都是 從費式級數開始講起…
  • 8. Tears of a Haskell Newbie Monad,單元(unit)的拉丁語,來自範疇 論的一種技術,其已經被採用作為處理在功 能性程序設計語言中… In functional programming, a monad is a structure that represents computations. In category theory, a branch of mathematics, a monad, Kleisli triple, or triple is an (endo-)functor, together with two natural transformations. A monad is an "amplifier" of types that obeys certain rules and which has certain operations provided. 單子(monad,也譯單體)是函數式編程中的一種抽象 數據類型,其特別之處在於,它是用來表示計算而不是 數據的。在以函數式風格編寫的程序中,單子可以用來 組織包含有序操作的過程,或者用來定義任意的控制流
  • 9. Monad,單元(unit)的拉丁語,來自範疇 論的一種技術,其已經被採用作為處理在功 能性程序設計語言中… In functional programming, a monad is a structure that represents computations. In category theory, a branch of mathematics, a monad, Kleisli triple, or triple is an (endo-)functor, together with two natural transformations. A monad is an "amplifier" of types that obeys certain rules and which has certain operations provided. 單子(monad,也譯單體)是函數式編程中的一種抽象 數據類型,其特別之處在於,它是用來表示計算而不是 數據的。在以函數式風格編寫的程序中,單子可以用來 組織包含有序操作的過程,或者用來定義任意的控制流 Tears of a Haskell Newbie
  • 10. Monad everywhere and not a piece to understand… Tears of a Haskell Newbie
  • 11. There is no royal road to Haskell. —Euclid* Tears of a Haskell Newbie *from “typeclassopedia”
  • 12. “Typeclassopedia” in Monad.Reader # 13 http://www.haskell.org/wikiupload/8/85/TMR-Issue13.pdf
  • 13. Begin from Pure Functions
  • 14. Begin from Pure Functions fn:: a -> b gn:: b -> c gfn:: a -> c gfn a = gn ( fn ( a ) ) We can use “definition” to make new functions. But that’s not so “functional”.
  • 15. Composition in Functional Language (.):: (b -> c)->(a -> b)-> a -> c fngn 。 gfn Functional Language ( at least, in Haskell ) : Compose Everything !
  • 16. Composition in Functional Language 大的函式可由許多小函式合成而成 zn . yn . xn …. cn . bn . an
  • 17. Problem: Data in a Nutshell
  • 18. Problem: Data in a Nutshell (+4).(+5):: Int -> Int Int: 4 Int: 12 ((+4).(+5)) 4 == 12 +4 +5 When Int: 4 ~> [Int: 4]
  • 19. Problem: Data in a Nutshell (+4).(+5):: Int -> Int [Int]: [4] ((+4).(+5)) [4] -- Error ! +4 +5 X 函式無法處理帶 context 性質的值 每種 context 都有其意義
  • 20. Problem: Data in a Nutshell • Maybe a:: 代表不確定性運算 • Either e a:: 代表有可能會例外的運算 • [a]:: 代表不確定性運算 -- 可能性更多 • IO a:: 代表會對 RealWorld 做出影響 常見的 Context 使用 context 觀點會比容器觀點更加適切
  • 21. Problem: Data in a Nutshell (+4).(+5):: Int -> Int Solution #1 plus45 = (+4).(+5) plus45Special [ x ] = plus45 x -- use pattern matching 為該函式定義一特別的 “unwrap” 版本 有多少 context 就要定義多少版本…
  • 22. Problem: Data in a Nutshell (+4).(+5):: Int -> Int Solution #1 plus45 = (+4).(+5) plus45Special [ x ] = plus45 x plus45SpMaybe (Just x) = plus45 x plus45SpIO (IO x) = plus45 x ……..
  • 23. Problem: Data in a Nutshell (+4).(+5):: Int -> Int Solution #1 plus45 = (+4).(+5) plus45Special [ x ] = plus45 x plus45SpMaybe (Just x) = plus45 x plus45SpIO (IO x) = plus45 x …….. pure with context 實際上分為處理 context 與運算兩部分
  • 24. Problem: Data in a Nutshell (+4).(+5):: Int -> Int Solution #2 每種 context 定義出自己的包裹函式 代為處理包裹與「解包」的問題 (+4).(+5) [ 4 ] 4 12 [ 12 ] fmap:: (a->b)->f a -> f b
  • 25. Problem: Data in a Nutshell (+4).(+5):: Int -> Int Solution #2 重用:不用更改原本的運算函式 解耦:將運算與 context 處理分開 靈活:組合而非定義生成新的運算方式 fmap:: (a->b)->f a -> f b
  • 26. Type Class: Functor Abstract Structure with fmap
  • 27. Type Class: Functor from Typeclassopedia, Haskell Wiki http://www.haskell.org/haskellwiki/Typeclassopedia
  • 28. Type Class: Functor class Functor f where fmap:: ( a -> b ) -> f a -> f b 帶有 fmap 函式定義的 context fmap 的定義要懂得包裹與解包 fmap = map -- Functor [ ] fmap _ Nothing = Nothing fmap f ( Just a ) = Just ( f a ) -- Functor Maybe fmap f x = x >>= ( return . f) -- * Functor IO
  • 29. From Functor to Monad Functor 定義了如何讓普通函式「轉成」 特定 context 下的函式 fmap:: (a->b)->f a -> f b (.):: (b -> c)->(a -> b)-> a -> c Compose 定義了如何串出更大的運算 結合兩者可做出更大的 context 運算
  • 30. From Functor to Monad 從一個普通值帶到某 context 運算 4 → [ 4 ] [ 21 ] (+4).(+5 ) (+4).(+5 ) (+4).(+5 ) 值一但被包裹理論上就不會被解包(特例) 這整條運算:a -> m a ( m :: Context ) 可稱為 action ( from IO Monad ) fmap AND (.)
  • 31. From Functor to Monad 還缺少把值變成 context 值的抽象函式 4 → [ 4 ] [ 21 ] (+4).(+5 ) (+4).(+5 ) (+4).(+5 ) return:: a -> m a * 這個名字很不幸與許多程式語言的保留關鍵字相同,然而應該 注意其意義幾乎完全不同! * return 幾乎就等於 Data Constructor 了,例如 Just a [ a ] -> [ c ]
  • 32. From Functor to Monad 不僅僅是 [ ] :抽象概念互通 4 → [ 4 ] [ 31 ] (+4).(+5 ) (+4).(+5 ) (+4).(+5 ) 4 → Maybe 4 Maybe 31 4 → IO 4 IO 31 m a -> m c 都是從一個值 -> 運算後且帶 context 的值
  • 33. From Functor to Monad 我們用 fmap (.) 與 return 建出單個 context 運算 (+4).(+5 ) (+4).(+5 ) (+4).(+5 ) 理論上這樣的運算,應該要像函式可以組合 。( ) ( )
  • 34. From Functor to Monad 阻礙:型別不通 。( ) ( ) [ c ] c -> [ d ] (>>=):: m a -> (a -> m b ) -> m b 這個奇怪的 bind 運算子幫我們搭了橋
  • 35. From Functor to Monad 有了 bind 運算子我們可以任意組合同型 context 運算 。( ) ( ) [ c ] c -> [ d ] (>>=):: m a -> (a -> m b ) -> m b 效果:把前一個 context 值私下解包後,傳給下個運算
  • 36. From Functor to Monad 。( ) ( ) [ c ] c -> [ d ] (>>=):: m a -> (a -> m b ) -> m b find even [1,2] >>= return . ((!!) [1,2,4]) -- Maybe [‘3’,’4’,’5’]>>= digitToInt >>= return . even -- [ ] getLine >>= putStr.((++) “Hi, user [”) >> putStrLn “] !” -- IO
  • 37. From Functor to Monad (>>=):: m a -> (a -> m b ) -> m b find even [1,2] >>= return . ((!!) [1,2,4]) 找到為偶數的值:Just 2 找到 index#2 的值,並包裝之 find:: (a->Bool)->[a]->Maybe a even:: Integral a => a -> Bool (!!):: [a]->Int->a ; (!!) [1,2,4] :: Int -> a return:: a -> m a ; return . ( (!!) [1,2,4] ) :: Int -> m b return 夠抽象,所以可以視其正在 哪個 context 中用不同的 instance
  • 38. From Functor to Monad (>>=):: m a -> (a -> m b ) -> m b [‘3’,’4’,’5’]>>= return . digitToInt >>= return . even ( 為了方便示範 ) 各字元轉換成整數 各奇偶數轉成 Bool getLine >>= putStr.((++) “Hi, user [”) >> putStrLn “] !” 從 IO 取得一行 組合傳入字串並從 IO 輸出 不管前面結果而印出 抽象:注意每個 context 對 bind 詮釋都不同,但用法都相同 bind 表現的效果之一是不用管傳值,只要專注把運算組合即可 (>>):: m a -> m b -> m b -- 不管前面結果,自己執行出 m b
  • 39. From Functor to Monad Functor -- fn -> context fn fmap:: (a -> b) -> f a -> f b Monad -- computation under m return:: a -> m a (>>=):: m a-> (a->m b)-> m b 理論上所有 Monad 都要同時也是 Functor ,但並非 Haskell 現狀
  • 40. Monad Laws Left identity: return a >>= f ≡ f a Right identity: m >>= return ≡ m Associativity: (m >>= f) >>= g ≡ m >>= (x -> f x >>= g) 主要是確保組合小運算成大運算的過程中,不會因組合先後不同而出錯 http://www.haskell.org/haskellwiki/Monad_Laws
  • 41. Monad 與 Pure • Pure: 函式無副作用 → 輸入只能根據輸出唯一決定 openFile:: FilePath -> IOMode -> IO Handle In what sense is the IO monad pure ? id 3 == 3 id 3 == 3 id 3 == 3 id 3 = 3 id 3 = 3 id 3 = 4 Hidden State !
  • 42. Monad 與 Pure: IO Monad openFile:: FilePath -> IOMode -> IO Handle In what sense is the IO monad pure ? modify = openFile "/tmp/test" WriteMode >>= (h -> hPutStrLn h “watch#2: Hello World !" >> hClose h) watch = openFile "/tmp/test" ReadMode >>= (h-> hGetLine h >>= putStrLn >> hClose h) f = watch >> modify >> watch ---- watch#1: Original Content watch#2: Hello World ! 兩次 watch 呼叫參數都一樣 ,但是輸出卻不同!
  • 43. Monad 與 Pure: IO Monad fn:: a -> a’ ; gn:: a’ -> a’’ ; hn:: a’’ -> a’’’ hgfn:: a ~> a’ ~> a’’~> a’’’ :: a -> a’’’ Pure 函式本身不能存有狀態,但是狀態可以 用傳遞的方式給予 Haskell ( GHC ) 底層偷偷在 IO Monad 中間 加入傳遞 #RealWorld 的動作 → modify:: #RealWorld -> #RealWorld’ → watch:: #RealWorld “Problem ?”
  • 44. Monad 與 Pure: IO Monad watch >> modify >> watch -- 將變成類似於(非實際實做!) watch #RealWorld ~> modify #RealWorld ~> watch #RealWorld ’ Pure 函式本身不能存有狀態,但是狀態可以 用傳遞的方式給予 所以兩次 watch 的「參數」已經不同,故表面 上看來具有副作用的 watch 實際上也是 Pure → 不過我們可解釋 Pure 為:有副作用者,如檔 案內容這種值,不能直接「污染」Pure 函式 → 也就是 Pure Function 與 Action 不能混用
  • 45. Monad 與 Pure: IO Monad [a] -> a --:: head, tail, foldl, maximum, minimum … Maybe a -> a --:: fromJust, fromMaybe defaultValue … ---- IO a -> a --:: ( NO SUCH FUNCTION !! ) Haskell 利用 context 概念永久包住帶 「副作用」的 IO 值: a -> IO a -> …… IO z 一般 Monad 多少都有 unwrap function,也就 是在該 context 內部可以是 Impure 的處理。但 離開 context 的值必須只能是 Pure : m a -> a → 一入 IO ,永為 IO :因沒有 unwrapper, 所有要處理 IO 者都必須嵌入該 context 內
  • 46. Monad 小結 Pure Function 。 with Context value wrapper :: a -> m a >>=( ) ( ) [ c ] c -> [ d ]
  • 47. Monad 小結 • Monad 就是符合規則且實作 return 、>>= 等的抽 象結構 ( Type Class) • 這個抽象結構允許透過組合,產生出新的 action • action: 允許將純值包裹進某個 context ,並進行 一連串變換的運算 • Monad 提供工具將帶 context 運算組合再一起。 包括帶真正 Side-Effect 的 IO 也可以此達到 pure 補充:In what sense is the IO monad pure ? http://stackoverflow.com/questions/4063778/in-what-sense-is-the-io- monad-pure
  • 49. Arrow 介紹 from Typeclassopedia, Haskell Wiki http://www.haskell.org/haskellwiki/Typeclassopedia
  • 50. How to make an Arrow This is a normal function… fn:: a -> b … and this is an Arrow fn::(->) a b Just like any other data type Maybe[ ] Int Book Id Price - 這個 Arrow - 接收:a 給出:b Tip: 可以表達運 算與可以執行運 算是兩件事
  • 51. From Monad to Arrow getLine :: IO String putStr, putStrLn :: IO () main :: IO () main = getLine >>= putStr.((++) “Hi, user [”) >> putStrLn “] !” Monad 型別意義:m a 代表「這個 monad 會產生 a 型別的值 」因此,Monad 封裝出完整、不依賴外部的 operation ( 所以叫「單子」 ) 持有一個 Monad a: 持有一個「值」 ( 內部一連串運算得出) Arrow 型別意義:a b c 代表「這個 arrow 接收 b 傳出 c」 因此,Arrow 封裝的是一個 transformation ( 有接受端) 持有一個 Arrow b c: 持有一個「會從 b 到 c 的變換」 → 若以 `b` Apply 此 Arrow,就等於 ( M b ) ( Arrow 不一定都可 Apply) Monad 把資料連同運算封裝,模糊了 object 與 transformation Arrow 只封裝運算,並提供了「針對運算的運算」
  • 52. From Monad to Arrow 一如 Monad 有抽象的 return 代替實際的建構式,Arrow 中 arr:: Arrow a => (b -> c) -> a b c 如何將一個普通的函式封成其 context 下一個 transformation 實做視其 context (運算種類)不同而異 幾個常見的 Arrow ordinary functions : (->) b c Kleisli arrows : Monad m => (->) b m c stream transformers : (-> ) (Stream b) (Stream c) return:: a -> m a 對比於 Monad 的 return function 將值,而非運算轉換
  • 53. Arrows: A General Interface to Computation 如果我們有一堆的 Arrow a b c 我們可以針對他們進行一些組合動作 a b d a c d a b c >>> a c d :: a b d (c -> d)。(b -> c):: (->) b d ordinary functions: 就是普通的函式合成 Kleisli: 用 g b >>= f 去作組合
  • 54. Arrows: A General Interface to Computation 基本的 Arrow 函式 http://www.soi.city.ac.uk/~ross/papers/fop.html
  • 55. Arrows: A General Interface to Computation 使用 Arrow 組合出整個程式 http://www.soi.city.ac.uk/~ross/papers/fop.html 使用 Arrow ,整 個程式的邏輯單 元就可以像電路 一樣被組合
  • 56. Arrow vs. Monad Monad 的「中間環節」可脫離型別掌握 m a >>= (a -> m b) >>= ( b -> m c ) 並無法確認 (a -> m b) 這個 Action 處理中保持在同樣的 context 裡 a m b n c ? 只認頭與尾 無法控管中間
  • 57. Arrow vs. Monad Arrow 的組合函式會確保 context 相同 a b c >>> a c d >>> a d e >>> a e f a c d 只能再次由 >>> 構成: a c z >>> a z y >>> a y x >>> a x d a z y 只能再次由 >>> 構成: a z w >>> a w v >>> a v u >>> a u y
  • 58. Arrow vs. Monad Arrow 的組合函式會確保 context 相同 a b c >>> a c d >>> a d e >>> a e f a c z >>> a z y >>> a y x >>> a x d a z w >>> a w v >>> a v u >>> a u y 組合中所有子 Arrow 都在 a 這個 context 內
  • 59. Arrow vs. Monad Arrow 的組合函式會確保 context 相同 Every time we sequence two monadic computations,we have an opportunity to run arbitrary Haskell code in between them. Monad But in the case of arrows, in contrast, the second argument of (>>>) is just an arrow… Arrow from “Programming with Arrows”; John Hughes
  • 60. Other Type Classes in Typeclassopedia
  • 61. 其他運算元件介紹 from Typeclassopedia, Haskell Wiki http://www.haskell.org/haskellwiki/Typeclassopedia
  • 63. Applicative Functor : 可以讓一個函式被「context 化」 (+4).(+5) [ 4 ] 4 12 [ 12 ] fmap:: (a->b)->f a -> f b 但是僅限於只有一個參數的函式
  • 64. Applicative fmap 的函式如何給予一個以上的參數? (+):: Int -> (Int -> Int) fmap (+) :: f a -> f (Int -> Int) fn = fmap (+) -- 假設以 [] 為 context fn:: [ ] Integer -> [ Integer -> Integer ] fn [4] :: [Integer -> Integer] -- 無法進一步 apply [5] 給 (+) fn [4] [5] -- Error ! ( fn [4] 「滿了」,已經無法再給參數)
  • 65. Applicative Applicative 提供了如何 apply 的解決方式 pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b fn = fmap (+) -- 假設以 [] 為 context fn:: [ ] Integer -> [ Integer -> Integer ] fn [4] :: [Integer -> Integer] -- 無法進一步 apply [5] 給 (+) (<*>) (fn [4]) :: [ ] Integer -> [ ] Integer -- 可以給予參數了! fmap (+) [4] <*> [5] -- [9] 將被放在 context 內的變換轉出來,變成可給予的參數
  • 66. Applicative 根據 Applicative Laws ,fmap 可換成 fmap g x = pure g <*> x fn :: a -> b -> c -> d -> e -> f … -> z -- 很多參數 fn a b c d e … -- 一般的 function apply pure fn <*> f a <*> f b <*> f c <*> f d <*> f e … -- 就如同往常的 function apply fmap fn f a <*> f b <*> f c <*> f d <*> f e … -- fmap 會幫忙帶第一個參數 因此一般來說 Applicate 使用起來會長得像是 給定第一個參數
  • 68. Monoid Monoid: 可以作「加法」的類別 mzero :: m a -- [ ] ,Nothing mplus :: m a -> m a -> m a -- (++) Nothing `mplus` Nothing = Nothing -- 0 solutions + 0 solutions = 0 solutions Just x `mplus` Nothing = Just x -- 1 solution + 0 solutions = 1 solution Nothing `mplus` Just x = Just x -- 0 solutions + 1 solution = 1 solution Just x `mplus` Just y = Just x -- 1 solution + 1 solution = 2 solutions, Maybe 的 mplus 定義有點繁瑣 http://stackoverflow.com/questions/4504489/monadplus-definition-for-haskell-io * 「為何 IO 不是 MonadPlus ? 」-> ‘mzero’ would necessarily represent an IO computation that never returns.
  • 70. Foldable Foldable :可以從一個結構 -> 「加」成一個值 fold :: Monoid m => t m -> m Prelude> foldr (x y -> concat ["(",x,"+",y,")"]) "0" (map show [1..13]) "(1+(2+(3+(4+(5+(6+(7+(8+(9+(10+(11+(12+(13+0)))))))))))))" Prelude> foldl (x y -> concat ["(",x,"+",y,")"]) "0" (map show [1..13]) "(((((((((((((0+1)+2)+3)+4)+5)+6)+7)+8)+9)+10)+11)+12)+13)"
  • 72. Traversable Foldable 會改變最終結果的結構,與原本不同 Traversable 可以給出「保持結構的變化」 traverse :: Applicative f => (a -> f b) -> t a -> f (t b) instance Traversable Tree where traverse g Empty = pure Empty traverse g (Leaf x) = Leaf <$> g x traverse g (Node l x r) = Node <$> traverse g l <*> g x <*> traverse g r 如何把一個改變的函式 apply 到一個結構,及其子結構內? A B C traverse (+1) A + 1 B + 1 C + 1 ~>
  • 74. Comonad 前面說過一般而言 Monad 是「包裹」用 return :: a -> f a return a ~> f a ~> f b ~> f c 具有反向「解包」者稱為 Comonad extract :: f a -> a 可以從一個 Monad 中解出 pure 的值
  • 75. Comonad 除此之外還有「反向的」bind ( >>= ) extend :: ( w a -> b) -> w a -> w b (>>=):: m a -> ( a -> m b ) -> m b
  • 77. Beyond Haskell Patterns in Functional Programming
  • 78. Beyond Haskell • Type Class, (.), Monad, Foldable, Traversable… • 這些概念並非只存在於 Haskell 這個語言中 • 甚至並非僅存在於 Functional Programming 的世界中 First-Class Function class Add { int _a; public: Add(int a): _a(a){} int operator()(int b){ return _a + b; } }; Add a = Add(3); a(4) a = (+) 3 a 4
  • 79. Beyond Haskell • Type Class, (.), Monad, Foldable, Traversable… • 這些概念並非只存在於 Haskell 這個語言中 • 甚至並非僅存在於 Functional Programming 的世界中 class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool public interface Eq<A>{ public Boolean eq( A a ); public Boolean neq( A a ); } instance Eq Integer where x == y = x `integerEq` y public class Integer implements Eq { //… } Type Class
  • 80. Beyond Haskell • Type Class, (.), Monad, Foldable, Traversable… • 這些概念並非只存在於 Haskell 這個語言中 • 甚至並非僅存在於 Functional Programming 的世界中 hn = fn . gn Composition Command + Compoisite pattern
  • 81. Beyond Haskell • Type Class, (.), Monad, Foldable, Traversable… • 這些概念並非只存在於 Haskell 這個語言中 • 甚至並非僅存在於 Functional Programming 的世界中 Monad main = getLine >>= putStr.((++) “Hi, user [”) >> putStrLn “] !” $(dom).find(‘.subdom’) .hide() .append(some_dom) .addClass(‘show’); .fadeIn() http://importantshock.wordpress.com/2009/01/18/jquery-is-a-monad/ “jQuery is a monad” …OR any fluent interface + context computation http://en.wikipedia.org/wiki/Fluent_interface
  • 82. Beyond Haskell • Type Class, (.), Monad, Foldable, Traversable… • 這些概念並非只存在於 Haskell 這個語言中 • 甚至並非僅存在於 Functional Programming 的世界中 Monad main = getLine >>= putStr.((++) “Hi, user [”) >> putStrLn “] !” “Monad in Scala” “Monad in F#” “Monad in Java” (some terrible codes ) “Monad in C++” (with C++11 lambda) “Monad in Ruby” (lambda, again) “Monad in Python” (「with-nice-syntax」)
  • 83. Beyond Haskell • 反過來說,很多所謂 Design Pattern 都是為了 OOP 的概 念或語言而設計的 • 有些 pattern 到了 Haskell 或 FP 就不見得需要,或變得 是語言自然的一部分 Pattern in Haskell Strategy First class functions and lambdas Factory Method Template Method Higher-order functions Abstract Factory Builder Bridge Type classes and smart constructors Adapter Decorator Chain of Responsibility. Composition and lifting ( like fmap ) http://blog.ezyang.com/2010/05/design-patterns-in-haskel/
  • 84. Beyond Haskell • 反過來說,很多所謂 Design Pattern 都是為了 OOP 的概 念或語言而設計的 • 有些 pattern 到了 Haskell 或 FP 就不見得需要,或變得 是語言自然的一部分 Pattern in Haskell Visitor Equational functions; Foldable. Interpreter Functions; DSEL; ADT provides a nice way to construct the AST of your language. Command Monads ( computation ) Iterator Lazy lists Prototype Immutability Flyweight Memoising and constant applicative forms (CAF) http://blog.ezyang.com/2010/05/design-patterns-in-haskel/
  • 85. Beyond Haskell • 反過來說,很多所謂 Design Pattern 都是為了 OOP 的概 念或語言而設計的 • 有些 pattern 到了 Haskell 或 FP 就不見得需要,或變得 是語言自然的一部分 Pattern in Haskell State Memento Unnecessary ( LOL ); Undo Monad Singleton Unnecessary ( again ) Facade Functions Observer STM, Mvar, Channel functional reactive programming Proxy Wrapped data types, laziness and garbage collector Mediator Monad stack
  • 86. Thanks for your attention.