aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Tuomi <jan.tuomi@valuemotive.com>2022-09-24 13:43:58 +0300
committerJan Tuomi <jans.tuomi@gmail.com>2022-12-05 14:21:53 +0200
commit52a565296108e9406bd9ad2605f346d16fe34498 (patch)
tree59bf55447148ec35f40db521a6a67454f992bc73
parente6950bb8c053e0d6108ca0784b986254257f5f2f (diff)
Implement user defined functions with > 1 params
-rw-r--r--examples/test.lisp1
-rw-r--r--src/Lib.hs79
2 files changed, 61 insertions, 19 deletions
diff --git a/examples/test.lisp b/examples/test.lisp
index d93a5f4..b41007d 100644
--- a/examples/test.lisp
+++ b/examples/test.lisp
@@ -8,3 +8,4 @@
;; "another \n\"string\""
;; (let id
;; (\[a] a))
+(\[x] (\[y] (sum2 x y))) \ No newline at end of file
diff --git a/src/Lib.hs b/src/Lib.hs
index d1644be..16ce782 100644
--- a/src/Lib.hs
+++ b/src/Lib.hs
@@ -133,6 +133,21 @@ assertIntegerAST ast = case ast of
(ASTInteger _) -> return ast
_ -> throwError $ LException $ show ast ++ " is not an integer"
+assertSymbolAST :: AST -> LContext AST
+assertSymbolAST ast = case ast of
+ (ASTSymbol _) -> return ast
+ _ -> throwError $ LException $ show ast ++ " is not a symbol"
+
+assertVectorAST :: AST -> LContext AST
+assertVectorAST ast = case ast of
+ (ASTVector _) -> return ast
+ _ -> throwError $ LException $ show ast ++ " is not a vector"
+
+assertFunctionCallAST :: AST -> LContext AST
+assertFunctionCallAST ast = case ast of
+ (ASTFunctionCall _) -> return ast
+ _ -> throwError $ LException $ show ast ++ " is not a function call or body"
+
curryCall :: [AST] -> (AST -> LContext AST) -> LContext AST
curryCall [] f = return $ ASTFunction f
curryCall (arg:[]) f = f arg
@@ -145,9 +160,30 @@ curryCall (arg:rest) f = do
type Env = M.Map String AST
builtinEnv :: Env
builtinEnv = M.fromList [
- ("sum2", builtinSum2)
+ ("+", builtinAdd2),
+ ("-", builtinSubtract2)
]
+builtinAdd2 :: AST
+builtinAdd2 =
+ let outer ast1 = do
+ (ASTInteger a) <- assertIntegerAST ast1
+ let inner ast2 = do
+ (ASTInteger b) <- assertIntegerAST ast2
+ return $ ASTInteger $ a + b
+ return $ ASTFunction $ inner
+ in ASTFunction outer
+
+builtinSubtract2 :: AST
+builtinSubtract2 =
+ let outer ast1 = do
+ (ASTInteger a) <- assertIntegerAST ast1
+ let inner ast2 = do
+ (ASTInteger b) <- assertIntegerAST ast2
+ return $ ASTInteger $ a - b
+ return $ ASTFunction $ inner
+ in ASTFunction outer
+
traverseAndReplace :: String -> AST -> AST -> AST
traverseAndReplace param arg ast@(ASTSymbol sym)
| sym == param = arg
@@ -163,33 +199,38 @@ traverseAndReplace param arg (ASTHashMap hmap) =
.> asPairs .> M.fromList
traverseAndReplace _ _ other = other
-makeUserDefFn :: Env -> String -> AST -> AST -> LContext AST
-makeUserDefFn env param body =
+makeUserDefFn :: Env -> AST -> AST -> AST -> LContext AST
+makeUserDefFn env (ASTSymbol param) body =
let fn :: AST -> LContext AST
fn arg = do
- let newBody = traverseAndReplace param arg body
- evaluate env newBody
+ let newBody = traverseAndReplace param arg body
+ evaluate env newBody
in fn
+makeUserDefFn _ _ _ = error $ "unreachable"
-builtinSum2 :: AST
-builtinSum2 =
- let outer ast1 = do
- (ASTInteger a) <- assertIntegerAST ast1
- let inner ast2 = do
- (ASTInteger b) <- assertIntegerAST ast2
- return $ ASTInteger $ a + b
- return $ ASTFunction $ inner
- in ASTFunction outer
+curriedMakeUserDefFn :: Env -> [AST] -> AST -> AST -> LContext AST
+curriedMakeUserDefFn _ [] _ = error "unreachable"
+curriedMakeUserDefFn env (param:[]) body = makeUserDefFn env param body
+curriedMakeUserDefFn env ((ASTSymbol param):rest) body =
+ let fn :: AST -> LContext AST
+ fn arg = do
+ let newBody = traverseAndReplace param arg body
+ let ret = curriedMakeUserDefFn env rest newBody
+ return $ ASTFunction $ ret
+ in fn
+curriedMakeUserDefFn _ _ _ = error $ "unreachable"
evaluate :: Env -> AST -> LContext AST
evaluate env (ASTFunctionCall children@(first:args))
| first == ASTSymbol "\\" = do
- -- throwError $ LException "function def not implemented"
- -- let (ASTVector paramList : ASTFunctionCall body : []) = args
- let (ASTVector [ASTSymbol param] : body : []) = args
- let fn = makeUserDefFn env param body
+ when (length args /= 2) $ throwError $ LException $ "\\ called with " ++ show (length args) ++ " arguments"
+ let [arg1, arg2] = args
+ (ASTVector params') <- assertVectorAST arg1
+ params <- mapM assertSymbolAST params'
+ when (length params == 0) $ throwError $ LException $ "Function must have > 0 parameters"
+ body <- assertFunctionCallAST arg2
+ let fn = curriedMakeUserDefFn env params body
return $ ASTFunction fn
- -- return $ ASTFunction fn
| first == ASTSymbol "match" =
throwError $ LException "match not implemented"
| otherwise = do