0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

48時間でSchemeを書こう/評価: 第一部

Posted at

参考URL

48時間でSchemeを書こう/評価: 第一部

#ソース
https://github.com/0zawa/scheme_in_48_hours/blob/master/evaluation_1.hs

ListValの表示

ListValをprint関数などで表示(文字列化)可能にします。

List,DottedList以外は単純に値を表示しています。

showVal :: LispVal -> String
showVal (String contents) = "¥"" ++ contents ++ "¥""
showVal (Atom name) = name
showVal (Number contents) = show contents
showVal (Bool True) = "#t"
showVal (Bool False) = "#f"

List,DottedListはLispValのリストをunwordsList関数に
渡してから連結しています。

showVal (List contents) = "(" ++ unwordsList contents ++ ")"
showVal (DottedList head tail) = "(" ++ unwordsList head ++ " . " ++ showVal tail ++ ")"

unwordsList関数はLispValのリストをStringに変換する関数です。

unwordsList :: [LispVal] -> String
unwordsList = unwords . map showVal

リストの個々の要素にshowValを適用し、
それをunwords関数に適用しています。
unwords関数はStringのリストを連結してStringにする関数です。

> unwords ["a","b","c"]
"a b c"

> unwords $ map show [1,2,3]
"1 2 3"

続いてLispValをShowクラスのインスタンスにします。

instance Show LispVal where show = showVal

これでshow関数の引数にLispValが渡された場合、
文字列が出力されるようになります。

文字列が表示できるようになったので、readExpr関数を修正します。

readExpr input = case parse parseExpr "lisp" input of
    Left err -> "No match: " ++ show err
    Right val -> "Found " ++ show val

"Found "のあとに文字列化されたLispValが
表示されるようになりました。

評価

続いて、LispValを評価するための関数を作ります。

まずは簡単なものから定義します。

eval :: LispVal -> LispVal
eval val@(String _) = val
eval val@(Number _) = val
eval val@(Bool _) = val
eval (List [Atom "quote", val]) = val

「@」を使っている箇所ははasパターンと呼ばれ、
@の前の変数には()の中全体が入ります。

evalを適用できるようにするために、
readExprの戻り値の型をStringからLispValに変更します。

readExpr :: String -> LispVal
readExpr input = case parse parseExpr "lisp" input of
    Left err -> String $ "No match: " ++ show err
    Right val -> val

この関数で変換されたLispValをevalに渡します。

この操作はmain関数で行います。

main :: IO ()
main = getArgs >>= print . eval . readExpr . head

「>>=」はバインドと呼ばれるものですが、少々表記がわかりにくいので
別の形式で書き直すと

main :: IO ()
main = do
  x <- getArgs
  (print . eval . readExpr . head) x

となります。

getArgsから取得したxはStringではなく[String]なので、
リストの先頭を取得するためheadを適用します。

次にその文字列にreadExprを適用してLispValを得ます。

更にそのLispValにevalを適用して評価結果のLispValを得ます。

これにprint関数を適用すると先ほど作成したshowVal関数が呼ばれて
文字列が出力されます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?