2 Commits

Author SHA1 Message Date
918d929c09 # File eval mode now relies on main function
All checks were successful
Test, Build, and Release / test (push) Successful in 1m26s
Test, Build, and Release / build (push) Successful in 1m15s
To encourage organizing code in a way that helps in understanding, I
have implemented the common idiom of requiring a `main` function. In
tricu and other functional languages, it is usually placed near the top
of the module. The evaluator gracefully handles the situation of passing
multiple files where the intermediary "library" files do not have main functions.
2025-01-26 15:33:12 -06:00
a64b3f0829 Definition dependency analysis
All checks were successful
Test, Build, and Release / test (push) Successful in 1m34s
Test, Build, and Release / build (push) Successful in 1m21s
tricu now allows defining terms in any order and will resolve
dependencies to ensure that they're evaluated in the right order.
Undefined terms are detected and throw errors during dependency
ordering.
For now we can't define top-level mutually recursive terms.
2025-01-26 14:50:39 -06:00
20 changed files with 212 additions and 143 deletions

View File

@ -54,16 +54,12 @@ jobs:
cp -L ./result/bin/tricu ./tricu cp -L ./result/bin/tricu ./tricu
chmod 755 ./tricu chmod 755 ./tricu
nix develop --command upx ./tricu nix develop --command upx ./tricu
- name: Setup go for release action
uses: actions/setup-go@v5
with:
go-version: '>=1.20.1'
- name: Release binary - name: Release binary
uses: https://gitea.com/actions/release-action@main uses: akkuman/gitea-release-action@v1
with: with:
files: |- files: |-
./tricu ./tricu
api_key: '${{ secrets.RELEASE_TOKEN }}' token: '${{ secrets.RELEASE_TOKEN }}'
body: '${{ gitea.event.head_commit.message }}'
pre_release: true pre_release: true

View File

@ -71,7 +71,7 @@ tricu eval [OPTIONS]
-f --file=FILE Input file path(s) for evaluation. -f --file=FILE Input file path(s) for evaluation.
Defaults to stdin. Defaults to stdin.
-t --form=FORM Optional output form: (tree|fsl|ast|ternary|ascii). -t --form=FORM Optional output form: (tree|fsl|ast|ternary|ascii|decode).
Defaults to tricu-compatible `t` tree form. Defaults to tricu-compatible `t` tree form.
tricu decode [OPTIONS] tricu decode [OPTIONS]

View File

@ -1,3 +1,5 @@
main = lambdaEqualsTC
-- We represent `false` with a Leaf and `true` with a Stem Leaf -- We represent `false` with a Leaf and `true` with a Stem Leaf
demo_false = t demo_false = t
demo_true = t t demo_true = t t

View File

@ -1,11 +1,10 @@
main = exampleTwo
-- Level Order Traversal of a labelled binary tree -- Level Order Traversal of a labelled binary tree
-- Objective: Print each "level" of the tree on a separate line -- Objective: Print each "level" of the tree on a separate line
-- --
-- NOTICE: This demo relies on tricu base library functions -- We model labelled binary trees as nested lists where values act as labels. We
-- -- require explicit notation of empty nodes. Empty nodes can be represented
-- We model labelled binary trees as sublists where values act as labels. We -- with an empty list, `[]`, which evaluates to a single node `t`.
-- require explicit not?ation of empty nodes. Empty nodes can be represented
-- with an empty list, `[]`, which is equivalent to a single node `t`.
-- --
-- Example tree inputs: -- Example tree inputs:
-- [("1") [("2") [("4") t t] t] [("3") [("5") t t] [("6") t t]]]] -- [("1") [("2") [("4") t t] t] [("3") [("5") t t] [("6") t t]]]]
@ -15,7 +14,6 @@
-- 2 3 -- 2 3
-- / / \ -- / / \
-- 4 5 6 -- 4 5 6
--
label = \node : head node label = \node : head node
@ -61,5 +59,3 @@ exampleTwo = levelOrderTraversal [("1")
[("2") [("4") [("8") t t] [("9") t t]] [("2") [("4") [("8") t t] [("9") t t]]
[("6") [("10") t t] [("12") t t]]] [("6") [("10") t t] [("12") t t]]]
[("3") [("5") [("11") t t] t] [("7") t t]]] [("3") [("5") [("11") t t] t] [("7") t t]]]
exampleTwo

