狠狠撸

狠狠撸Share a Scribd company logo
型や型クラスを自分で
作ろう (前編)
すごい贬补蝉办别濒濒読书会 in 大阪 2週目 #7
2014-07-16
Suguru Hamazaki
Making Our Own Types and Type Classes
7章前半の内容
データ型の
定義方法
レコード構文
型引数 インスタンスの
自動導出
型シノニム
新しいデータ型を
定義する
De?ning a New Data Type
? 標準ライブラリーでどのように定義されている
か?
? Bool
? Int
data Bool = False | True
型名 値コンスト
ラクター
値コンスト
ラクター
data Int = -2147483648 | -2147483647 | ... | -1 | 0 | 1 | 2 | ... | 2147483647
実際の定義とは異なるが、
このように考えられる
形づくる
Shaping Up
? Shape型
? 2次元上の円と長方形を表現する
? area関数
? Shape型のデータの面積を求める
data Shape = Circle Float Float Float | Rectangle Float Float Float Float	
deriving (Show)
型名
値コンスト
ラクター
値コンスト
ラクター
値コンストラクター
? 値を作るので、値コンストラクター
? 実際には関数の一種
? ex) Circle は Float 型の値を3つ引数として受け取り、Shape
型の値を返す関数
? ex) False は?
? 型と値コンストラクターを混同しないよう注意
? 型名と値コンストラクターの名前が同じでもよい
Value Constructors
area :: Shape -> Float	
area (Circle _ _ r) = pi * r ^ 2	
area (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1)
型シグネチャーには、
型名であるShape を使う
(Circle や Rectangle は型名ではない)
パターンマッチには
コンストラクターが使える
? Point型
? Circle, Rectangle のフィールドを構成する中間的な
型
? nudge関数
? Shape型のデータを移動
? baseCircle, baseRect関数
? ファクトリー的なもの
data Point = Point Float Float deriving (Show)	
data Shape = Circle Point Float | Rectangle Point Point deriving (Show)
Circle, Rectangle のフィールドを
Point 型で定義して整理
area :: Shape -> Float	
area (Circle _ r) = pi * r ^ 2	
area (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1)
パターンマッチも
若干すっきり (?)
nudge :: Shape -> Float -> Float -> Shape	
nudge (Circle (Point x y) r) a b = Circle (Point (x + a) (y + b)) r	
nudge (Rectangle (Point x1 y1) (Point x2 y2)) a b = Rectangle (Point (x1 + a) (y1 + b))
(Point (x2 + a) (y2 + b))	
!
baseCircle :: Float -> Shape	
baseCircle r = Circle (Point 0 0) r	
!
baseRect :: Float -> Float -> Shape	
baseRect width height = Rectangle (Point 0 0) (Point width height)	
baseCircle
baseRectangle
モジュールからエクスポート
module Shapes	
( Point(..)	
, Shape(..)	
, area	
, nudge	
, baseCircle	
, baseRect	
) where
値コンストラクターを
全てエクスポートする記法
明示的に列挙してもよい
? 型のみエクスポートして、値コンストラクターを
エクスポートしないのも OK
? 実装を隠 できる
レコード構文
Record Syntax
data Person = Person String String Int Float String String deriving (Show)	
!
firstName :: Person -> String	
firstName (Person firstname _ _ _ _ _) = firstname	
!
lastName :: Person -> String	
lastName (Person _ lastname _ _ _ _) = lastname	
!
age :: Person -> Int	
age (Person _ _ age _ _ _) = age	
!
height :: Person -> Float	
height (Person _ _ _ height _ _) = height	
!
phoneNumber :: Person -> String	
phoneNumber (Person _ _ _ _ number _) = number	
!
flavor :: Person -> String	
flavor (Person _ _ _ _ _ flavor) = flavor
data Person = Person { firstName :: String	
, lastName :: String	
, age :: Int	
, height :: Float	
, phoneNumber :: String	
, flavor :: String } deriving (Show)	
それぞれ、フィールド名とその
型名を指定する
ghci> :t firstName	
firstName :: Person -> String	 対応する関数が自動的
に作られる
data Car = Car { company :: String	
, model :: String	
, year :: Int } deriving (Show)	
ghci> Car { company = "Ford", model = "Mustang", year = 1967}	
Car {company = "Ford", model = "Mustang", year = 1967}	
ghci> Car { company = "Ford", year = 1967, model = "Mustang"}	
Car {company = "Ford", model = "Mustang", year = 1967}	
フィールドを任意の順
番で指定できる
(型クラス Show を
derive した場合) 出力
が整形される
? レコード構文が役に立つケース
? フィールドが複数あって、
? どれがどれに対応するのかわかりにくい场合
型引数
Type Parameters
data Maybe a = Nothing | Just a
型コンストラクター
型引数
? 値コンストラクターは、
? 値を引数に取り、
? 値を作る
? 型コンストラクターは、
? 型を引数に取り (型引数)、
? 型を作る
? Maybe は型ではなく、型コンストラクター
? Maybe Char は型
? Just ‘a’ は Maybe Char 型の値
? Nothing は Maybe a 型の値
? Maybe a は polymorphic な型
? Maybe Int, Maybe Char, etc. として振る舞える
型引数を取らなくても
(0個取っても)
型コンストラクターって
言うのかな?
Carをパラメーター化すると?
data Car a b c = Car { company :: a	
, model :: b	
, year :: c } deriving (Show)
tellCar :: (Show a) => Car String String a -> String	
tellCar (Car { company = c, model = m, year = y}) =	
"This " ++ c ++ " " ++ m ++ " was made in " ++ show y	
tellCar では year の型
しかパラメーター化さ
れてない
結局、ほとんどのケースで
Car String String Int 型を
使うことになりそう
型引数を使うと良いケース
? 値コンストラクターに含まれる型が、どんなも
のでも構わないケース
? ex) Maybe a, [a], Data.Map k a
データ宣言に型クラス制約は
加えない
data (Ord k) => Map k v = ...
このような制約は
(文法上は正しいが)
規約上、付けない
? 必要な関数の型宣言に付ければ済む
? 必要の無い関数の型宣言に付けないで済む
3次元ベクトルを表わす
Vector a 型 の場合
data Vector a = Vector a a a deriving (Show)	
!
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)	
!
dotProd :: (Num a) => Vector a -> Vector a -> a	
(Vector i j k) `dotProd` (Vector l m n) = i * l + j * m + k * n	
!
vmult :: (Num a) => Vector a -> a -> Vector a	
(Vector i j k) `vmult` m = Vector (i * m) (j * m) (k * m)	
型クラス制約は
付けない
関数の方に型クラ
ス制約を付ける
インスタンスの
自動導出
Derived Instances
型クラス
? オブジェクト指向プログラミングにおける「クラス」と混
同しないよう注意
? OOPのクラスは、そのクラスから作られたオブジェクト
が持つ性質を規定
? Haskell の型クラスは、型が型クラスのインスタンスにな
り、その型の性質を定義する
? deriving キーワードを使って、ある型を型クラスのインスタ
ンスにすることができる
data Person = Person { firstName :: String	
, lastName :: String	
, age :: Int	
} deriving (Eq)
1. Person型の値同士を == または /= で比べた時、マッチする値コンスト
ラクターを探す
2. 見付かった値コンストラクターのフィールド同士を、それぞれ == また
は /= で比べる
? 全てのフィールドの型が Eq のインスタンスでなければならない
mikeD = Person { firstName = "Michael"	
, lastName = "Diamond"	
, age = 43 }	
!
adRock = Person { firstName = "Adam"	
, lastName = "Horovitz"	
, age = 41 }	
!
mca = Person { firstName = "Adam"	
, lastName = "Yauch"	
, age = 44 }	
ghci> mikeD == adRock	
False	
ghci> mikeD == mikeD	
True	
ghci> mikeD == Person { firstName = "Michael", lastName = "Diamond", age = 43 }	
True
? Eq
? equality / inequality についてテストできる
? Show
? 値をStringへ変換できる
? Read
? Stringをパーズして値を作れる
? Ord
? 大小比較、順序付けできる
? Bounded
? 上限 (maxBound) 、下限 (minBound) がある
? Enum
? 順番に列挙することができる
data Person = Person { firstName :: String	
, lastName :: String	
, age :: Int	
} deriving (Eq, Show, Read)	
!
mikeD = Person { firstName = "Michael"	
, lastName = "Diamond"	
, age = 43 }	
!
mysteryDude = "Person { firstName = "Michael"" ++	
", lastName = "Diamond"" ++	
", age = 43}"	
ghci> read mysteryDude :: Person	
Person {firstName = "Michael", lastName = "Diamond", age = 43}	
ghci> read mysteryDude == mikeD	
True	
String 型を read
して Person 型に
型クラス Show の show が使えるので、
値をGHCi コンソールに出力できる
data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday	
deriving (Eq, Ord, Show, Read, Bounded, Enum)	
!
λ> Saturday > Sunday	
False	
λ> Monday `compare` Wednesday	
LT	
λ> minBound :: Day	
Monday	
λ> maxBound :: Day	
Sunday	
λ> succ Monday	
Tuesday	
λ> pred $ succ Monday	
Monday	
λ> [Thursday .. Sunday]	
[Thursday,Friday,Saturday,Sunday]	
λ> [minBound .. maxBound] :: [Day]	
[Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday]	
Ord による大小比較
Bound による上限
と下限
Enum による順次的な
列挙
上限、下限を利用した、
順次的な列挙
型シノニム
Type Synonyms
type String = [Char]
? 既存の型の別名を定義
? 新しい型が作られるのではない
type PhoneNumber = String	
type Name = String	
type PhoneBook = [(Name,PhoneNumber)]
inPhoneBook :: Name -> PhoneNumber -> PhoneBook -> Bool	
inPhoneBook name pnumber pbook = (name, pnumber) `elem` pbook
より明確な意図を伝える
型シグネチャー
!
!
!
book = [("betty", "555-2938")	
,("bonnie", "452-2928")	
,("patsy", "493-2928")	
,("lucille", "205-2928")	
,("wendy", "939-8282")	
,("penny", "853-2492")	
]	
λ> inPhoneBook "wendy" "939-8282" book	
True
型シノニムの型パラメーター化
type AssocList k v = [(k, v)]
type IntMap v = Map Int v
型パラメーターを持つ
型シノニムの定義
型パラメーターを
部分適用した型シノニム
AssocList, IntMap は
型コンストラクターになる
!
値コンストラクターと
混同しないよう注意
data Either a b = Left a | Right b	
deriving (Eq, Ord, Read, Show)
? ある型か他のある型の値を表現
? Maybe a と同様に、処理の結果を表わすのに
よく使われる
? 失敗した場合もデータを保持できるのが違
い
ロッカーの例
import qualified Data.Map as Map	
!
data LockerState = Taken | Free deriving (Show, Eq)	
!
type Code = String	
!
type LockerMap = Map.Map Int (LockerState, Code)	
!
lockerLookup :: Int -> LockerMap -> Either String Code	
lockerLookup lockerNumber map = case Map.lookup lockerNumber map of	
Nothing -> Left $ "Locker " ++ show lockerNumber ++ " doesn't exist!"	
Just (state, code) -> if state /= Taken	
then Right code	
else Left $ "Locker " ++ show lockerNumber ++ " is already taken!"	
!
lockers :: LockerMap	
lockers = Map.fromList	
[(100,(Taken, "ZD39I"))	
,(101,(Free,"JAH3I"))	
,(103,(Free,"IQSA9"))	
,(105,(Free,"QOTSA"))	
,(109,(Taken,"893JJ"))	
,(110,(Taken,"99292"))]
練習問題
? 上のような構造を持つ、URIを表現する型を作ってみましょう
? query は複数の key, value のペアを持ちます
? 必須の要素とオプショナルの要素があることに注意して下さい
https://user:password@example.com:80/path/somewhere?foo=bar#baz
scheme userinfo host port path query fragment
authority
Ad

