Haskell: type と typeclass を作る (5)
前回の続き.
Learn You a Haskell for Great Good! の Chapter 8, Making Our Own Types and Typeclasses を元にしたものです.基本的には翻訳のつもりですが,省略や加筆が勝手に入ることもあります.原文は CC-BY-NC-SA でライセンスされており,この文書もそれに従います.
今回は Type synonyms から.
Type synonyms
[Char]
と String
って一緒で interchangeable じゃん,String
があるのはそのほうが見やすい/意味が通りやすいから.たとえば
toUpperString :: [Char] -> [Char]
よりは String -> String
のほうがわかりやすいでしょ.
これはこういう感じで実現されている
type String = [Char]
それから電話帳なんかも,この本の前のところでは
phoneBook :: [(String, String)]
phoneBook =
[
("Betty", "000-0000"),
("Richard", "111-1111")
]
こんな感じで書いてたけど phoneBook :: [(String, String)]
では紛らわしい.
そこで
type PhoneNumber = String
type Name = String type PhoneBook = [(Name, PhoneNumber)]
とするとわかりやすいし phoneBook :: PhoneBook
と出来て幸せだ.
因みに,この type synonym
は本当に synonym なので,例えば s::PhoneNumber
と t::String
とを (++)
で繋げたりするのは通る.
さて,この type synonym は例によって引数とるようにできて, 例えばこうだ
type AssociationList k v = [(k,v)]
こうすると例えば getItem みたいな函数は
(Eq k) => l -> AssociationList k v -> Maybe v
みたいな型を持つことになる .
実際の値が持つ型は AssociationList String Int
みたいな感じ.
わかりやすそうだ.
因みにこういう芸当も可能
type IntMap v = Map Int v
まあそらそうか,という感じですね.
さて,このあと原文のいろいろを飛ばしますが,recursive なデータ構造も作れるということを少し書いておきましょう.
リスト構造を模倣してみよう
data List a = Empty | Cons a (List a) deriving (Show, Read, Eq, Ord)
型変数が入っていることに気をつける. この段階ではこういうふうに使えて
ghci> 3 `Cons` (4 `Cons` (5 `Cons` Empty))
Cons 3 (Cons 4 (Cons 5 Empty))
いいんだけど括弧が面倒そう.演算子っぽい文字を使えば infixr
, infixl
で演算子としての結合度を決められる.
r
のほうが右結合ということで,その後の数字は優先度だ(ghci で :i (+)
とかやると色々見られるから試してみよう).
例えば *
は infixl 7
, +
は infixl 6
ということになっている.ご存知 $
は infixr 0
だ.
こうなる
infixr 5 :-:
data List a = Empty | a :-: (List a) deriving (Show, Read, Eq, Ord)
ghci> 3 :-: 4 :-: 5 :-: Empty
(:-:) 3 ((:-:) 4 ((:-:) 5 Empty))
Pattern match もいい感じにできる(あれはコンストラクタを比べている1):
infixr 5 .++
(.++) :: List a -> List a -> List a
Empty .++ ys = ys
(x :-: xs) .++ ys = x :-: (xs .++ ys)
このあと二分木を実装し, Typeclasses 102 に至ります.二分木は飛ばす.
–
-
Eq 配下にないものでもできるのはそういうわけだ ↩