すごいHaskell六章 (後半6.3から終わりまで)
連想リスト
山場が来たぞー!ドコドコドコドコドコドコドコドコ
キー(Stringだけど)が重複してる(ペアのリスト型)連想リストにfindKey(Maybeでない)を使うとどうなるか。
phoneBook :: [(String, String)] phoneBook = [("betty", "555-2938") ,("bonnie", "452-2928") ,("bonnie", "452-2928") ]
findKey' :: (Eq k) => k -> [(k, v)] -> v findKey' key xs = snd .head .filter (\(k, _) -> key == k) $ xs
ghci> findKey "betty" phoneBook "555-2938" ghci> findKey "bonnie" phoneBook "452-2928" ghci> findKey' "penny" phoneBook "*** Exception: Prelude.head: empty list
実装がfilterしてheadだから最初の要素が返ってくるのか。
Maybe版findKey、ミスがあるな。ガード一つ目のところ、key == x じゃなくて key == kだ。
findKey :: (Eq k) => k -> [(k, v)] -> Maybe v findKey _ [] = Nothing findKey key ((k,v):xs) | key == k = Just v | otherwise = findKey key xs
実行してみる。
ghci> findKey "betty" phoneBook Just "555-2938" ghci> findKey "bonnie" phoneBook Just "452-2928" ghci> findKey "penny" phoneBook Nothing
こっちも重複したキーは、最初に一致したキーの値が返ってくる。
リストに対するふつうな再帰パターン(リストの先頭要素headを取り出して、残りtailを再帰)だと、再帰より畳込みで書いた方がいいらしい。
ここのfindKeyの畳込みはかっこいいので引用する。
findKey :: (Eq k) => k -> [(k, v)] -> Maybe v findKey key xs = foldr (\(k,v) acc -> if key == k then Just v else acc) Nothing xs
ガードの条件文をif文にして畳込みの関数に渡しちゃうんだな。そして、アキュムレータの初期値は再帰の基低部を使う。
いまさらだけど、このスタイルシートだとソースコードの引用がものすごく見づらくなるのなんとかしたい。→スタイルシート変えた。
Map.Map
なんかMapをimportしようとすると警告が出る。
import qualified Data.Map as Map
ghci> :l imports.hs [1 of 1] Compiling Main ( imports.hs, interpreted ) imports.hs:6:1: Warning: The import of `Data.Map' is redundant except perhaps to import instances from `Data.Map' To import instances alone, use: import Data.Map() <no location info>: Failing due to -Werror. Failed, modules loaded: none.
インスタンスをimportする時以外冗長だって言われてる。うーむ。
でもData.Map()でimportするとasが使えないっぽい。警告を抑制する方法がいるな。
などと言いつつ -Werror オプションを外すことにした。
なんでMapの時だけ警告が出るんだろう。
とりあえず、これで進められるようになった。
(追記)コードの中でMap.Mapを使ったら出なくなった。使われてないモジュールをimportするなってことだったのかな。
fromListの表示がfromListだったりMapの表示もMap.Mapだったりするのあんまり納得いかない…
こういうの
ghci> :t Map.fromList Map.fromList :: Ord k => [(k, a)] -> Map.Map k a
Map.mapが関数を適用するのは、キーじゃなくて値の方だけなのかな。
ghci> Map.map string2digits ( Map.fromList [("234", "123")]) fromList [("234",[1,2,3])]
ぽいな。こういうデータ構造だと大抵、キーは変更不可能になってるはずだしな。