Recommended

Ruby 3の型推論やってます
Ruby 3の型推論やってます
mametter
?
すごいHaskell 第7章 型や型クラスを自分で作ろう(前編)
すごいHaskell 第7章 型や型クラスを自分で作ろう(前編)
Nozomu Kaneko
?
Scala の関数型フ?ロク?ラミンク?を支える技術
Scala の関数型フ?ロク?ラミンク?を支える技術
Naoki Aoyama
?
Algebraic DP: 動的計画法を書きやすく
Algebraic DP: 動的計画法を書きやすく
Hiromi Ishii
?
今から始める Lens/Prism
今から始める Lens/Prism
Naoki Aoyama
?
Scalaz
Scalaz
Kota Mizushima
?
颁辞肠辞补勉强会201208
颁辞肠辞补勉强会201208
Satoshi Oomori
?
20141128 iOSチーム勉強会 My Sweet Swift
20141128 iOSチーム勉強会 My Sweet Swift
necocen
?
Object-Funcational Analysis and design
Object-Funcational Analysis and design
Tomoharu ASAMI
?
What Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミット
Taisuke Oe
?
実务者のためのかんたん厂肠补濒补锄
実务者のためのかんたん厂肠补濒补锄
Tomoharu ASAMI
?
MP in Scala
MP in Scala
Kent Ohashi
?
Strings and Characters in Swift
Strings and Characters in Swift
Goichi Hirakawa
?
颁++コミュニティーの中心で颁++を顿滨厂る
颁++コミュニティーの中心で颁++を顿滨厂る
Hideyuki Tanaka
?
すごいHaskell楽しく学ぼう 第6章
すごいHaskell楽しく学ぼう 第6章
aomori ringo
?
MP in Haskell
MP in Haskell
Kent Ohashi
?
Haskell勉強会2 in ie
Haskell勉強会2 in ie
maeken2010
?
Scalaの文字列処理 Day 3 コードポイントとサロゲートペア
Scalaの文字列処理 Day 3 コードポイントとサロゲートペア
ynupc
?
Haskell Lecture 2
Haskell Lecture 2
Yusuke Matsushita
?
オブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional Programming
Tomoharu ASAMI
?
明日から业务て?使う厂肠补濒补
明日から业务て?使う厂肠补濒补
martin_lover_ca
?
础耻虫パターンを顿辞迟迟测で解决する
础耻虫パターンを顿辞迟迟测で解决する
Taisuke Oe
?
Object-Functional Analysis and Design and Programming温泉
Object-Functional Analysis and Design and Programming温泉
Tomoharu ASAMI
?
すごい贬补蝉办别濒濒読书会
すごい贬补蝉办别濒濒読书会
Kosuke Usami
?
すごい Haskell 読書会 in 大阪 #5
すごい Haskell 読書会 in 大阪 #5
Kazkuki Oakamoto
?

