top page > computer > haskell > web_lecture > for_programmer > type_synonym.html
更新日:
文責: 重城良国

型シノニム

原点からの距離再び

コーディング

原点からの距離を求めよう。型宣言書いて関数定義書いて...

dist0 :: (Double, Double) -> Double
dist0 (x, y) = sqrt $ x ^ 2 + y ^ 2

ghci points.hs
*Main> dist0 (3, 4)
5.0

ある点(x, y)が中心(x0, y0)の半径rの円内にあるかどうかをチェックする関数を書こう。

inCircle :: (Double, Double) -> Double -> (Double, Double) -> Bool
inCircle (x0, y0) r (x, y) = (x - x0) ^ 2 + (y - y0) ^ 2 <= r ^ 2

*Main> :reload
*Main> inCircle (3, 8) 5 (5, 7)
True
*Main> inCircle (4, 5) 3 (10, -8)
False

(Double, Double)は点の表現なので今後も何度も書くよね。めんどくさい。

そこで型シノニムですよ

型の別名が定義できる。

type Point = (Double, Double)

すると上記の2つの型宣言は以下のように書ける。

dist0 :: Point -> Double

inCircle :: Point -> Double -> Point -> Bool

すっきりした。

構文

type [型の別名] = [型]

[型]の部分は例のように複合的な型でも良い。

アンケートの結果

問題定義

2つのうちのどちらかを選ぶアンケートを実施した。「象とキリンなら象が好きだ(Yes/No)」のようなアンケートだ。質問のリストと答えのリストがある。結果を保存し必要に応じて好きなものリストと嫌いなものリストを抽出できるようにしよう。

質問の型

質問のリストは文字列のペアのリストで良さそうだ。

type Questions = [(String, String)]

同じアンケートを番号つきの商品について行うとする。オフィス用品を扱う会社で椅子の商品番号は112でソファは113だとする。そして以下のようなアンケートをするとする。「椅子(No. 112)とソファ(No. 113)では椅子のほうが望ましい(Yes/No)」。この場合以下のような型シノニムとなるだろう。

type Questions = [((Int, String), (Int, String))]

アンケートの結果を選ぶ場合、選択肢の型は何であっても良い。よってこれらの型は以下のようにしてまとめることができる。

type Questions a = [(a, a)]

こうしておけばただの文字列に対してはQuestions Stringとすれば良いし、商品番号つきの質問のリストに対してはQuestions (Int, String)とすれば良い。

解答の型と保存される結果の型

解答はYesとNoのリストなので以下のようになる。

type Answers = [Bool]

保存される結果の型は解答と質問を結合したものなので以下のようにする。

type Results a = [(Bool, (a, a))]

質問と答えの例1

questions1 :: Questions String
questions1 = [
("Elephant", "Giraffe"),
("Apple", "Banana"),
("TV", "Radio"),
("Plane", "Ship"),
("Tennis", "Ski") ]

answers1 :: Answers
answers1 = [True, False, True, True, False]

質問と答えから結果を作成する

result :: Quentions a -> Answers -> Results a
result = flip zip

好きなものリスト、嫌いなものリスト

likes, hates :: Results a -> [a]
likes = map $ \(a, s) -> (if a then fst else snd) s

hates = map $ \(a, s) -> (if a then snd else fst) s

例1で試す

ghci survey.hs
*Main> result questions1 answers1
[(True, ("Elephant", "Giraffe"), ...]
*Main> let r = it
*Main> likes r
["Elephant", "Banana", "TV", "Plane", "Ski"]
*Main> hates r
["Giraffe", "Apple", "Radio", "Ship", "Tennis"]

質問と答えの例2

questions2 :: Questions (Int, String)
questions2 = [
((112, "Chair"), (113, "Sofa")),
((343, "Telephone"), (344, "Fax")),
((522, "Projector"), (523, "Monitor")) ]

answers2 :: Answers
answers2 = [False, True, True]

例2を試す

*Main> :reload
*Main> result questions2 answers2
[(False, ((112, "Chair"), (113, "Sofa"))), ...]
*Main> let r = it
*Main> likes r
[(113, "Sofa"), (343, "Telephone"), (522, "Projector")]
*Main> hates r
[(112, "Chair"), (344, "Fax"), (523, "Monitor")]

メモ

構文

型シノニムは型引数をとることができる。型引数は複数あっても良い。

type [型名] [型変数1] [型変数2] ... = [型]

[型]のなかでは[型変数1], [型変数2] ... が使える。

まとめ

型には別名(シノニム)がつけられる。型シノニムは型引数をとることができる。

「関数fst, snd」へもどる 「構文: レイアウトルール」へ

正当なCSSです! HTML5 Powered with CSS3 / styling, and Semantics