型シノニムの多相化
型シノニムに型引数をとることができる
type AssocList k v = [(k, v)]
型引数を部分適用すると新しい型コンストラクタが作れる
type IntMap v = Map Int v
こうも書ける
type IntMap = Map Int
Data.Map
を修飾付インポートをする時は型コンストラクタの前にもモジュール名付ける必要がある。
type IntMap = Map.Map Int
Haskell のソースコードは値の領域、型の領域に分かれている。
- 型の領域
- データ型
- 型シノニムの宣言
- 型宣言や型注釈の
::
の右側
Either型
Either は型引数を2つとる。定義は以下
data Either a b = Left a | Right b deriving (Eq, Ord, Read, Show)
Either型は2つの型のうちどちらか一方
という値を表現できる。
*Main> Right 20 Right 20 *Main> Left "w00t" Left "w00t" *Main> :t Right 'a' Right 'a' :: Either a Char *Main> :t Left True Left True :: Either Bool b
関数がなぜ失敗したのか、どのように失敗したのかを知りたい時にEither a b
型の返り値を使う。
a
は失敗が起こった場合に何であるかを伝えてくれる型、b
は成功した計算の型。
エラーはLeft
値コンストラクタ、結果はRight
値コンストラクタを使って表現する。
ロッカーをMapで表現する
import qualified Data.Map as Map data LockerState = Taken | Free deriving (Show, Eq) type Code = String type LockerMap = Map.Map Int (LockerState, Code)
ロッカーの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")) ,(102, (Free, "POEG3")) ,(105, (Free, "HUYT3")) ,(109, (Taken, "MMNB7")) ,(110, (Taken, "QWEU9"))]
検索する
*Main> lockerLookup 101 lockers Right "JAH3I" *Main> lockerLookup 100 lockers Left "Locker 100 is already taken!" *Main> lockerLookup 102 lockers Right "POEG3" *Main> lockerLookup 103 lockers Left "Locker 103 doesn't exist!"
結果を表現するのにMaybe a
を使うとロッカーの取得に失敗しても原因が伝わらない。
Either a b
を使うと失敗の情報も伝えることができる。
所感
データ型のパターンマッチで処理が分岐していく様がわかって楽しい。Either a b
型とMaybe a
型で何が表現できるのかというところの感覚をもう少し掴んでいく必要がある。この例に出てきた関数も自分で書くとなると難しそう。

- 作者: MiranLipovaca
- 出版社/メーカー: オーム社
- 発売日: 2017/07/14
- メディア: Kindle版
- 購入: 4人 クリック: 9回
- この商品を含むブログを見る