More Related Content

What's hot (20)

Object-Funcational Analysis and design
Object-Funcational Analysis and design
Tomoharu ASAMI
?
What Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミット
Taisuke Oe
?
実务者のためのかんたん厂肠补濒补锄
実务者のためのかんたん厂肠补濒补锄
Tomoharu ASAMI
?
MP in Scala
MP in Scala
Kent Ohashi
?
Strings and Characters in Swift
Strings and Characters in Swift
Goichi Hirakawa
?
颁++コミュニティーの中心で颁++を顿滨厂る
颁++コミュニティーの中心で颁++を顿滨厂る
Hideyuki Tanaka
?
すごいHaskell楽しく学ぼう 第6章
すごいHaskell楽しく学ぼう 第6章
aomori ringo
?
MP in Haskell
MP in Haskell
Kent Ohashi
?
Haskell勉強会2 in ie
Haskell勉強会2 in ie
maeken2010
?
Scalaの文字列処理 Day 3 コードポイントとサロゲートペア
Scalaの文字列処理 Day 3 コードポイントとサロゲートペア
ynupc
?
Haskell Lecture 2
Haskell Lecture 2
Yusuke Matsushita
?
オブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional Programming
Tomoharu ASAMI
?
明日から业务て?使う厂肠补濒补
明日から业务て?使う厂肠补濒补
martin_lover_ca
?
础耻虫パターンを顿辞迟迟测で解决する
础耻虫パターンを顿辞迟迟测で解决する
Taisuke Oe
?
Object-Functional Analysis and Design and Programming温泉
Object-Functional Analysis and Design and Programming温泉
Tomoharu ASAMI
?
Object-Funcational Analysis and design
Object-Funcational Analysis and design
Tomoharu ASAMI
?
What Dotty fixes @ Scala関西サミット
What Dotty fixes @ Scala関西サミット
Taisuke Oe
?
実务者のためのかんたん厂肠补濒补锄
実务者のためのかんたん厂肠补濒补锄
Tomoharu ASAMI
?
Strings and Characters in Swift
Strings and Characters in Swift
Goichi Hirakawa
?
颁++コミュニティーの中心で颁++を顿滨厂る
颁++コミュニティーの中心で颁++を顿滨厂る
Hideyuki Tanaka
?
すごいHaskell楽しく学ぼう 第6章
すごいHaskell楽しく学ぼう 第6章
aomori ringo
?
Haskell勉強会2 in ie
Haskell勉強会2 in ie
maeken2010
?
Scalaの文字列処理 Day 3 コードポイントとサロゲートペア
Scalaの文字列処理 Day 3 コードポイントとサロゲートペア
ynupc
?
オブジェクト指向開発におけるObject-Functional Programming
オブジェクト指向開発におけるObject-Functional Programming
Tomoharu ASAMI
?
明日から业务て?使う厂肠补濒补
明日から业务て?使う厂肠补濒补
martin_lover_ca
?
础耻虫パターンを顿辞迟迟测で解决する
础耻虫パターンを顿辞迟迟测で解决する
Taisuke Oe
?
Object-Functional Analysis and Design and Programming温泉
Object-Functional Analysis and Design and Programming温泉
Tomoharu ASAMI
?

