top page > computer > haskell > web_lecture > for_programmer > nsc_list.html
更新日:
文責: 重城良国

Nano Scheme: リスト

(工事中 30%)

はじめに

SchemeなどのLisp系の言語はコードをリスト(コンス)に解析し、リストの1番目の手続きを2番目以降の引数に適用する。Nano Schemeの値にリスト値を追加する。

リスト値を追加

Environment.hs

Value型にList値を追加する。

data Value
= Sym Symbol
| Int Integer
| List [Value]

表示する。

showValue :: Value -> String
showValue (Symbol s) = s
showValue (Int i) = show i
showValue (List vs) = "(" ++ unwords (map showValue vs) ++ ")"

関数unwordsは文字列のリストをスペース区切りでひとつの文字列にまとめる。

トークン

Parse.hs

トークンに開き丸括弧と閉じ丸括弧とを追加する。

data Token
= TkSym Symbol
| TkInt Integer
| TkOPr
| TkCPr
deriving Show

字句解析

'('と')'とをトークンにする。

tokens :: String -> Maybe [Token]
tokens ('(' : s) = (TkOPr :) `mapply` tokens s
tokens (')' : s) = (TkCPr :) `mapply` tokens s
tokens (c : s)
| ...

構文解析

開き丸括弧を読みこんだらリストの構文解析にうつる。parse1とparseLとは相互再帰的に呼びあっている。

...
parse1 (TkInt i : ts) = Just (Int i, ts)
parse1 (TkOPr : ts) = (\(vs, ts') -> (List vs, ts')) `mapply` parseL ts
...

関数parseLの返り値の型は([Value], [Token])だ。タプルの第1要素に値構築子Listを適用することで[Value]をValueに変換する。

parseL :: [Token] -> Maybe ([Value], [Token])
parseL (TkCPr : ts) = Just ([], ts)
parseL ts = case parse1 ts of
Just (v, ts') -> (\(vs, ts'') -> (v : vs, ts'')) `mapply` parseL ts'
_ -> Nothing

閉じ括弧を読みこんだらリストの読みこみは終了する。そうでないなら値をひとつ読みこみ、成功すれば残りのトークンからリストを読みこむ。その結果得られた値のリストに読みこんだ値を追加する。

評価

Eval.hs

本当はリストの先頭の値を残りの値に適用する。まだ「適用可能な値」つまり「手続き」や「特殊形式」「ラムダ」を定義していないので、リストの評価は何もしないことにする。

eval :: Value -> Env -> Maybe (Value, Env)
eval (Symbol s) e = (, e) `mapply` refer s e
eval i@(Int _) e = Just (i, e)
eval l@(List _) e = Just (l, e)

(Int _)(List _)をまとめてしまおう。

eval (Symbol s) e = (, e) `mapply` refer s e
eval v e = Just (v, e)

試してみる

コマンドラインで

% echo 'nsc (123 45 6)' | runghc -Wall nsc.hs
(123 45 6)

Hubotで

Hubotを再起動して

nsc (123 45 6)

とすると

(123 45 6)

と答える。

まとめ

リストの読みこみを実装した。今のところ「評価」は何もしない。

「Nano Scheme: 変数の評価」へもどる 「Nano Scheme: 四則演算」へ

正当なCSSです! HTML5 Powered with CSS3 / styling, and Semantics