Xeebi

home categories feeds

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::PhoneNumbert::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 に至ります.二分木は飛ばす.

過去記事: 第1回 /第2回 /第3回 /第4回 /今回

  1. Eq 配下にないものでもできるのはそういうわけだ