Stop using lists to represent args
This commit is contained in:
166
src/Eval.hs
166
src/Eval.hs
@ -2,63 +2,139 @@ module Eval where
|
||||
|
||||
import Parser
|
||||
import Research
|
||||
|
||||
import Data.Set (Set)
|
||||
import qualified Data.Set as Set
|
||||
import Data.List (foldl')
|
||||
import qualified Data.Map as Map
|
||||
import Data.Map (Map)
|
||||
import Data.Map (Map)
|
||||
|
||||
evalSingle :: Map String T -> SaplingAST -> Map String T
|
||||
evalSingle env TLeaf = Map.insert "__result" Leaf env
|
||||
evalSingle env (TStem t) =
|
||||
let result = Stem (evalTreeCalculus env t)
|
||||
in Map.insert "__result" result env
|
||||
evalSingle env (TFork t1 t2) =
|
||||
let result = Fork (evalTreeCalculus env t1) (evalTreeCalculus env t2)
|
||||
in Map.insert "__result" result env
|
||||
evalSingle env (SFunc name [] body) =
|
||||
let value = evalTreeCalculus env body
|
||||
in Map.insert name value env
|
||||
evalSingle env (SVar name) =
|
||||
case Map.lookup name env of
|
||||
Just value -> Map.insert "__result" value env
|
||||
Nothing -> error $ "Variable " ++ name ++ " not defined"
|
||||
evalSingle env ast = Map.insert "__result" (evalTreeCalculus env ast) env
|
||||
evalSingle :: Map.Map String T -> SaplingAST -> Map.Map String T
|
||||
evalSingle env term = case term of
|
||||
SFunc name [] body ->
|
||||
let result = evalAST env body
|
||||
in Map.insert name result env
|
||||
SApp func arg ->
|
||||
let result = apply (evalAST env func) (evalAST env arg)
|
||||
in Map.insert "__result" result env
|
||||
SVar name -> case Map.lookup name env of
|
||||
Just value -> Map.insert "__result" value env
|
||||
Nothing -> error $ "Variable " ++ name ++ " not defined"
|
||||
_ ->
|
||||
let result = evalAST env term
|
||||
in Map.insert "__result" result env
|
||||
|
||||
evalSapling :: Map String T -> [SaplingAST] -> Map String T
|
||||
evalSapling env [] = env
|
||||
evalSapling env [lastLine] =
|
||||
let updatedEnv = evalSingle env lastLine
|
||||
let
|
||||
lastLineNoLambda = eliminateLambda lastLine
|
||||
updatedEnv = evalSingle env lastLineNoLambda
|
||||
in Map.insert "__result" (result updatedEnv) updatedEnv
|
||||
evalSapling env (line:rest) =
|
||||
let updatedEnv = evalSingle env line
|
||||
let
|
||||
lineNoLambda = eliminateLambda line
|
||||
updatedEnv = evalSingle env lineNoLambda
|
||||
in evalSapling updatedEnv rest
|
||||
|
||||
evalTreeCalculus :: Map.Map String T -> SaplingAST -> T
|
||||
evalTreeCalculus _ TLeaf = Leaf
|
||||
evalTreeCalculus env (TStem t) = Stem (evalTreeCalculus env t)
|
||||
evalTreeCalculus env (TFork t1 t2) = Fork (evalTreeCalculus env t1) (evalTreeCalculus env t2)
|
||||
evalTreeCalculus env (SApp base []) = evalTreeCalculus env base
|
||||
evalTreeCalculus env (SApp base args) =
|
||||
let func = evalTreeCalculus env base
|
||||
argVals = map (evalTreeCalculus env) args
|
||||
in foldl apply func argVals
|
||||
evalTreeCalculus env (SVar name) =
|
||||
case Map.lookup name env of
|
||||
Just value -> value
|
||||
Nothing -> error $ "Variable " ++ name ++ " not defined"
|
||||
evalTreeCalculus _ (SStr str) = toString str
|
||||
evalTreeCalculus _ (SInt num) = toNumber num
|
||||
evalTreeCalculus _ (SList elems) = toList (map (evalTreeCalculus Map.empty) elems)
|
||||
evalTreeCalculus _ (SFunc name args body) =
|
||||
error $ "Unexpected function definition " ++ name ++ " in \
|
||||
\ evalTreeCalculus; functions should be evaluated to Tree Calculus \
|
||||
\ terms by evalSingle."
|
||||
evalAST :: Map String T -> SaplingAST -> T
|
||||
evalAST env term = case term of
|
||||
SVar name ->
|
||||
case Map.lookup name env of
|
||||
Just value -> value
|
||||
Nothing -> error $ "Variable " ++ name ++ " not defined"
|
||||
TLeaf -> Leaf
|
||||
TStem t ->
|
||||
Stem (evalAST env t)
|
||||
TFork t1 t2 ->
|
||||
Fork (evalAST env t1) (evalAST env t2)
|
||||
SApp t1 t2 ->
|
||||
apply (evalAST env t1) (evalAST env t2)
|
||||
SStr str -> toString str
|
||||
SInt num -> toNumber num
|
||||
SList elems -> toList (map (evalAST Map.empty) elems)
|
||||
SFunc name args body ->
|
||||
error $ "Unexpected function definition " ++ name
|
||||
++ " in evalAST; define via evalSingle."
|
||||
SLambda {} ->
|
||||
error "Internal error: SLambda found in evalAST after elimination."
|
||||
|
||||
result :: Map String T -> T
|
||||
result r = case (Map.lookup "__result" r) of
|
||||
Just a -> a
|
||||
Nothing -> error "No __result field found in provided environment"
|
||||
result r = case Map.lookup "__result" r of
|
||||
Just a -> a
|
||||
Nothing -> error "No __result field found in provided environment"
|
||||
|
||||
|
||||
eliminateLambda :: SaplingAST -> SaplingAST
|
||||
eliminateLambda (SLambda (v:vs) body)
|
||||
| null vs = lambdaToT v (eliminateLambda body)
|
||||
| otherwise =
|
||||
eliminateLambda (SLambda [v] (SLambda vs body))
|
||||
eliminateLambda (SApp f arg) =
|
||||
SApp (eliminateLambda f) (eliminateLambda arg)
|
||||
eliminateLambda (TStem t) =
|
||||
TStem (eliminateLambda t)
|
||||
eliminateLambda (TFork l r) =
|
||||
TFork (eliminateLambda l) (eliminateLambda r)
|
||||
eliminateLambda (SList xs) =
|
||||
SList (map eliminateLambda xs)
|
||||
eliminateLambda (SFunc n vs b) =
|
||||
SFunc n vs (eliminateLambda b)
|
||||
eliminateLambda other = other
|
||||
|
||||
lambdaToT :: String -> SaplingAST -> SaplingAST
|
||||
lambdaToT x (SVar y)
|
||||
| x == y = tI
|
||||
lambdaToT x (SVar y)
|
||||
| x /= y =
|
||||
SApp tK (SVar y)
|
||||
lambdaToT x t
|
||||
| not (isFree x t) =
|
||||
SApp tK t
|
||||
lambdaToT x (SApp n u)
|
||||
| not (isFree x (SApp n u)) =
|
||||
SApp tK (SApp (eliminateLambda n) (eliminateLambda u))
|
||||
lambdaToT x (SApp n u) =
|
||||
SApp
|
||||
(SApp tS (lambdaToT x (eliminateLambda n)))
|
||||
(lambdaToT x (eliminateLambda u))
|
||||
lambdaToT x (SApp f args) = lambdaToT x f
|
||||
lambdaToT x body
|
||||
| not (isFree x body) =
|
||||
SApp tK body
|
||||
| otherwise =
|
||||
SApp
|
||||
(SApp tS (lambdaToT x body))
|
||||
tLeaf
|
||||
|
||||
tLeaf :: SaplingAST
|
||||
tLeaf = TLeaf
|
||||
|
||||
freeVars :: SaplingAST -> Set String
|
||||
freeVars (SVar v) = Set.singleton v
|
||||
freeVars (SInt _) = Set.empty
|
||||
freeVars (SStr _) = Set.empty
|
||||
freeVars (SList xs) = foldMap freeVars xs
|
||||
freeVars (SFunc _ _ b) = freeVars b
|
||||
freeVars (SApp f arg) = freeVars f <> freeVars arg
|
||||
freeVars TLeaf = Set.empty
|
||||
freeVars (TStem t) = freeVars t
|
||||
freeVars (TFork l r) = freeVars l <> freeVars r
|
||||
freeVars (SLambda vs b) = foldr Set.delete (freeVars b) vs
|
||||
|
||||
isFree :: String -> SaplingAST -> Bool
|
||||
isFree x = Set.member x . freeVars
|
||||
|
||||
toAST :: T -> SaplingAST
|
||||
toAST Leaf = TLeaf
|
||||
toAST (Stem a) = TStem (toAST a)
|
||||
toAST Leaf = TLeaf
|
||||
toAST (Stem a) = TStem (toAST a)
|
||||
toAST (Fork a b) = TFork (toAST a) (toAST b)
|
||||
|
||||
tI :: SaplingAST
|
||||
tI = toAST _I
|
||||
|
||||
tK :: SaplingAST
|
||||
tK = toAST _K
|
||||
|
||||
tS :: SaplingAST
|
||||
tS = toAST _S
|
||||
|
||||
|
10
src/Lexer.hs
10
src/Lexer.hs
@ -13,6 +13,8 @@ data LToken
|
||||
| LIntegerLiteral Int
|
||||
| LStringLiteral String
|
||||
| LAssign
|
||||
| LColon
|
||||
| LBackslash
|
||||
| LOpenParen
|
||||
| LCloseParen
|
||||
| LOpenBracket
|
||||
@ -48,6 +50,12 @@ stringLiteral = do
|
||||
assign :: Lexer LToken
|
||||
assign = char '=' *> pure LAssign
|
||||
|
||||
colon :: Lexer LToken
|
||||
colon = char ':' *> pure LColon
|
||||
|
||||
backslash :: Lexer LToken
|
||||
backslash = char '\\' *> pure LBackslash
|
||||
|
||||
openParen :: Lexer LToken
|
||||
openParen = char '(' *> pure LOpenParen
|
||||
|
||||
@ -73,6 +81,8 @@ saplingLexer = many (sc *> choice
|
||||
, try integerLiteral
|
||||
, try stringLiteral
|
||||
, assign
|
||||
, colon
|
||||
, backslash
|
||||
, openParen
|
||||
, closeParen
|
||||
, openBracket
|
||||
|
@ -6,7 +6,7 @@ import Parser
|
||||
import REPL (repl)
|
||||
import Research
|
||||
|
||||
import Data.Map as Map
|
||||
import qualified Data.Map as Map
|
||||
import Text.Megaparsec (runParser)
|
||||
|
||||
main :: IO ()
|
||||
|
@ -1,5 +1,7 @@
|
||||
module Parser where
|
||||
|
||||
import Debug.Trace
|
||||
|
||||
import Lexer
|
||||
import Research hiding (toList)
|
||||
|
||||
@ -13,15 +15,16 @@ import Text.Megaparsec.Error (errorBundlePretty, ParseErrorBundle)
|
||||
|
||||
type Parser = Parsec Void [LToken]
|
||||
data SaplingAST
|
||||
= SVar String
|
||||
| SInt Int
|
||||
| SStr String
|
||||
| SList [SaplingAST]
|
||||
| SFunc String [String] SaplingAST
|
||||
| SApp SaplingAST [SaplingAST]
|
||||
= SVar String
|
||||
| SInt Int
|
||||
| SStr String
|
||||
| SList [SaplingAST]
|
||||
| SFunc String [String] SaplingAST
|
||||
| SApp SaplingAST SaplingAST
|
||||
| TLeaf
|
||||
| TStem SaplingAST
|
||||
| TFork SaplingAST SaplingAST
|
||||
| TStem SaplingAST
|
||||
| TFork SaplingAST SaplingAST
|
||||
| SLambda [String] SaplingAST
|
||||
deriving (Show, Eq, Ord)
|
||||
|
||||
parseSapling :: String -> [SaplingAST]
|
||||
@ -41,10 +44,11 @@ scnParser = skipMany (satisfy isNewline)
|
||||
parseExpression :: Parser SaplingAST
|
||||
parseExpression = choice
|
||||
[ try parseFunction
|
||||
, try parseLambda
|
||||
, try parseListLiteral
|
||||
, try parseApplication
|
||||
, parseTreeTerm
|
||||
, try parseTreeTerm
|
||||
, parseLiteral
|
||||
, parseListLiteral
|
||||
]
|
||||
|
||||
parseFunction :: Parser SaplingAST
|
||||
@ -55,24 +59,54 @@ parseFunction = do
|
||||
body <- parseExpression
|
||||
return (SFunc name (map getIdentifier args) body)
|
||||
|
||||
parseLambda :: Parser SaplingAST
|
||||
parseLambda = between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) $ do
|
||||
satisfy (== LBackslash)
|
||||
param <- satisfy isIdentifier
|
||||
rest <- many (satisfy isIdentifier)
|
||||
satisfy (== LColon)
|
||||
body <- parseLambdaExpression
|
||||
let nestedLambda = foldr (\v acc -> SLambda [v] acc) body (map getIdentifier rest)
|
||||
return (SLambda [getIdentifier param] nestedLambda)
|
||||
|
||||
parseLambdaExpression :: Parser SaplingAST
|
||||
parseLambdaExpression = choice
|
||||
[ try parseLambdaApplication
|
||||
, parseAtomicLambda
|
||||
]
|
||||
|
||||
parseAtomicLambda :: Parser SaplingAST
|
||||
parseAtomicLambda = choice
|
||||
[ parseVar
|
||||
, parseTreeLeaf
|
||||
, parseLiteral
|
||||
, parseListLiteral
|
||||
, between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) parseLambdaExpression
|
||||
]
|
||||
|
||||
parseApplication :: Parser SaplingAST
|
||||
parseApplication = do
|
||||
func <- parseAtomicBase
|
||||
args <- many parseAtomicApplication
|
||||
case func of
|
||||
TLeaf | not (null args) && all isTreeTerm args -> fail "Defer to Tree Calculus"
|
||||
_ -> return (SApp func args)
|
||||
args <- many parseAtomic
|
||||
return $ foldl (\acc arg -> SApp acc arg) func args
|
||||
|
||||
parseLambdaApplication :: Parser SaplingAST
|
||||
parseLambdaApplication = do
|
||||
func <- parseAtomicLambda
|
||||
args <- many parseAtomicLambda
|
||||
return $ foldl (\acc arg -> SApp acc arg) func args
|
||||
|
||||
isTreeTerm :: SaplingAST -> Bool
|
||||
isTreeTerm TLeaf = True
|
||||
isTreeTerm (TStem _) = True
|
||||
isTreeTerm TLeaf = True
|
||||
isTreeTerm (TStem _) = True
|
||||
isTreeTerm (TFork _ _) = True
|
||||
isTreeTerm _ = False
|
||||
isTreeTerm _ = False
|
||||
|
||||
parseAtomicBase :: Parser SaplingAST
|
||||
parseAtomicBase = choice
|
||||
[ parseVar
|
||||
, parseTreeLeaf
|
||||
, parseGrouped
|
||||
]
|
||||
|
||||
parseTreeLeaf :: Parser SaplingAST
|
||||
@ -107,27 +141,15 @@ foldTree (x:y:rest) = TFork x (foldTree (y:rest))
|
||||
parseAtomic :: Parser SaplingAST
|
||||
parseAtomic = choice
|
||||
[ parseVar
|
||||
, parseTreeLeafOrParenthesized
|
||||
, parseLiteral
|
||||
, parseTreeLeaf
|
||||
, parseListLiteral
|
||||
, between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) parseExpression
|
||||
, parseGrouped
|
||||
, parseLiteral
|
||||
]
|
||||
|
||||
parseAtomicApplication :: Parser SaplingAST
|
||||
parseAtomicApplication = do
|
||||
token <- anySingle
|
||||
case token of
|
||||
LAssign -> fail
|
||||
"Unexpected `=` character in application context. \
|
||||
\ This is usually caused by an incomplete definition such as: \
|
||||
\ `function a b =`"
|
||||
LIdentifier name -> return (SVar name)
|
||||
LKeywordT -> return TLeaf
|
||||
LIntegerLiteral value -> return (SInt value)
|
||||
LStringLiteral value -> return (SStr value)
|
||||
LOpenBracket -> parseListLiteral
|
||||
LOpenParen -> between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) parseExpression
|
||||
_ -> fail "Invalid token while parsing attempted function application"
|
||||
|
||||
parseGrouped :: Parser SaplingAST
|
||||
parseGrouped = between (satisfy (== LOpenParen)) (satisfy (== LCloseParen)) parseExpression
|
||||
|
||||
parseLiteral :: Parser SaplingAST
|
||||
parseLiteral = choice
|
||||
|
Reference in New Issue
Block a user