「48時間でSchemeを書こう/変数と代入」の版間の差分

削除された内容 追加された内容
翻訳の修正
翻訳の修正2
50 行
 まず最初に、readIORefを使って、IORefから実際の環境の値を取り出します。そして、私たちが関心のある変数を探すため、この環境の値をlookupに渡します。lookupはMaybeの値を返すので、もしこの値がNothingならばFalseを返し、他の値ならTureを返します(ここで[http://www.haskell.org/onlinereport/standard-prelude.html#$vconst const]関数を使います。 というのも、[http://www.haskell.org/onlinereport/standard-prelude.html#$vmaybe maybe]が要求するのは、ただの値ではなく、結果を実行する関数だからです)。最後に値をIOモナドに持ち上げるためreturnを使います。ここではtrueかfalseかの値に興味があるので、lookupが返した実際のIORefを扱う必要はありません。
 
  次に、変数の現在の値を取り出す関数を定義します。
 
getVar :: Env -> String -> IOThrowsError LispVal
58 行
(lookup var env)
 
 これは、前出した関数のように、まず、IORefから実際の環境を取り出し始めます。しかただし、getVarはIOthrowsErrorIothrowsErrorモナドを使います。というのも、これも同様にいくつかのは、エラーを扱う処理が必要があるからです。結局、readIORefを取り出す合成モナドに持ち上げるための関数である、 [http://www.haskell.org/ghc/docs/6.4/html/libraries/mtl/Control.Monad.Trans.html#v%3aliftIO liftIO]関数を使う必要が出てきました。同じように、私たちが値を返すとき時にも、liftIO検索されたIORef使います。読み込むようなIOThrowsErrorアクションを作り出生成ため liftIO . readIORefは、IORefの返り値 返し使います。しかし、私たちはエラーを投げてもらうために、liftIOを使う必要はなくなりましたせん。というのも、throwErrorは[http://www.haskell.org/ghc/docs/6.4/html/libraries/mtl/Control.Monad.Error.html#t%3aMonadError MonadError typeclass]に定義されているからで、ErrorTはこのインスタンスだからです。
 
 関数に、値をセットする関数を作りましょう。
69 行
return value
 
 再び、まずこの、前と同じようにIORefの外にあるから環境を読み込んで結果にlookupを走らせています。しかただし、このときこでは私たちはただ読み込む代わりにだけでなく、値を変えて欲と思ってまのです。[http://www.haskell.org/ghc/docs/6.4/html/libraries/base/Data.IORef.html#v%3awriteIORef writeIORef]アクションは、これらの意味を供給してくれますが、間違った命令引数の順序が逆です(refvalue -> balueref insteadではなく of valueref -> refvalue である)のいくつかの引数を受けとりますだからそこでwriteIORef周辺の引数を切り替えるためのビルトイン関数[http://www.haskell.org/onlinereport/standard-prelude.html#$vflip flip] からを使い、writeIORefの引数を入れ替え、値を受けとり渡します。最後に、便に、便性のめ、セットした値を返します。
 
 次は、変数が既に束縛されている場合は、変数をセットし、そうでない場合は、新しく変数を作成する、という[http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-8.html#%_sec_5.2 define]の動作を実現しましょう。前者の場合には、に定義した値をセットする関数が使えます。
defineVar :: Env -> String -> LispVal -> IOThrowsError LispVal
84 行
return value
 
 興味深いのは、後者の、変数が束縛されていない、後者の場合です。do記法を使って、ひとつのIOアクションを作っています。このアクションは、新しい変数を保持する新しいIORefを作り、環境の現在の値を読み込み、その先頭に、新しい変数の (key,変数) ペアを追加して、その新しいリストを書き戻しています。そして、このdoブロック全体をliftIOを使って、IOThrowsErrorモナドへ持ち上げています。
 
 もうひとつ便利な環境関数を作りましょう。この環境関数は、関数の実行に際して、変数の一群を一度に束縛することができます。次のセクションまで使うことはないでしょうが、今なら、これを上手く作成できます。