Viktor Lin
data Tree a = Leaf | Node a (Tree a) (Tree a)
Tree
: Datatype 名稱Branch,Node
: Constructor 名稱a
: Type VariableBranch :: Tree a -> Tree a -> Tree a
Leaf :: a -> Tree a
t1 :: Tree Int
t1 = Node 1 (Node 2 Leaf Leaf) Leaf
height :: Tree a -> Int
height Leaf = 0
height (Node a t1 t2) = max (height t1) (height t2) + 1
height
作用於任意的 Tree> height (Node 'c' (Node 'o' Leaf (Node 'c' Leaf Leaf)) Leaf)
3
data Tree a = Leaf | Node a (Tree a) (Tree a)
---------------------------------------------
data Tree a where
Leaf :: Tree a
Node :: a -> Tree a -> Tree a
data Empty
data NonEmpty
data SafeList a b where
Nil :: SafeList a Empty
Cons :: a -> SafeList a b -> SafeList a NonEmpty
class Show a where
show :: a -> String
instance Show Bool where
show True = "True"
show False = "False"
class Eq a where
(==) :: a -> a -> Bool
instance Eq a => Eq (Tree a) where
Leaf == Leaf = True
Leaf == _ = False
(Node a t1 t2) == (Node b u1 u2) = a == b && t1 == u1 && t2 == u2
(Node a t1 t2) == _ = False
data Empty
data NonEmpty
data SafeList :: * -> * -> * where
Nil :: SafeList a Empty
Cons :: a -> SafeList a b -> SafeList a NonEmpty
* Jeremy Gibbons (2007): Datatype-generic Programming. In: Proceedings of the 2006 International Conference on Datatype-generic Programming, SSDGP’06, Springer-Verlag, Berlin, Heidelberg, pp. 1– 71, doi:10.1007/978-3-540-76786-2 1. Available at http://dl.acm.org/citation.cfm?id=1782894.1782895.
#include<stdio.h>
int main() {
printn(5);
printn(10);
}
void printn(int n) {
for (int i = 1; i <= n; i++) {
for (int j = 0; j < i; j++)
printf("*");
printf("\n");
}
}
Function in C
printf("*");
printf("**");
printf("***");
printf("****");
printf("*****");
printf("*");
printf("**");
printf("***");
printf("****");
printf("*****");
printf("******");
printf("*******");
printf("********");
printf("*********");
printf("**********");
5
10
data ListInt = Nil | Int :+ ListInt
append :: ListInt -> ListInt -> ListInt
append Nil ys = ys
append (x :+ xs) ys = x :+ append xs ys
xs :: ListInt
xs = 0 :+ 1 :+ Nil
Datatype and function in Haskell
data ListChar = Nil | Char :+ ListChar
append :: ListChar -> ListChar -> ListChar
append Nil ys = ys
append (x :+ xs) ys = x :+ append xs ys
data List a = Nil | a :+ ListInt
append :: List a -> List a -> List a
append Nil ys = ys
append (x :+ xs) ys = x :+ append xs ys
xs :: List Int
xs = 0 :+ 1 :+ Nil
Parametrized Type in Haskell
類似的 datatype 要有類似的函數,以 map 為例:
data List a = Nil | a :+ List a
mapList :: (a -> b) -> List a -> List b
mapList f Nil = Nil
mapList f (x :+ xs) = f x :+ mapList f xs
mapList
apply f to each element in a list
data Tree a = Leaf | Node a (Tree a) (Tree a)
mapTree :: (a -> b) -> Tree a -> Tree b
mapTree f Leaf = Leaf
mapTree f (Node a t1 t2) = Node (f a) (mapTree f t1) (mapTree f t2)
我們也能對 Tree 定義類似的 map 函數
data List a = Nil | a :+ List a
mapList :: (a -> b) -> List a -> List b
mapList f Nil = Nil
mapList f (x :+ xs) = f x :+ mapList f xs
data Tree a = Leaf | Node a (Tree a) (Tree a)
mapTree :: (a -> b) -> Tree a -> Tree b
mapTree f Leaf = Leaf
mapTree f (Node a t1 t2) = Node (f a) (mapTree f t1) (mapTree f t2)
{-# LANGUAGE GADTs, RankNTypes, PolyKinds, DataKinds #-}
data Color = Red | Black
data RBTree :: forall a. a -> Color -> * where
LeafB :: RBTree a Black
NodeR :: a -> RBTree a Black -> RBTree a Black -> RBTree a Red
NodeB :: a -> RBTree a c1 -> RBTree a c2 -> RBTree a Black
mapRBTree :: (a -> b) -> RBTree a c -> RBTree b c
mapRBTree f LeafB = LeafB
mapRBTree f (NodeR a t1 t2) = NodeR (f a) (mapRBTree f t1) (mapRBTree f t2)
mapRBTree f (NodeB a t1 t2) = NodeB (f a) (mapRBTree f t1) (mapRBTree f t2)
mapList
與 mapTree
像在哪?1. Tree 跟 List 很像!
a(都是
a -> *
的 Type Constructor)a
及被定義的 Datatype 自己data List a where
Nil :: List a
(:+) :: a -> List a -> List a
mapList :: (a -> b) -> List a -> List b
mapList f Nil = Nil
mapList f (x :+ xs) = f x :+ mapList f xs
data Tree a where
Leaf :: Tree a
Node :: a -> Tree a -> Tree a -> Tree a
mapTree :: (a -> b) -> Tree a -> Tree b
mapTree f Leaf = Leaf
mapTree f (Node a t1 t2) = Node (f a) (mapTree f t1) (mapTree f t2)
2. mapList
與 mapTree
的 type 有一樣的形式:
(a -> b) -> T a -> T b
data List a where
Nil :: List a
(:+) :: a -> List a -> List a
mapList :: (a -> b) -> List a -> List b
mapList f Nil = Nil
mapList f (x :+ xs) = f x :+ mapList f xs
data Tree a where
Leaf :: Tree a
Node :: a -> Tree a -> Tree a -> Tree a
mapTree :: (a -> b) -> Tree a -> Tree b
mapTree f Leaf = Leaf
mapTree f (Node a t1 t2) = Node (f a) (mapTree f t1) (mapTree f t2)
3. 兩個 map 定義方式相似:
一個 clause 對應一個 constructor
一個 clause 的結果與拿到的 Datatype 使用同一個 constructor
f 被套用在被參數化的型別的值
map f 被遞迴地套用在同樣的 Datatype 上
data List a where
Nil :: List a
(:+) :: a -> List a -> List a
mapList :: (a -> b) -> List a -> List b
mapList f Nil = Nil
mapList f (x :+ xs) = f x :+ mapList f xs
data Tree a where
Leaf :: Tree a
Node :: a -> Tree a -> Tree a -> Tree a
mapTree :: (a -> b) -> Tree a -> Tree b
mapTree f Leaf = Leaf
mapTree f (Node a t1 t2) = Node (f a) (mapTree f t1) (mapTree f t2)
class Functor f where
fmap :: (a -> b) -> f a -> f b
instance Functor List where
fmap f Nil = Nil
fmap f (Cons x xs) = Cons (f x) (fmap f xs)
instance Functor Tree where
fmap f Nil = Nil
fmap f (Node x t1 t2) = Node (f x) (fmap f t1) (fmap f t2)
我們想要一個打全部的 generic map!
Functor Laws 部分捕捉了我們想要的性質:
目前出現過的 Datatype 不外乎能用一個結構表示:
我們叫它多項式表示法(polynomial representation)
被抽象化的是 constructor 的形狀
data List a where
Nil :: List a
_:+_ :: a -> List a -> List a
data Tree a where
Leaf :: Tree a
Node :: a -> Tree a -> Tree a -> Tree a
data NP :: (k -> *) -> [k] -> * where
Nil :: NP f '[]
(:*) :: f x -> NP f xs -> NP f (x ': xs)
data NS :: (k -> *) -> [k] -> * where
Z :: f x -> NS f (x ': xs)
S :: NS f xs -> NS f (x ': xs)
A taste of the polynomial representation:
type family Code (a :: *) :: [[*]]
data Expr = Num Int | Add {left :: Expr, right :: Expr}
type instance Code Expr = '[ '[Int], '[Expr, Expr] ]
type SOP (f :: k -> *) (xss :: [[k]]) = NS (NP f) xss
type Rep a = SOP I (Code a)
class (Code a) => Generic (a :: *) where
from :: a -> Rep a
to :: Rep a -> a
instance Generic Expr where
from (Num n) = Z (I n :* Nil)
from (Add e f) = S (Z (I e :* I f :* Nil))
to (Z (I n :* Nil)) = Num n
to (S (Z (I e :* I f :* Nil))) = Add e f
A taste of the polynomial representation:
type family Code (a :: *) :: [[*]]
data Expr = Num Int | Add {left :: Expr, right :: Expr}
type instance Code Expr = '[ '[Int], '[Expr, Expr] ]
只要是 Generic 的 instance (e.g. Expr)就能轉成 JSON:
Generic
的 instance 就能有 Eq, Show, Lens, toJSON, fromJSON...
pub trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
}
Functor 是「kind 為 * -> * 的 Type Constructor」
的性質:e.g. List :: * -> *, Tree :: * -> *
沒有 higher kinded type 無法完整表達!