Lisp処理系
適当なLisp処理系(と言えるのか?)を作りました。半日で作った感じなので、細かいミスは仕方ない!
import System.IO import Control.Monad import Text.ParserCombinators.Parsec data LispVal = Atom String | Boolean Bool | String String | Number Integer | List [LispVal] | Proc LispProc instance Show LispVal where show (Atom a) = a show (Boolean b) = if b then "#t" else "#f" show (String s) = show s show (Number n) = show n show (List l) = "(" ++ (foldl1 (?a b-> a++" "++b) $ map show l) ++ ")" show (Proc _) = "<function>" type LispProc = [LispVal] -> LispVal type Env = [(String, LispVal)] type LParser = GenParser Char Env fromAtom (Atom a) = a fromNumber (Number x) = x fromString (String s) = s fromList (List l) = l primitive :: [(String, LispVal)] primitive = [ ("+", makeFun Number fromNumber (+)) , ("-", makeFun Number fromNumber (-)) , ("*", makeFun Number fromNumber (*)) , ("/", makeFun Number fromNumber div) ] ++ [ ("string-append", makeFun String fromString (++)) ] ++ [ ("number?", Proc $ ?l -> case head l of Number _ -> Boolean True _ -> Boolean False) ] ++ [ ("list", Proc $ List) , ("car", Proc $ ?[x] -> head $ fromList x) , ("cdr", Proc $ ?[x] -> List $ tail $ fromList x) , ("append", makeFun List fromList (++)) ] where makeFun dataCon from f = Proc $ dataCon . (foldl1 f) . (map from) pStart :: LParser (LispVal, Env) pStart = do result <- pLisp state <- getState return (result, state) pLisp :: LParser LispVal pLisp = do v <- try pDefine <|> try pLambda <|> pLispExp <|> pLispNumber <|> pLispString <|> pLispBoolean <|> pLispAtom spaces return v pLispExp :: LParser LispVal pLispExp = do (op:args) <- between (char '(') (char ')') $ many1 pLisp table <- getState case op of Proc p -> return $ p args _ -> fail $ "not function" pLispNumber :: LParser LispVal pLispNumber = many1 digit >>= return . Number . read pLispString = between (char '"') (char '"') $ many1 (noneOf " ?"") >>= return . String pLispBoolean = do char '#' (char 't' >> return (Boolean True)) <|> (char 'f' >> return (Boolean False)) pLispAtom = do s <- many1 (noneOf "() ?t?n'?"#") table <- getState case lookup s table of Nothing -> fail $ "unbound variable: " ++ s Just x -> return x pDefine :: LParser LispVal pDefine = between (char '(') (char ')') inner where inner = do string "define" spaces name <- many1 $ noneOf "() ?t?n'?"#" spaces val <- pLisp updateState ((name,val):) return $ Atom name pLambda :: LParser LispVal pLambda = between (char '(') (char ')') inner where inner = do string "lambda" spaces argNames <- between (char '(') (char ')') $ sepBy1 ident spaces spaces def <- getExpr 0 table <- getState return $ Proc $ ?args -> case eval (zip argNames args ++ table) def of Left e -> String $ show (zip argNames args ++ table) Right (v,_) -> v ident = do f <- letter t <- many alphaNum return $ f:t getExpr n = do a <- anyChar let m = case a of '(' -> n+1 ')' -> n-1 _ -> n if a==')' && m==0 then return [a] else do rest <- getExpr m return $ a:rest main :: IO () main = main' primitive where main' s = do putStr "mins> " >> hFlush stdout expr <- getLine case eval s expr of Left e -> print e >> main' s Right (v,s) -> print v >> main' s eval s str = runParser pStart s "" str
うーん、バックスラッシュがはてなマークになってしまうな…。