あどけない話

インターネットに関する技術的な話など

HaskellでScheme

ついに、Write Yourself a Scheme in 48 Hoursをやりました。

分ったこと

以下のことが、なんとなく分ったり、少なくともどう使うのかを体験できました。

  • エラー処理
    • 正常系の値と異常系の値を包含する型を作って、Scheme の関数はそれを返すようにする
  • モナド変換子
  • クロージャの実装

コードの問題点

ファイルとして置いてあるコードですが、以下のような小さな問題があります。

  • 2箇所Texのコマンドが残っている
parseString = do char ;\textcolor{string}{\texttt{'"'}};
  • cdr の定義が間違っている
cdr [DottedList (_ : xs) x] = return $ DottedList xs x
cdr [DottedList [xs] x] = return x

は誤りで、正しくはこう。

cdr [DottedList [xs] x] = return x
cdr [DottedList (_ : xs) x] = return $ DottedList xs x

でも、こう書く方が、もっと分りやすいと思います。

cdr [DottedList [_] x] = return x
cdr [DottedList (_ : xs) x] = return $ DottedList xs x
  • Haskell 98 にない forall が使われている

ghci を使う場合は、ファイルの先頭に以下を入れるといいです。

{-# LANGUAGE ExistentialQuantification #-}

独自拡張

大域の環境とクロージャの環境を表示する Scheme の関数を作ってみました。それぞれ、(show) と (closure "関数名") です。

eval env (List [Atom "show"]) = do pairs <- liftIO $ readIORef env
                                   return $ String $ unwords $ map fst pairs

eval env (List [Atom "closure", String name]) =
    do func <- getVar env name
       pairs <- liftIO $ readIORef $ closure func
       return $ String $ unwords $ map fst pairs

以下のようにクロージャを作って、

(define acm (lambda (n) (lambda (m) (+ n m))))
(define plus1 (acm 1))

以下のようにクロージャの環境を表示してみると

(closure "plus1") 

n が積まれていることが分ります。

おまけ

Hugs では動かないことが分りました。素直に GHC を使いましょう。