Real World Haskell - 第6章 Using Typeclasses
Real World Haskell で Haskell を継続的に勉強中。
いろいろあって、しばらく間が空いてしまったが、なんとかペースを取り戻すぞ。
Chapter 6. Using Typeclasses
Chapter 6. Using Typeclasses
The need for typeclasses
- == のように異なる型を比較する場合でも同じ名前を使えると便利
- そういう generic なコードを書くのに typeclasses が使える
What are typeclasses?
typeclass の定義
class BasicEq a where isEqual :: a -> a -> Bool
instance の作成
instance BasicEq Bool where isEqual True True = True isEqual False False = True isEqual _ _ = False
default implementation を書ける
class BasicEq3 a where isEqual3 :: a -> a -> Bool isEqual3 x y = not (isNotEqual3 x y) isNotEqual3 :: a -> a -> Bool isNotEqual3 x y = not (isEqual3 x y)
Important Built-In Typeclasses
- Show
- 値を文字列に変換する
- ghci で表示するために使ってるよね
- putStrLn と使い分けましょう
- 値を文字列に変換する
- Read
- Show と反対に文字列をある型の値にする
- 型は明示的に指定すべし
main = do putStrLn "Please enter a Double:" inpStr <- getLine let inpDouble = (read inpStr)::Double putStrLn ("Twice " ++ show inpDouble ++ " is " ++ show (inpDouble * 2))
Serialization with Read and Show
Show と Read はシリアライズに使える
Numeric Types
(+) なども typeclass で実装されている
Automatic Derivation
- 下記の typeclass については自動導出可能
- Read
- Show
- Bounded
- Enum
- Eq
- Ord
data Color = Red | Green | Blue deriving (Read, Show, Eq, Ord)
More helpful errors
- エラーを表示するのには Maybe より Either が便利
data Maybe a = Nothing | Just a deriving (Eq, Ord, Read, Show) data Either a b = Left a | Right b deriving (Eq, Ord, Read, Show)
Making an instance with a type synonym
- pragma を書けば GHC 拡張が使える
- typeclass の instance で型のシノニム (String など) を使いたい場合
{-# LANGUAGE TypeSynonymInstances #-}
Living in an open world
- open world assumption
- typeclass を定義した module に限らず、どこでも instance を定義できる
When do overlapping instances cause problems?
- instance の関数適用が曖昧になる場合はエラーが出る
- OverlappingInstances pragma を覚えておくべし
How to give a type a new identity
- 既存の型と同じように扱える別の型を newtype で定義できる
newtype NewtypeInt = N Int deriving (Eq, Ord, Show)
Differences between data and newtype declarations
-- ok: any number of fields and constructors data TwoFields = TwoFields Int Int -- ok: exactly one field newtype Okay = ExactlyOne Int -- ok: type parameters are no problem newtype Param a b = Param (Either a b) -- ok: record syntax is fine newtype Record = Record { getInt :: Int } -- bad: no fields newtype TooFew = TooFew -- bad: more than one field newtype TooManyFields = Fields Int Int -- bad: more than one constructor newtype TooManyCtors = Bad Int | Worse Int
Summary: the three ways of naming types
- data は代数データ型の定義に使う
- type は既存の型のシノニムの定義に使う
- 既存の型とシノニムは可換
- newtype は既存の型に別の名前を付ける
- 既存の型と新しい型は非可換
The dreaded monomorphism restriction
これはエラーになる
myShow = show
こうすると問題ない
myShow2 value = show value myShow3 :: (Show a) => a -> String myShow3 = show
- GHC が the monomorphism restriction でエラーを吐いた場合の対応方法
the monomorphism restriction について詳しく知りたいなら Haskell 98 Report を読むべし
The Haskell 98 Report: Declarations