LYH 7.6 型シノニム

新しい型を作る = ( 1 ) キーワード
型同義名(型シノニム)を作る = ( 2 ) キーワード

例えば、Stringは以下ように型シノニムとして定義されている。

type String = [Char]

電話帳を定義してみよう。

type PhoneNumber = String
type Name = String
type PhoneBook = [(Name, PhoneNumber)]

pbook :: PhoneBook
pbook = [
  ("betty", "555-2938"),
  ("bonnie", "452-2928"),
  ...
]

inPhoneBook :: (  3  )
inPhoneBook name pnumber pbook = (name, pnumber) `elem` pbook
型シノニムの多相化
type AssocList (  4  ) = [(k, v)]

とすることで、型引数を取ることができる。AssocListは ( 5 ) である。

以下の2つは同義

type (  6  )
type IntMap v = Map.Map Int v
そこを左に行って、すぐ右へ

Either a b は( 7 )を2つとるデータ型である。
Left, Right はそれぞれ( 8 )である。

ghci> Right 20
(  9  )

ghci> Left "w00t"
(  10  )

ghci> :t Right 'a'
(  11  )

ghci> :t Left True
(  12  )

Left True の型を評価すると ( 12 ) となっていることがわかる。Left ( 8 ) で作った値なので、1つ目の型引数は Bool に決まっているが、2つ目の型引数は ( 13 ) のまま残っている。これは、Nothing という値に ( 14 ) という型が付くのと同じ理屈である。

Nothing は何故失敗したかの情報を持つことはできない。これを持てるようにするために、普通は ( 15 ) 型の返り値を使う。ここで、( 16 ) は失敗が起こった場合に何であるかを伝えてくれる型、( 17 ) は、成功した計算の型である。したがって、エラーは ( 18 ) を、結果は ( 19 ) を使って表す。

ロッカーの割当のコードを書け。( 20 )
ロッカーを表すMapから暗証番号を検索する関数を作りたい。
関数が失敗するパターンが、( 21 ) と、( 22 ) の2通りあるので、( 23 ) 型で表すようにする。
実際に、暗証番号を検索する関数を作れ。( 24 )

解答

1. data
2. type
3. Name -> PhoneNumber -> PhoneBook -> Bool
4. k v
5. 型コンストラクタ
6. IntMap = Map.Map Int
7. 型引数
8. 値コンストラクタ
9 Right 20
10. Left "w00t"
11. Right 'a' :: Either a Char
12. Left True :: Either Bool b
13. 多相
14. Maybe a
15. Eihter a b
16. a
17. b
18. Left 値コンストラクタ
19. Right 値コンストラクタ
20.
ロッカーが使用中かどうかのフラグとロッカーへの暗証番号へのMapで表す。

import qualified Data.Map as Map
data LockerState = Taken | Free deriving (Show, Eq)
type Code = String
type LockerMap = Map.Map Int (LockerState, Code)

21. ロッカーを他の誰かが使っている場合
22. ロッカー番号が存在しない場合
23. Either String Code
24.

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!"