Similar to すごい贬补蝉办别濒濒読书会 第7章 (前編) (20)

すごい贬补蝉办别濒濒読书会
すごい贬补蝉办别濒濒読书会
Kosuke Usami
?
すごい Haskell 読書会 in 大阪 #5
すごい Haskell 読書会 in 大阪 #5
Kazkuki Oakamoto
?
How wonderful to be (statically) typed ?型が付くってスバラシイ?
How wonderful to be (statically) typed ?型が付くってスバラシイ?
Hiromi Ishii
?
すごいH 第12章モノイド
すごいH 第12章モノイド
Shinta Hatatani
?
第3章 型とクラス
第3章 型とクラス
Yasuaki Takebe
?
第3章 型とクラス
第3章 型とクラス
Yasuaki Takebe
?
すごいHaskell 第7章 型や型クラスを自分で作ろう(後編)
すごいHaskell 第7章 型や型クラスを自分で作ろう(後編)
Nozomu Kaneko
?
すごい贬补蝉办别濒濒楽しく学ぼう-第12章モノイド-
すごい贬补蝉办别濒濒楽しく学ぼう-第12章モノイド-
Hiromasa Ohashi
?
Haskell Lecture 1
Haskell Lecture 1
Yusuke Matsushita
?
スタートHaskell2 型を信じろ
スタートHaskell2 型を信じろ
Satoshi KOJIMA
?
すごい贬补蝉办别濒濒読书会 in 大阪 #6
すごい贬补蝉办别濒濒読书会 in 大阪 #6
cojna
?
厂肠补濒补で型クラス入门
厂肠补濒补で型クラス入门
Makoto Fukuhara
?
厂肠补濒补プログラミング?マニアックス
厂肠补濒补プログラミング?マニアックス
Tomoharu ASAMI
?
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
Shin-ya Koga
?
初めてのHaskell (表)
初めてのHaskell (表)
karky7
?
Processingによるプログラミング入門 第6回
Processingによるプログラミング入門 第6回
Ryo Suzuki
?
Vim scriptとJavaとHaskell
Vim scriptとJavaとHaskell
aiya000
?
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~
Nobuhisa Koizumi
?
すごい贬补蝉办别濒濒読书会
すごい贬补蝉办别濒濒読书会
Kosuke Usami
?
すごい Haskell 読書会 in 大阪 #5
すごい Haskell 読書会 in 大阪 #5
Kazkuki Oakamoto
?
How wonderful to be (statically) typed ?型が付くってスバラシイ?
How wonderful to be (statically) typed ?型が付くってスバラシイ?
Hiromi Ishii
?
すごいH 第12章モノイド
すごいH 第12章モノイド
Shinta Hatatani
?
すごいHaskell 第7章 型や型クラスを自分で作ろう(後編)
すごいHaskell 第7章 型や型クラスを自分で作ろう(後編)
Nozomu Kaneko
?
すごい贬补蝉办别濒濒楽しく学ぼう-第12章モノイド-
すごい贬补蝉办别濒濒楽しく学ぼう-第12章モノイド-
Hiromasa Ohashi
?
スタートHaskell2 型を信じろ
スタートHaskell2 型を信じろ
Satoshi KOJIMA
?
すごい贬补蝉办别濒濒読书会 in 大阪 #6
すごい贬补蝉办别濒濒読书会 in 大阪 #6
cojna
?
厂肠补濒补で型クラス入门
厂肠补濒补で型クラス入门
Makoto Fukuhara
?
厂肠补濒补プログラミング?マニアックス
厂肠补濒补プログラミング?マニアックス
Tomoharu ASAMI
?
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
2014年の社内新人教育テキスト #2(関数型言語からオブジェクト指向言語へ)
Shin-ya Koga
?
初めてのHaskell (表)
初めてのHaskell (表)
karky7
?
Processingによるプログラミング入門 第6回
Processingによるプログラミング入門 第6回
Ryo Suzuki
?
Vim scriptとJavaとHaskell
Vim scriptとJavaとHaskell
aiya000
?
F#入門 ~関数プログラミングとは何か~
F#入門 ~関数プログラミングとは何か~
Nobuhisa Koizumi
?
Ad