View File

@ -1,21 +1,21 @@
main = size size
compose = \f g x : f (g x) compose = \f g x : f (g x)
succ = y (\self : succ = y (\self :
triage triage
1 1
t t
(triage (triage
(t (t t)) (t (t t))
(\_ tail : t t (self tail)) (\_ tail : t t (self tail))
t)) t))
size = (\x : size = (\x :
(y (\self x : (y (\self x :
compose succ compose succ
(triage (triage
(\x : x) (\x : x)
self self
(\x y : compose (self x) (self y)) (\x y : compose (self x) (self y))
x)) x 0)) x)) x 0))
size size

View File

@ -1,3 +1,4 @@
main = toSource not?
-- Thanks to intensionality, we can inspect the structure of a given value -- Thanks to intensionality, we can inspect the structure of a given value
-- even if it's a function. This includes lambdas which are eliminated to -- even if it's a function. This includes lambdas which are eliminated to
-- Tree Calculus (TC) terms during evaluation. -- Tree Calculus (TC) terms during evaluation.

View File

@ -18,9 +18,9 @@ y = ((\mut wait fun : wait mut (\x : fun (wait mut x)))
triage = \leaf stem fork : t (t leaf stem) fork triage = \leaf stem fork : t (t leaf stem) fork
test = triage "Leaf" (\_ : "Stem") (\_ _ : "Fork") test = triage "Leaf" (\_ : "Stem") (\_ _ : "Fork")
matchBool = (\ot of : triage matchBool = (\ot of : triage
of of
(\_ : ot) (\_ : ot)
(\_ _ : ot) (\_ _ : ot)
) )
@ -35,44 +35,44 @@ emptyList? = matchList true (\_ _ : false)
head = matchList t (\head _ : head) head = matchList t (\head _ : head)
tail = matchList t (\_ tail : tail) tail = matchList t (\_ tail : tail)
lconcat = y (\self : matchList lconcat = y (\self : matchList
(\k : k) (\k : k)
(\h r k : pair h (self r k))) (\h r k : pair h (self r k)))
lAnd = (triage lAnd = (triage
(\_ : false) (\_ : false)
(\_ x : x) (\_ x : x)
(\_ _ x : x)) (\_ _ x : x))
lOr = (triage lOr = (triage
(\x : x) (\x : x)
(\_ _ : true) (\_ _ : true)
(\_ _ _ : true)) (\_ _ _ : true))
map_ = y (\self : map_ = y (\self :
matchList matchList
(\_ : t) (\_ : t)
(\head tail f : pair (f head) (self tail f))) (\head tail f : pair (f head) (self tail f)))
map = \f l : map_ l f map = \f l : map_ l f
equal? = y (\self : triage equal? = y (\self : triage
(triage (triage
true true
(\_ : false) (\_ : false)
(\_ _ : false)) (\_ _ : false))
(\ax : (\ax :
triage triage
false false
(self ax) (self ax)
(\_ _ : false)) (\_ _ : false))
(\ax ay : (\ax ay :
triage triage
false false
(\_ : false) (\_ : false)
(\bx by : lAnd (self ax bx) (self ay by)))) (\bx by : lAnd (self ax bx) (self ay by))))
filter_ = y (\self : matchList filter_ = y (\self : matchList
(\_ : t) (\_ : t)
(\head tail f : matchBool (t head) i (f head) (self tail f))) (\head tail f : matchBool (t head) i (f head) (self tail f)))
filter = \f l : filter_ l f filter = \f l : filter_ l f

View File

@ -3,19 +3,19 @@ module Eval where
import Parser import Parser
import Research import Research
import Data.List (partition)
import Data.Map (Map) import Data.Map (Map)
import qualified Data.Map as Map import qualified Data.Map as Map
import qualified Data.Set as Set import qualified Data.Set as Set
evalSingle :: Env -> TricuAST -> Env evalSingle :: Env -> TricuAST -> Env
evalSingle env term evalSingle env term
| SFunc name [] body <- term = | SDef name [] body <- term =
if if
| Map.member name env -> | Map.member name env ->
errorWithoutStackTrace $ errorWithoutStackTrace $
"Error: Identifier '" ++ name ++ "' is already defined." "Error: Identifier '" ++ name ++ "' is already defined."
| otherwise -> | otherwise ->
let res = evalAST env body let res = evalAST env body
in Map.insert "__result" res (Map.insert name res env) in Map.insert "__result" res (Map.insert name res env)
| SApp func arg <- term = | SApp func arg <- term =
@ -23,18 +23,23 @@ evalSingle env term
in Map.insert "__result" res env in Map.insert "__result" res env
| SVar name <- term = | SVar name <- term =
case Map.lookup name env of case Map.lookup name env of
Just v -> Map.insert "__result" v env Just v ->
Nothing -> errorWithoutStackTrace $ "Variable `" ++ name ++ "` not defined" Map.insert "__result" v env
Nothing ->
errorWithoutStackTrace $ "Variable `" ++ name ++ "` not defined\n\
\This error should never occur here. Please report this as an issue."
| otherwise = | otherwise =
Map.insert "__result" (evalAST env term) env Map.insert "__result" (evalAST env term) env
evalTricu :: Env -> [TricuAST] -> Env evalTricu :: Env -> [TricuAST] -> Env
evalTricu env [] = env evalTricu env x = go env (reorderDefs env x)
evalTricu env [x] = where
let updatedEnv = evalSingle env x go env [] = env
in Map.insert "__result" (result updatedEnv) updatedEnv go env [x] =
evalTricu env (x:xs) = let updatedEnv = evalSingle env x
evalTricu (evalSingle env x) xs in Map.insert "__result" (result updatedEnv) updatedEnv
go env (x:xs) =
evalTricu (evalSingle env x) xs
evalAST :: Env -> TricuAST -> T evalAST :: Env -> TricuAST -> T
evalAST env term evalAST env term
@ -61,13 +66,13 @@ elimLambda = go
go (SLambda [v] (SApp f (SVar x))) go (SLambda [v] (SApp f (SVar x)))
| v == x && not (isFree v f) = elimLambda f | v == x && not (isFree v f) = elimLambda f
-- Triage optimization -- Triage optimization
go (SLambda [a] (SLambda [b] (SLambda [c] body))) go (SLambda [a] (SLambda [b] (SLambda [c] body)))
| body == triageBody = _TRIAGE | body == triageBody = _TRIAGE
where where
triageBody = triageBody =
(SApp (SApp TLeaf (SApp (SApp TLeaf (SVar a)) (SVar b))) (SVar c)) (SApp (SApp TLeaf (SApp (SApp TLeaf (SVar a)) (SVar b))) (SVar c))
-- Composition optimization -- Composition optimization
go (SLambda [f] (SLambda [g] (SLambda [x] body))) go (SLambda [f] (SLambda [g] (SLambda [x] body)))
| body == composeBody = _COMPOSE | body == composeBody = _COMPOSE
where where
composeBody = SApp (SVar f) (SApp (SVar g) (SVar x)) composeBody = SApp (SVar f) (SApp (SVar g) (SVar x))
@ -93,20 +98,89 @@ elimLambda = go
_I = parseSingle "t (t (t t)) t" _I = parseSingle "t (t (t t)) t"
_TRIAGE = parseSingle "t (t (t t (t (t (t t t))))) t" _TRIAGE = parseSingle "t (t (t t (t (t (t t t))))) t"
_COMPOSE = parseSingle "t (t (t t (t (t (t t t)) t))) (t t)" _COMPOSE = parseSingle "t (t (t t (t (t (t t t)) t))) (t t)"
isFree x = Set.member x . freeVars isFree :: String -> TricuAST -> Bool
freeVars (SVar v ) = Set.singleton v isFree x = Set.member x . freeVars
freeVars (SInt _ ) = Set.empty
freeVars (SStr _ ) = Set.empty freeVars :: TricuAST -> Set.Set String
freeVars (SList s ) = foldMap freeVars s freeVars (SVar v ) = Set.singleton v
freeVars (SApp f a ) = freeVars f <> freeVars a freeVars (SInt _ ) = Set.empty
freeVars (TLeaf ) = Set.empty freeVars (SStr _ ) = Set.empty
freeVars (SFunc _ _ b) = freeVars b freeVars (SList s ) = foldMap freeVars s
freeVars (TStem t ) = freeVars t freeVars (SApp f a ) = freeVars f <> freeVars a
freeVars (TFork l r ) = freeVars l <> freeVars r freeVars (TLeaf ) = Set.empty
freeVars (SLambda v b ) = foldr Set.delete (freeVars b) v freeVars (SDef _ _ b) = freeVars b
freeVars (TStem t ) = freeVars t
freeVars (TFork l r ) = freeVars l <> freeVars r
freeVars (SLambda v b ) = foldr Set.delete (freeVars b) v
reorderDefs :: Env -> [TricuAST] -> [TricuAST]
reorderDefs env defs
| not (null missingDeps) =
errorWithoutStackTrace $
"Missing dependencies detected: " ++ show missingDeps
| otherwise = orderedDefs ++ others
where
(defsOnly, others) = partition isDef defs
graph = buildDepGraph defsOnly
sortedDefs = sortDeps graph
defMap = Map.fromList [(name, def) | def@(SDef name _ _) <- defsOnly]
orderedDefs = map (\name -> defMap Map.! name) sortedDefs
topDefNames = Set.fromList (Map.keys defMap)
envNames = Set.fromList (Map.keys env)
freeVarsDefs = foldMap (\(SDef _ _ body) -> freeVars body) defsOnly
freeVarsOthers = foldMap freeVars others
allFreeVars = freeVarsDefs <> freeVarsOthers
validNames = topDefNames `Set.union` envNames
missingDeps = Set.toList (allFreeVars `Set.difference` validNames)
isDef (SDef _ _ _) = True
isDef _ = False
buildDepGraph :: [TricuAST] -> Map.Map String (Set.Set String)
buildDepGraph topDefs
| not (null duplicateNames) =
errorWithoutStackTrace $
"Duplicate definitions detected: " ++ show duplicateNames
| otherwise =
Map.fromList
[ (name, depends topDefs (SDef name [] body))
| SDef name _ body <- topDefs]
where
names = [name | SDef name _ _ <- topDefs]
duplicateNames =
[ name | (name, count) <- Map.toList (countOccurrences names) , count > 1]
countOccurrences = foldr (\x -> Map.insertWith (+) x 1) Map.empty
sortDeps :: Map.Map String (Set.Set String) -> [String]
sortDeps graph = go [] (Map.keys graph)
where
go sorted [] = sorted
go sorted remaining
| null ready =
errorWithoutStackTrace
"ERROR: Top-level cyclic dependency detected and prohibited\n\
\RESOLVE: Use nested lambdas"
| otherwise = go (sorted ++ ready) notReady
where
ready = [ name | name <- remaining
, all (`elem` sorted) (Set.toList (graph Map.! name))]
notReady =
[ name | name <- remaining , name `notElem` ready]
depends :: [TricuAST] -> TricuAST -> Set.Set String
depends topDefs (SDef _ _ body) =
Set.intersection
(Set.fromList [n | SDef n _ _ <- topDefs])
(freeVars body)
depends _ _ = Set.empty
result :: Env -> T result :: Env -> T
result r = case Map.lookup "__result" r of result r = case Map.lookup "__result" r of
Just a -> a Just a -> a
Nothing -> errorWithoutStackTrace "No __result field found in provided environment" Nothing -> errorWithoutStackTrace "No __result field found in provided env"
mainResult :: Env -> T
mainResult r = case Map.lookup "main" r of
Just a -> a
Nothing -> errorWithoutStackTrace "No valid definition for `main` found."

View File

@ -13,9 +13,9 @@ evaluateFileResult filePath = do
contents <- readFile filePath contents <- readFile filePath
let asts = parseTricu contents let asts = parseTricu contents
let finalEnv = evalTricu Map.empty asts let finalEnv = evalTricu Map.empty asts
case Map.lookup "__result" finalEnv of case Map.lookup "main" finalEnv of
Just finalResult -> return finalResult Just finalResult -> return finalResult
Nothing -> errorWithoutStackTrace "No expressions to evaluate found" Nothing -> errorWithoutStackTrace "No `main` function detected"
evaluateFile :: FilePath -> IO Env evaluateFile :: FilePath -> IO Env
evaluateFile filePath = do evaluateFile filePath = do

View File

@ -1,6 +1,6 @@
module Main where module Main where
import Eval (evalTricu, result) import Eval (evalTricu, mainResult, result)
import FileEval import FileEval
import Parser (parseTricu) import Parser (parseTricu)
import REPL import REPL
@ -16,7 +16,7 @@ import qualified Data.Map as Map
data TricuArgs data TricuArgs
= Repl = Repl
| Evaluate { file :: [FilePath], form :: EvaluatedForm } | Evaluate { file :: [FilePath], form :: EvaluatedForm }
| Decode { file :: [FilePath] } | TDecode { file :: [FilePath] }
deriving (Show, Data, Typeable) deriving (Show, Data, Typeable)
replMode :: TricuArgs replMode :: TricuArgs
@ -31,7 +31,7 @@ evaluateMode = Evaluate
\ Defaults to stdin." \ Defaults to stdin."
&= name "f" &= typ "FILE" &= name "f" &= typ "FILE"
, form = TreeCalculus &= typ "FORM" , form = TreeCalculus &= typ "FORM"
&= help "Optional output form: (tree|fsl|ast|ternary|ascii).\n \ &= help "Optional output form: (tree|fsl|ast|ternary|ascii|decode).\n \
\ Defaults to tricu-compatible `t` tree form." \ Defaults to tricu-compatible `t` tree form."
&= name "t" &= name "t"
} }
@ -40,7 +40,7 @@ evaluateMode = Evaluate
&= name "eval" &= name "eval"
decodeMode :: TricuArgs decodeMode :: TricuArgs
decodeMode = Decode decodeMode = TDecode
{ file = def { file = def
&= help "Optional input file path to attempt decoding.\n \ &= help "Optional input file path to attempt decoding.\n \
\ Defaults to stdin." \ Defaults to stdin."
@ -70,10 +70,10 @@ main = do
(filePath:restFilePaths) -> do (filePath:restFilePaths) -> do
initialEnv <- evaluateFile filePath initialEnv <- evaluateFile filePath
finalEnv <- foldM evaluateFileWithContext initialEnv restFilePaths finalEnv <- foldM evaluateFileWithContext initialEnv restFilePaths
pure $ result finalEnv pure $ mainResult finalEnv
let fRes = formatResult form result let fRes = formatResult form result
putStr fRes putStr fRes
Decode { file = filePaths } -> do TDecode { file = filePaths } -> do
value <- case filePaths of value <- case filePaths of
[] -> getContents [] -> getContents
(filePath:_) -> readFile filePath (filePath:_) -> readFile filePath

View File

@ -112,7 +112,7 @@ parseFunctionM = do
_ <- satisfyM (== LAssign) _ <- satisfyM (== LAssign)
scnParserM scnParserM
body <- parseExpressionM body <- parseExpressionM
pure (SFunc name (map getIdentifier args) body) pure (SDef name (map getIdentifier args) body)
parseLambdaM :: ParserM TricuAST parseLambdaM :: ParserM TricuAST
parseLambdaM = do parseLambdaM = do

View File

@ -59,10 +59,3 @@ repl env = runInputT defaultSettings (loop env)
strip :: String -> String strip :: String -> String
strip = dropWhileEnd isSpace . dropWhile isSpace strip = dropWhileEnd isSpace . dropWhile isSpace
decodeResult :: T -> String
decodeResult tc
| Right num <- toNumber tc = show num
| Right str <- toString tc = "\"" ++ str ++ "\""
| Right list <- toList tc = "[" ++ intercalate ", " (map decodeResult list) ++ "]"
| otherwise = formatResult TreeCalculus tc

View File

@ -19,7 +19,7 @@ data TricuAST
| SInt Int | SInt Int
| SStr String | SStr String
| SList [TricuAST] | SList [TricuAST]
| SFunc String [String] TricuAST | SDef String [String] TricuAST
| SApp TricuAST TricuAST | SApp TricuAST TricuAST
| TLeaf | TLeaf
| TStem TricuAST | TStem TricuAST
@ -45,7 +45,7 @@ data LToken
deriving (Show, Eq, Ord) deriving (Show, Eq, Ord)
-- Output formats -- Output formats
data EvaluatedForm = TreeCalculus | FSL | AST | Ternary | Ascii data EvaluatedForm = TreeCalculus | FSL | AST | Ternary | Ascii | Decode
deriving (Show, Data, Typeable) deriving (Show, Data, Typeable)
-- Environment containing previously evaluated TC terms -- Environment containing previously evaluated TC terms
@ -115,6 +115,7 @@ formatResult FSL = show
formatResult AST = show . toAST formatResult AST = show . toAST
formatResult Ternary = toTernaryString formatResult Ternary = toTernaryString
formatResult Ascii = toAscii formatResult Ascii = toAscii
formatResult Decode = decodeResult
toSimpleT :: String -> String toSimpleT :: String -> String
toSimpleT s = T.unpack toSimpleT s = T.unpack
@ -147,4 +148,9 @@ toAscii tree = go tree "" True
++ go left (prefix ++ (if isLast then " " else "| ")) False ++ go left (prefix ++ (if isLast then " " else "| ")) False
++ go right (prefix ++ (if isLast then " " else "| ")) True ++ go right (prefix ++ (if isLast then " " else "| ")) True
-- Utility decodeResult :: T -> String
decodeResult tc
| Right num <- toNumber tc = show num
| Right str <- toString tc = "\"" ++ str ++ "\""
| Right list <- toList tc = "[" ++ intercalate ", " (map decodeResult list) ++ "]"
| otherwise = formatResult TreeCalculus tc

View File

@ -85,7 +85,7 @@ parser = testGroup "Parser Tests"
, testCase "Parse function definitions" $ do , testCase "Parse function definitions" $ do
let input = "x = (\\a b c : a)" let input = "x = (\\a b c : a)"
expect = SFunc "x" [] (SLambda ["a"] (SLambda ["b"] (SLambda ["c"] (SVar "a")))) expect = SDef "x" [] (SLambda ["a"] (SLambda ["b"] (SLambda ["c"] (SVar "a"))))
parseSingle input @?= expect parseSingle input @?= expect
, testCase "Parse nested Tree Calculus terms" $ do , testCase "Parse nested Tree Calculus terms" $ do
@ -105,7 +105,7 @@ parser = testGroup "Parser Tests"
, testCase "Parse function with applications" $ do , testCase "Parse function with applications" $ do
let input = "f = (\\x : t x)" let input = "f = (\\x : t x)"
expect = SFunc "f" [] (SLambda ["x"] (SApp TLeaf (SVar "x"))) expect = SDef "f" [] (SLambda ["x"] (SApp TLeaf (SVar "x")))
parseSingle input @?= expect parseSingle input @?= expect
, testCase "Parse nested lists" $ do , testCase "Parse nested lists" $ do
@ -147,7 +147,7 @@ parser = testGroup "Parser Tests"
, testCase "Parse nested parentheses in function body" $ do , testCase "Parse nested parentheses in function body" $ do
let input = "f = (\\x : t (t (t t)))" let input = "f = (\\x : t (t (t t)))"
expect = SFunc "f" [] (SLambda ["x"] (SApp TLeaf (SApp TLeaf (SApp TLeaf TLeaf)))) expect = SDef "f" [] (SLambda ["x"] (SApp TLeaf (SApp TLeaf (SApp TLeaf TLeaf))))
parseSingle input @?= expect parseSingle input @?= expect
, testCase "Parse lambda abstractions" $ do , testCase "Parse lambda abstractions" $ do
@ -157,12 +157,12 @@ parser = testGroup "Parser Tests"
, testCase "Parse multiple arguments to lambda abstractions" $ do , testCase "Parse multiple arguments to lambda abstractions" $ do
let input = "x = (\\a b : a)" let input = "x = (\\a b : a)"
expect = SFunc "x" [] (SLambda ["a"] (SLambda ["b"] (SVar "a"))) expect = SDef "x" [] (SLambda ["a"] (SLambda ["b"] (SVar "a")))
parseSingle input @?= expect parseSingle input @?= expect
, testCase "Grouping T terms with parentheses in function application" $ do , testCase "Grouping T terms with parentheses in function application" $ do
let input = "x = (\\a : a)\nx (t)" let input = "x = (\\a : a)\nx (t)"
expect = [SFunc "x" [] (SLambda ["a"] (SVar "a")),SApp (SVar "x") TLeaf] expect = [SDef "x" [] (SLambda ["a"] (SVar "a")),SApp (SVar "x") TLeaf]
parseTricu input @?= expect parseTricu input @?= expect
, testCase "Comments 1" $ do , testCase "Comments 1" $ do
@ -488,8 +488,9 @@ fileEval = testGroup "File evaluation tests"
res @?= Fork (Stem Leaf) Leaf res @?= Fork (Stem Leaf) Leaf
, testCase "Mapping and Equality" $ do , testCase "Mapping and Equality" $ do
res <- liftIO $ evaluateFileResult "./test/map.tri" library <- liftIO $ evaluateFile "./lib/base.tri"
res @?= Stem Leaf fEnv <- liftIO $ evaluateFileWithContext library "./test/map.tri"
(mainResult fEnv) @?= Stem Leaf
, testCase "Eval and decoding string" $ do , testCase "Eval and decoding string" $ do
library <- liftIO $ evaluateFile "./lib/base.tri" library <- liftIO $ evaluateFile "./lib/base.tri"

View File

@ -2,7 +2,7 @@
-- t (t t) (t (t t t)) -- t (t t) (t (t t t))
-- t (t t t) (t t) -- t (t t t) (t t)
-- x = (\a : a) -- x = (\a : a)
t (t t) t -- Fork (Stem Leaf) Leaf main = t (t t) t -- Fork (Stem Leaf) Leaf
-- t t -- t t
-- x -- x
-- x = (\a : a) -- x = (\a : a)

View File

@ -1 +1 @@
t t t main = t t t

View File

@ -1,24 +1,2 @@
false = t
true = t t
_ = t
k = t t
i = t (t k) t
s = t (t (k t)) t
m = s i i
b = s (k s) k
c = s (s (k s) (s (k k) s)) (k k)
iC = (\a b c : s a (k c) b)
yi = (\i : b m (c b (i m)))
y = yi iC
triage = (\a b c : t (t a b) c)
pair = t
matchList = (\oe oc : triage oe _ oc)
lconcat = y (\self : matchList (\k : k) (\h r k : pair h (self r k)))
hmap = y (\self : matchList (\f : t) (\hd tl f : pair (f hd) (self tl f)))
map = (\f l : hmap l f)
lAnd = triage (\x : false) (\_ x : x) (\_ _ x : x)
lOr = triage (\x : x) (\_ _ : true) (\_ _ x : true)
equal = y (\self : triage (triage true (\z : false) (\y z : false)) (\ax : triage false (self ax) (\y z : false)) (\ax ay : triage false (\z : false) (\bx by : lAnd (self ax bx) (self ay by))))
x = map (\i : lconcat "Successfully concatenated " i) [("two strings!")] x = map (\i : lconcat "Successfully concatenated " i) [("two strings!")]
equal x [("Successfully concatenated two strings!")] main = equal? x [("Successfully concatenated two strings!")]

21
test/size.tri Normal file
View File

@ -0,0 +1,21 @@
compose = \f g x : f (g x)
succ = y (\self :
triage
1
t
(triage
(t (t t))
(\_ tail : t t (self tail))
t))
size = (\x :
(y (\self x :
compose succ
(triage
(\x : x)
self
(\x y : compose (self x) (self y))
x)) x 0))
size size

1
test/undefined.tri Normal file
View File

@ -0,0 +1 @@
namedTerm = undefinedForTesting

View File

@ -1,7 +1,7 @@
cabal-version: 1.12 cabal-version: 1.12
name: tricu name: tricu
version: 0.9.0 version: 0.11.0
description: A micro-language for exploring Tree Calculus description: A micro-language for exploring Tree Calculus
author: James Eversole author: James Eversole
maintainer: james@eversole.co maintainer: james@eversole.co