Rubyには連想配列を表すHash
クラスが用意されており、文法上もHashを定義するリテラルが存在するなど手厚いサポートがされている。ではHaskellはどうか。Haskellでは連想配列はData.Map
モジュールで提供されている。今日はRubyのHash
と、HaskellのData.Map
の使い方を以下のRubyのコードを元に比較してゆきたい。
phoneBook = {"alice" => "1234-5678", "bob" => "2345-6789", "carol" => "3456-7890"}
p phoneBook["alice"] # => "1234-5678"
phoneBook.store("carol", "3456-7890")
p phoneBook["carol"] # => "3456-7890"
phoneBook.delete("bob")
p phoneBook["bob"] # => nil
このRubyのコードは、電話帳を操作するものだ。電話帳はHash
のインスタンスで表現し、名前をキーに、電話番号を値とする連想配列とする。まず電話帳を初期化し、それに対して電話帳の項目の追加、削除と名前から電話番号の検索を行う。これをHaskellで実装してみることにする。
import qualified Data.Map as Map
phoneBook :: Map.Map String String
phoneBook = Map.fromList [("alice", "1234-5678"), ("bob", "2345-6789")]
main = do
print $ Map.lookup "alice" phoneBook -- => Just "1234-5678"
let phoneBook2 = Map.insert "carol" "3456-7890" phoneBook
print $ Map.lookup "carol" phoneBook2 -- => Just "3456-7890"
let phoneBook3 = Map.delete "bob" phoneBook2
print $ Map.lookup "bob" phoneBook3 -- => Nothing
HaskellではまずData.Map
モジュールを使用するためにこれを修飾つきでimpomt
する。これはPrelude
の関数とData.Map
の関数が一部重複するため、明示的にMap
を指定しなければData.Map
の関数を呼び出せない形でインポートするためである。RubyのHash
とHaskellのData.Map
の基本的なメソッドの対応は以下のとおり。
Ruby | Data.Map | 意味 |
---|---|---|
{}リテラル | Data.Map.fromList | 連想配列を初期化する |
[] | Data.Map.lookup | キーに対応する値を取得する |
store | Data.Map.insert | キーに対応する値を設定する |
delete | Data.Map.delete | キーとその値を削除する |
HaskellではfromLinst
を使ってタプル(ペア)のリストから連想配列を初期化できる。 Haskellの関数はいずれも連想配列自体は変更せずに、新しい連想配列を返すようになっている。 そのためinsert
やdelete
毎に新しい連想配列を変数に束縛している。 これはちょっと不恰好に見えるのだが、直接連想配列を操作する方法は見当たらなかった。
注目すべきはlookup
関数の型である。これをGHCiで調べてみると以下のようにMaybe
がついた特別な型が返ることがわかる。これはその型の値か、Nothingが返ることを意味している。実際、電話帳からbob
の項目を削除したあとでbob
を検索するとNothing
が返ってくることがわかる。
*Main> :t Map.lookup
Map.lookup :: Ord k => k -> Map.Map k a -> Maybe a
なおHaskellのプログラムで頻出している$
、$
に続く関数の評価を優先して行うためのシンタックスシュガーである。print
の例ではprint $ 1 + 1
とprint (1 + 1)
が等価である。$
以降がすべて括弧で囲われているものと思えば良い。
電話帳を題材にしたData.Map
の使い方については、”すごいHaskellたのしく学ぼう!”の6章を参考にした。本書ではまず自力でタプルとリストを使った連想リストを実装したあとに、Data.Map
を導入する流れとなっており、良い勉強になる。
オーム社
売り上げランキング: 126,678