すごい贬补蝉办别濒濒読书会 第7章 (前編)

  • 1. 型や型クラスを自分で 作ろう (前編) すごい贬补蝉办别濒濒読书会 in 大阪 2週目 #7 2014-07-16 Suguru Hamazaki Making Our Own Types and Type Classes
  • 5. data Bool = False | True 型名 値コンスト ラクター 値コンスト ラクター
  • 6. data Int = -2147483648 | -2147483647 | ... | -1 | 0 | 1 | 2 | ... | 2147483647 実際の定義とは異なるが、 このように考えられる
  • 8. ? Shape型 ? 2次元上の円と長方形を表現する ? area関数 ? Shape型のデータの面積を求める
  • 9. data Shape = Circle Float Float Float | Rectangle Float Float Float Float deriving (Show) 型名 値コンスト ラクター 値コンスト ラクター
  • 10. 値コンストラクター ? 値を作るので、値コンストラクター ? 実際には関数の一種 ? ex) Circle は Float 型の値を3つ引数として受け取り、Shape 型の値を返す関数 ? ex) False は? ? 型と値コンストラクターを混同しないよう注意 ? 型名と値コンストラクターの名前が同じでもよい Value Constructors
  • 11. area :: Shape -> Float area (Circle _ _ r) = pi * r ^ 2 area (Rectangle x1 y1 x2 y2) = (abs $ x2 - x1) * (abs $ y2 - y1) 型シグネチャーには、 型名であるShape を使う (Circle や Rectangle は型名ではない) パターンマッチには コンストラクターが使える
  • 12. ? Point型 ? Circle, Rectangle のフィールドを構成する中間的な 型 ? nudge関数 ? Shape型のデータを移動 ? baseCircle, baseRect関数 ? ファクトリー的なもの
  • 13. data Point = Point Float Float deriving (Show) data Shape = Circle Point Float | Rectangle Point Point deriving (Show) Circle, Rectangle のフィールドを Point 型で定義して整理
  • 14. area :: Shape -> Float area (Circle _ r) = pi * r ^ 2 area (Rectangle (Point x1 y1) (Point x2 y2)) = (abs $ x2 - x1) * (abs $ y2 - y1) パターンマッチも 若干すっきり (?)
  • 15. nudge :: Shape -> Float -> Float -> Shape nudge (Circle (Point x y) r) a b = Circle (Point (x + a) (y + b)) r nudge (Rectangle (Point x1 y1) (Point x2 y2)) a b = Rectangle (Point (x1 + a) (y1 + b)) (Point (x2 + a) (y2 + b)) ! baseCircle :: Float -> Shape baseCircle r = Circle (Point 0 0) r ! baseRect :: Float -> Float -> Shape baseRect width height = Rectangle (Point 0 0) (Point width height) baseCircle baseRectangle
  • 16. モジュールからエクスポート module Shapes ( Point(..) , Shape(..) , area , nudge , baseCircle , baseRect ) where 値コンストラクターを 全てエクスポートする記法 明示的に列挙してもよい
  • 19. data Person = Person String String Int Float String String deriving (Show) ! firstName :: Person -> String firstName (Person firstname _ _ _ _ _) = firstname ! lastName :: Person -> String lastName (Person _ lastname _ _ _ _) = lastname ! age :: Person -> Int age (Person _ _ age _ _ _) = age ! height :: Person -> Float height (Person _ _ _ height _ _) = height ! phoneNumber :: Person -> String phoneNumber (Person _ _ _ _ number _) = number ! flavor :: Person -> String flavor (Person _ _ _ _ _ flavor) = flavor
  • 20. data Person = Person { firstName :: String , lastName :: String , age :: Int , height :: Float , phoneNumber :: String , flavor :: String } deriving (Show) それぞれ、フィールド名とその 型名を指定する ghci> :t firstName firstName :: Person -> String 対応する関数が自動的 に作られる
  • 21. data Car = Car { company :: String , model :: String , year :: Int } deriving (Show) ghci> Car { company = "Ford", model = "Mustang", year = 1967} Car {company = "Ford", model = "Mustang", year = 1967} ghci> Car { company = "Ford", year = 1967, model = "Mustang"} Car {company = "Ford", model = "Mustang", year = 1967} フィールドを任意の順 番で指定できる (型クラス Show を derive した場合) 出力 が整形される
  • 22. ? レコード構文が役に立つケース ? フィールドが複数あって、 ? どれがどれに対応するのかわかりにくい场合
  • 24. data Maybe a = Nothing | Just a 型コンストラクター 型引数
  • 25. ? 値コンストラクターは、 ? 値を引数に取り、 ? 値を作る ? 型コンストラクターは、 ? 型を引数に取り (型引数)、 ? 型を作る
  • 26. ? Maybe は型ではなく、型コンストラクター ? Maybe Char は型 ? Just ‘a’ は Maybe Char 型の値 ? Nothing は Maybe a 型の値 ? Maybe a は polymorphic な型 ? Maybe Int, Maybe Char, etc. として振る舞える
  • 28. Carをパラメーター化すると? data Car a b c = Car { company :: a , model :: b , year :: c } deriving (Show) tellCar :: (Show a) => Car String String a -> String tellCar (Car { company = c, model = m, year = y}) = "This " ++ c ++ " " ++ m ++ " was made in " ++ show y tellCar では year の型 しかパラメーター化さ れてない 結局、ほとんどのケースで Car String String Int 型を 使うことになりそう
  • 30. データ宣言に型クラス制約は 加えない data (Ord k) => Map k v = ... このような制約は (文法上は正しいが) 規約上、付けない ? 必要な関数の型宣言に付ければ済む ? 必要の無い関数の型宣言に付けないで済む
  • 31. 3次元ベクトルを表わす Vector a 型 の場合 data Vector a = Vector a a a deriving (Show) ! 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) ! dotProd :: (Num a) => Vector a -> Vector a -> a (Vector i j k) `dotProd` (Vector l m n) = i * l + j * m + k * n ! vmult :: (Num a) => Vector a -> a -> Vector a (Vector i j k) `vmult` m = Vector (i * m) (j * m) (k * m) 型クラス制約は 付けない 関数の方に型クラ ス制約を付ける
  • 33. 型クラス ? オブジェクト指向プログラミングにおける「クラス」と混 同しないよう注意 ? OOPのクラスは、そのクラスから作られたオブジェクト が持つ性質を規定 ? Haskell の型クラスは、型が型クラスのインスタンスにな り、その型の性質を定義する ? deriving キーワードを使って、ある型を型クラスのインスタ ンスにすることができる
  • 34. data Person = Person { firstName :: String , lastName :: String , age :: Int } deriving (Eq) 1. Person型の値同士を == または /= で比べた時、マッチする値コンスト ラクターを探す 2. 見付かった値コンストラクターのフィールド同士を、それぞれ == また は /= で比べる ? 全てのフィールドの型が Eq のインスタンスでなければならない
  • 35. mikeD = Person { firstName = "Michael" , lastName = "Diamond" , age = 43 } ! adRock = Person { firstName = "Adam" , lastName = "Horovitz" , age = 41 } ! mca = Person { firstName = "Adam" , lastName = "Yauch" , age = 44 } ghci> mikeD == adRock False ghci> mikeD == mikeD True ghci> mikeD == Person { firstName = "Michael", lastName = "Diamond", age = 43 } True
  • 36. ? Eq ? equality / inequality についてテストできる ? Show ? 値をStringへ変換できる ? Read ? Stringをパーズして値を作れる ? Ord ? 大小比較、順序付けできる ? Bounded ? 上限 (maxBound) 、下限 (minBound) がある ? Enum ? 順番に列挙することができる
  • 37. data Person = Person { firstName :: String , lastName :: String , age :: Int } deriving (Eq, Show, Read) ! mikeD = Person { firstName = "Michael" , lastName = "Diamond" , age = 43 } ! mysteryDude = "Person { firstName = "Michael"" ++ ", lastName = "Diamond"" ++ ", age = 43}" ghci> read mysteryDude :: Person Person {firstName = "Michael", lastName = "Diamond", age = 43} ghci> read mysteryDude == mikeD True String 型を read して Person 型に 型クラス Show の show が使えるので、 値をGHCi コンソールに出力できる
  • 38. data Day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday deriving (Eq, Ord, Show, Read, Bounded, Enum) !
  • 39. λ> Saturday > Sunday False λ> Monday `compare` Wednesday LT λ> minBound :: Day Monday λ> maxBound :: Day Sunday λ> succ Monday Tuesday λ> pred $ succ Monday Monday λ> [Thursday .. Sunday] [Thursday,Friday,Saturday,Sunday] λ> [minBound .. maxBound] :: [Day] [Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday] Ord による大小比較 Bound による上限 と下限 Enum による順次的な 列挙 上限、下限を利用した、 順次的な列挙
  • 41. type String = [Char] ? 既存の型の別名を定義 ? 新しい型が作られるのではない
  • 42. type PhoneNumber = String type Name = String type PhoneBook = [(Name,PhoneNumber)] inPhoneBook :: Name -> PhoneNumber -> PhoneBook -> Bool inPhoneBook name pnumber pbook = (name, pnumber) `elem` pbook より明確な意図を伝える 型シグネチャー
  • 43. ! ! ! book = [("betty", "555-2938") ,("bonnie", "452-2928") ,("patsy", "493-2928") ,("lucille", "205-2928") ,("wendy", "939-8282") ,("penny", "853-2492") ] λ> inPhoneBook "wendy" "939-8282" book True
  • 44. 型シノニムの型パラメーター化 type AssocList k v = [(k, v)] type IntMap v = Map Int v 型パラメーターを持つ 型シノニムの定義 型パラメーターを 部分適用した型シノニム AssocList, IntMap は 型コンストラクターになる ! 値コンストラクターと 混同しないよう注意
  • 45. data Either a b = Left a | Right b deriving (Eq, Ord, Read, Show) ? ある型か他のある型の値を表現 ? Maybe a と同様に、処理の結果を表わすのに よく使われる ? 失敗した場合もデータを保持できるのが違 い
  • 47. import qualified Data.Map as Map ! data LockerState = Taken | Free deriving (Show, Eq) ! type Code = String ! type LockerMap = Map.Map Int (LockerState, Code) ! lockerLookup :: Int -> LockerMap -> Either String Code lockerLookup lockerNumber map = case Map.lookup lockerNumber map of Nothing -> Left $ "Locker " ++ show lockerNumber ++ " doesn't exist!" Just (state, code) -> if state /= Taken then Right code else Left $ "Locker " ++ show lockerNumber ++ " is already taken!" ! lockers :: LockerMap lockers = Map.fromList [(100,(Taken, "ZD39I")) ,(101,(Free,"JAH3I")) ,(103,(Free,"IQSA9")) ,(105,(Free,"QOTSA")) ,(109,(Taken,"893JJ")) ,(110,(Taken,"99292"))]
  • 48. 練習問題 ? 上のような構造を持つ、URIを表現する型を作ってみましょう ? query は複数の key, value のペアを持ちます ? 必須の要素とオプショナルの要素があることに注意して下さい https://user:password@example.com:80/path/somewhere?foo=bar#baz scheme userinfo host port path query fragment authority