haskell勉強会2 in ie
TRANSCRIPT
勉強会について
• 前回のHaskell勉強会 in ieの続きのようなもの
• 「すごいhaskell楽しく学ぼう」本を元にしています
• スライド内のコード詰め合わせを下記に公開していますhttps://gist.github.com/maeken2010/8e70e07435137702ac3c
型定義
• dataキーワード
• data Bool = False | True
• data Int = -2147483648 | .. | -1 | 0 | 1 | 2 | .. |2147483647
※実際は違います
データ型
• ex)長方形と円の図形の型を定義
data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving (Show)
データ型
• ex)長方形と円の図形の型を定義
data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving (Show)
値を使う
• 面積を返す関数
area :: Shape -> Float area (Circle _ _ r) = pi*r^2 area (Rectangle x1 y1 x2 y2) = (abs $ x2-x1)*(abs $ y2-y1)
ghci> area maru 254.46901
deriving
• 型を表示したい時はderiving(詳細は後で)
data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving (Show)
レコード構文
• 値を作る際は順番は関係なし
ghci> let maeken = Person{age = 20,name="maeken"} ghci> maeken Person {name = "maeken", age = 20} ghci> name maeken "maeken"
型引数
• 型引数 aは数字を受け取りたい(Int,Float..)
vplus :: (Num a) => Vector a -> Vector a -> Vector a (Vector i j k) `vplus` (Vector l m n) = Vector (i+l) (j+m) (k+n)
インスタンス自動導出
• derivingでその型を自動的に指定した型クラスのインスタンスにする
data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday deriving (Eq,Ord,Show,Read,Bounded,Enum)
Ordクラス
• Ordインスタンスは比較が可能
• 先に定義されてるほうが小さいとされる
ghci> Saturday > Friday True ghci> Monday `compare` Wednesday LT
Enumクラス
• Enumインスタンスは要素の列を列挙可能
ghci> succ Monday Tuesday ghci> [Thursday .. Sunday] [Thursday,Friday,Saturday,Sunday]
型シノニム
• 電話帳の型の型シノニムを定義
type PhoneNumber = String type Name = String type PhoneBook = [(String,String)]
再帰データ構造
• 実際のリストとの比較
ghci> Empty Empty ghci> 4 `Cons` (5 `Cons` Empty) Cons 4 (Cons 5 Empty)
ghci> [] [] ghci> 4 : (5 : []) [4,5]
演算子
• Consを中置換数に
• infixrで結合性を宣言.infixr 7 *,infixr 6 +等
infixr 5 :-: data List a = Empty | :-: a (List a) deriving(Show,Read,Eq,Ord)
演算子
• リストを結合する演算子を定義
infixr 5 ^++ (^++) :: List a -> List a -> List a Empty ^++ ys = ys (x :-: xs) ^++ ys = x :-: (xs ^++ ys)
ツリー構造
• 深さ優先でリスト化
flatten :: Nodes a -> [a] flatten (Node s t) = (flattenT s)++(flattenT t) flatten (Leaf x) = [x]
型クラス
• 型クラスは特定の振る舞いを定義する
• ある型Tがある型クラスCのインスタンスであるとは,型クラスCが定義する関数を型Tに対して使えるという事
• ※オブジェクト指向で言うクラスとは違うので注意
型クラス内部
• 例)Eq型クラス class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool x == y = not (x /= y) x /= y = not (x == y)
型クラス内部
• aは型変数.将来Eqのインスタンスとなる class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool x == y = not (x /= y) x /= y = not (x == y)
インスタンスを作る
• Eqのインスタンスを手動で生成 data TrafficLight = Red | Yellow | Green
instance Eq TrafficLight where Red == Red = True Green == Green = True Yellow == Yellow = True _ == _ = False
インスタンスを作る• 型変数aに具体的な型が入っている
class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool x == y = not (x /= y) x /= y = not (x == y)
instance Eq TrafficLight where Red == Red = True Green == Green = True Yellow == Yellow = True _ == _ = False
インスタンスを作る
• Showのインスタンスを手動で生成
instance Show TrafficLight where show Red = "Red light" show Yellow = "Yellow light" show Green = "Green light"
インスタンスを作る
ghci> Red Red light ghci> Red == Red True ghci> [Red,Green,Yellow] [Red light,Green light,Yellow light]
多相型の注意
• MaybeをEqのインスタンスにする場合
• 下記はまちがい.Maybeは型ではなく型コンストラクタ
instance Eq Maybe where Just x == Just y = x == y Nothing == Nothing = True _ == _ = False
多相型の注意
• まだまちがい
• Maybeの中身に対して==を使っている
• つまりmはEqに属してないといけない instance Eq (Maybe m) where Just x == Just y = x == y Nothing == Nothing = True _ == _ = False
多相型の注意
• せいかい
instance (Eq m) => Eq (Maybe m) where Just x == Just y = x == y Nothing == Nothing = True _ == _ = False
型クラスを作る
• JavaScriptの真理値を実装する
if(0) alert("Yes!") else alert("No!") if("") alert("Yes!") else alert("No!") if(false) alert("Yes!") else alert("No!")
⇛すべて"No!"が返る
YesNoインスタンス
• Int
• リスト
• Bool
instance YesNo Int where yesno 0 = False yesno _ = True
instance YesNo [a] where yesno [] = False yesno _ = True
instance YesNo Bool where yesno = id
YesNoインスタンス
• Maybe
• TrafficLight
instance YesNo (Maybe a) where yesno (Just _) = True yesno Nothing = False
instance YesNo TrafficLight where yesno Red = False yesno _ = True
YesNoインスタンス• 早速遊んでみる
ghci> yesno [] False ghci> yesno "aaa" True ghci> yesno (Just 0) True ghci> yesno Red False ghci> :t yesno yesno :: YesNo a => a -> Bool
YesNoインスタンス
• ついでに関数も作る
yesnoIf :: (YesNo y) => y -> a -> a -> a yesnoIf yesnoVal yesResult noResult = if yesno yesnoVal then yesResult else noResult
YesNoインスタンス
ghci> yesnoIf [] "yes!" "no!" "no!" ghci> yesnoIf "0" "yes!" "no!" "yes!" ghci> yesnoIf True "yes!" "no!" "yes!" ghci> yesnoIf Nothing "yes!" "no!" "no!"
Functor型クラス
• fは具体型ではなく型コンストラクタ
• fmapは,「ある型aから別の型bへの関数」と「ある型aに適用されたファンクター値」を取り,「別の型bへ適用されたファンクター値」を返す関数と読める
mapとfmap
• 実はmapはfmapのリスト版
• mapは「型aから型bへの関数」と「型aのリスト」を受け取り,「型bのリスト」を返す
map :: (a -> b) -> [a] -> [b] fmap :: (a -> b) -> f a -> f b
MaybeもFunctor
• Maybe型はFanctorなのでfmap可能
instance Functor Maybe where fmap f (Just x) = Just (f x) fmap Nothing = Nothing
NodesもFunctor
• Nodes型にもfmap可能.インスタンスは下記.
instance Functor Nodes where fmap f (Leaf a) = (Leaf (f a)) fmap f (Node left right) = Node (fmap f left) (fmap f right)
Functorで遊ぶ
ghci> fmap (+5) (Just 4) Just 9 ghci> fmap (++"!") (Just "maeken") Just “maeken!" ghci> let x=Node (Node (Leaf 1) (Node (Leaf 2) (Leaf 4))) (Leaf 3) ghci> fmap (*2) x Node (Node (Leaf 2) (Node (Leaf 4) (Leaf 8))) (Leaf 6)