Compare commits

..

No commits in common. "main" and "0.18.0" have entirely different histories.
main ... 0.18.0

22 changed files with 266 additions and 298 deletions

View File

@ -11,11 +11,12 @@ tricu is the word for "tree" in Lojban: `(x1) is a tree of species/cultivar (x2)
## Features
- Tree Calculus operator: `t`
- Immutable definitions: `x = t t`
- Lambda abstraction: `id = (a : a)`
- Assignments: `x = t t`
- Immutable definitions
- Lambda abstraction syntax: `id = (\a : a)`
- List, Number, and String literals: `[(2) ("Hello")]`
- Function application: `not (not false)`
- Higher order/first-class functions: `map (a : append a "!") [("Hello")]`
- Higher order/first-class functions: `map (\a : append a "!") [("Hello")]`
- Intensionality blurs the distinction between functions and data (see REPL examples)
- Simple module system for code organization
@ -23,15 +24,15 @@ tricu is the word for "tree" in Lojban: `(x1) is a tree of species/cultivar (x2)
```
tricu < -- Anything after `--` on a single line is a comment
tricu < id = (a : a) -- Lambda abstraction is eliminated to tree calculus terms
tricu < head (map (i : append i " world!") [("Hello, ")])
tricu < id = (\a : a) -- Lambda abstraction is eliminated to tree calculus terms
tricu < head (map (\i : append i " world!") [("Hello, ")])
tricu > "Hello, world!"
tricu < id (head (map (i : append i " world!") [("Hello, ")]))
tricu < id (head (map (\i : append i " world!") [("Hello, ")]))
tricu > "Hello, world!"
tricu < -- Intensionality! We can inspect the structure of a function or data.
tricu < triage = (a b c : t (t a b) c)
tricu < test = triage "Leaf" (z : "Stem") (a b : "Fork")
tricu < triage = (\a b c : t (t a b) c)
tricu < test = triage "Leaf" (\z : "Stem") (\a b : "Fork")
tricu < test (t t)
tricu > "Stem"
tricu < -- We can even convert a term back to source code (/demos/toSource.tri)
@ -54,7 +55,9 @@ tricu < !version -- Print tricu version
## Installation and Use
You can easily build and run this project using [Nix](https://nixos.org/download/).
[Releases are available for Linux.](https://git.eversole.co/James/tricu/releases)
Or you can easily build and run this project using [Nix](https://nixos.org/download/).
- Quick Start (REPL):
- `nix run git+https://git.eversole.co/James/tricu`

View File

@ -11,17 +11,20 @@ demo_true = t t
not_TC? = t (t (t t) (t t t)) (t t (t t t))
-- /demos/toSource.tri contains an explanation of `triage`
demo_triage = a b c : t (t a b) c
demo_matchBool = a b : demo_triage b (_ : a) (_ _ : a)
demo_triage = \a b c : t (t a b) c
demo_matchBool = (\ot of : demo_triage
of
(\_ : ot)
(\_ _ : ot)
)
-- Lambda representation of the Boolean `not` function
not_Lambda? = demo_matchBool demo_false demo_true
-- As tricu eliminates Lambda terms to SKI combinators, the tree form of many
-- Since tricu eliminates Lambda terms to SKI combinators, the tree form of many
-- functions defined via Lambda terms are larger than the most efficient TC
-- representation possible. Between different languages that evaluate to tree
-- calculus terms, the exact implementation of Lambda elimination may differ
-- and lead to different trees even if they share extensional behavior.
-- representation. Between different languages that evaluate to tree calculus
-- terms, the exact implementation of Lambda elimination may differ and lead
-- to different tree representations even if they share extensional behavior.
-- Let's see if these are the same:
lambdaEqualsTC = equal? not_TC? not_Lambda?

View File

@ -18,15 +18,15 @@ main = exampleTwo
-- / / \
-- 4 5 6
label = node : head node
label = \node : head node
left = node : (if (emptyList? node)
left = (\node : if (emptyList? node)
[]
(if (emptyList? (tail node))
[]
(head (tail node))))
right = node : (if (emptyList? node)
right = (\node : if (emptyList? node)
[]
(if (emptyList? (tail node))
[]
@ -34,25 +34,25 @@ right = node : (if (emptyList? node)
[]
(head (tail (tail node))))))
processLevel = y (self queue : if (emptyList? queue)
processLevel = y (\self queue : if (emptyList? queue)
[]
(pair (map label queue) (self (filter
(node : not? (emptyList? node))
(\node : not? (emptyList? node))
(append (map left queue) (map right queue))))))
levelOrderTraversal_ = a : processLevel (t a t)
levelOrderTraversal_ = \a : processLevel (t a t)
toLineString = y (self levels : if (emptyList? levels)
toLineString = y (\self levels : if (emptyList? levels)
""
(append
(append (map (x : append x " ") (head levels)) "")
(append (map (\x : append x " ") (head levels)) "")
(if (emptyList? (tail levels)) "" (append (t (t 10 t) t) (self (tail levels))))))
levelOrderToString = s : toLineString (levelOrderTraversal_ s)
levelOrderToString = \s : toLineString (levelOrderTraversal_ s)
flatten = foldl (acc x : append acc x) ""
flatten = foldl (\acc x : append acc x) ""
levelOrderTraversal = s : append (t 10 t) (flatten (levelOrderToString s))
levelOrderTraversal = \s : append (t 10 t) (flatten (levelOrderToString s))
exampleOne = levelOrderTraversal [("1")
[("2") [("4") t t] t]

View File

@ -1,37 +0,0 @@
!import "../lib/patterns.tri" !Local
-- We can do conditional pattern matching by providing a list of lists, where
-- each sublist contains a boolean expression and a function to return if said
-- boolean expression evaluates to true.
value = 42
main = match value [[(equal? "Hello") (_ : ", world!")] [(equal? 42) (_ : "The answer.")]]
-- < main
-- > "The answer."
matchExample = (x : match x
[[(equal? 1) (_ : "one")]
[(equal? 2) (_ : "two")]
[(equal? 3) (_ : "three")]
[(equal? 4) (_ : "four")]
[(equal? 5) (_ : "five")]
[(equal? 6) (_ : "six")]
[(equal? 7) (_ : "seven")]
[(equal? 8) (_ : "eight")]
[(equal? 9) (_ : "nine")]
[(equal? 10) (_ : "ten")]
[ otherwise (_ : "I ran out of fingers!")]])
-- < matchExample 3
-- > "three"
-- < matchExample 5
-- > "five"
-- < matchExample 9
-- > "nine"
-- < matchExample 11
-- > "I ran out of fingers!"
-- < matchExample "three"
-- > "I ran out of fingers!"
-- < matchExample [("hello") ("world")]
-- > "I ran out of fingers!"

View File

@ -3,9 +3,11 @@
main = size size
size = x : y (self x : compose succ (triage
id
size = (\x :
(y (\self x :
compose succ
(triage
(\x : x)
self
(x y : compose (self x) (self y))
x)
) x 0
(\x y : compose (self x) (self y))
x)) x 0))

View File

@ -18,25 +18,25 @@ main = toSource not?
sourceLeaf = t (head "t")
-- Stem case
sourceStem = convert : (a rest :
sourceStem = (\convert : (\a rest :
t (head "(") -- Start with a left parenthesis "(".
(t (head "t") -- Add a "t"
(t (head " ") -- Add a space.
(convert a -- Recursively convert the argument.
(t (head ")") rest))))) -- Close with ")" and append the rest.
(t (head ")") rest)))))) -- Close with ")" and append the rest.
-- Fork case
sourceFork = convert : (a b rest :
sourceFork = (\convert : (\a b rest :
t (head "(") -- Start with a left parenthesis "(".
(t (head "t") -- Add a "t"
(t (head " ") -- Add a space.
(convert a -- Recursively convert the first arg.
(t (head " ") -- Add another space.
(convert b -- Recursively convert the second arg.
(t (head ")") rest))))))) -- Close with ")" and append the rest.
(t (head ")") rest)))))))) -- Close with ")" and append the rest.
-- Wrapper around triage
toSource_ = y (self arg :
toSource_ = y (\self arg :
triage
sourceLeaf -- `triage` "a" case, Leaf
(sourceStem self) -- `triage` "b" case, Stem
@ -44,7 +44,7 @@ toSource_ = y (self arg :
arg) -- The term to be inspected
-- toSource takes a single TC term and returns a String
toSource = v : toSource_ v ""
toSource = \v : toSource_ v ""
exampleOne = toSource true -- OUT: "(t t)"
exampleTwo = toSource not? -- OUT: "(t (t (t t) (t t t)) (t t (t t t)))"

View File

@ -2,46 +2,57 @@
description = "tricu";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs";
flake-utils.url = "github:numtide/flake-utils";
nixpkgs = {
url = "https://github.com/nh2/nixpkgs/archive/ede5282c487a1fd2de64303ba59adad6726f1225.tar.gz";
type = "tarball";
flake = false;
};
static-haskell-nix = {
url = "github:nh2/static-haskell-nix";
flake = false;
};
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
outputs = { self, nixpkgs, static-haskell-nix }:
let
pkgs = nixpkgs.legacyPackages.${system};
system = "x86_64-linux";
compiler = "ghc948";
packageName = "tricu";
containerPackageName = "${packageName}-container";
customGHC = pkgs.haskellPackages.ghcWithPackages (hpkgs: with hpkgs; [
megaparsec
]);
overlay = self: super: {
haskell = super.haskell // {
packages = super.haskell.packages // {
${compiler} = super.haskell.packages.${compiler}.override {
overrides = final: prev: {
${packageName} = prev.callCabal2nix packageName ./. {};
};
};
};
};
};
haskellPackages = pkgs.haskellPackages;
overlays = [overlay];
enableSharedExecutables = false;
enableSharedLibraries = false;
normalPkgs = import nixpkgs { inherit overlays system; };
survey = import "${static-haskell-nix}/survey" { inherit compiler normalPkgs; };
tricuStatic = survey.haskellPackages.${packageName};
tricu = pkgs.haskell.lib.justStaticExecutables self.packages.${system}.default;
in {
packages.${system}.default = tricuStatic;
packages.${packageName} =
haskellPackages.callCabal2nix packageName self rec {};
packages.default = self.packages.${system}.${packageName};
defaultPackage = self.packages.${system}.default;
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
haskellPackages.cabal-install
haskellPackages.ghc-events
haskellPackages.ghcid
customGHC
upx
devShells.default = normalPkgs.mkShell {
buildInputs = with normalPkgs; [
normalPkgs.haskellPackages.cabal-install
normalPkgs.haskellPackages.ghc-events
normalPkgs.haskellPackages.ghcid
normalPkgs.upx
];
inputsFrom = builtins.attrValues self.packages.${system};
};
devShell = self.devShells.${system}.default;
});
devShell = self.devShells.${system}.default;
};
}

View File

@ -1,74 +1,74 @@
false = t
_ = t
true = t t
id = a : a
const = a b : a
id = \a : a
const = \a b : a
pair = t
if = cond then else : t (t else (t t then)) t cond
if = \cond then else : t (t else (t t then)) t cond
y = ((mut wait fun : wait mut (x : fun (wait mut x)))
(x : x x)
(a0 a1 a2 : t (t a0) (t t a2) a1))
y = ((\mut wait fun : wait mut (\x : fun (wait mut x)))
(\x : x x)
(\a0 a1 a2 : t (t a0) (t t a2) a1))
compose = f g x : f (g x)
compose = \f g x : f (g x)
triage = leaf stem fork : t (t leaf stem) fork
test = triage "Leaf" (_ : "Stem") (_ _ : "Fork")
triage = \leaf stem fork : t (t leaf stem) fork
test = triage "Leaf" (\_ : "Stem") (\_ _ : "Fork")
matchBool = (ot of : triage
matchBool = (\ot of : triage
of
(_ : ot)
(_ _ : ot)
(\_ : ot)
(\_ _ : ot)
)
lAnd = (triage
(_ : false)
(_ x : x)
(_ _ x : x))
(\_ : false)
(\_ x : x)
(\_ _ x : x))
lOr = (triage
(x : x)
(_ _ : true)
(_ _ _ : true))
(\x : x)
(\_ _ : true)
(\_ _ _ : true))
matchPair = a : triage _ _ a
matchPair = \a : triage _ _ a
not? = matchBool false true
and? = matchBool id (_ : false)
and? = matchBool id (\_ : false)
or? = (x z :
or? = (\x z :
matchBool
(matchBool true true z)
(matchBool true false z)
x)
xor? = (x z :
xor? = (\x z :
matchBool
(matchBool false true z)
(matchBool true false z)
x)
equal? = y (self : triage
equal? = y (\self : triage
(triage
true
(_ : false)
(_ _ : false))
(ax :
(\_ : false)
(\_ _ : false))
(\ax :
triage
false
(self ax)
(_ _ : false))
(ax ay :
(\_ _ : false))
(\ax ay :
triage
false
(_ : false)
(bx by : lAnd (self ax bx) (self ay by))))
(\_ : false)
(\bx by : lAnd (self ax bx) (self ay by))))
succ = y (self :
succ = y (\self :
triage
1
t
(triage
(t (t t))
(_ tail : t t (self tail))
(\_ tail : t t (self tail))
t))

View File

@ -1,70 +1,68 @@
!import "base.tri" !Local
_ = t
matchList = \a b : triage a _ b
matchList = a b : triage a _ b
emptyList? = matchList true (\_ _ : false)
head = matchList t (\head _ : head)
tail = matchList t (\_ tail : tail)
emptyList? = matchList true (_ _ : false)
head = matchList t (head _ : head)
tail = matchList t (_ tail : tail)
append = y (\self : matchList
(\k : k)
(\h r k : pair h (self r k)))
append = y (self : matchList
(k : k)
(h r k : pair h (self r k)))
lExist? = y (self x : matchList
lExist? = y (\self x : matchList
false
(h z : or? (equal? x h) (self x z)))
(\h z : or? (equal? x h) (self x z)))
map_ = y (self :
map_ = y (\self :
matchList
(_ : t)
(head tail f : pair (f head) (self tail f)))
map = f l : map_ l f
(\_ : t)
(\head tail f : pair (f head) (self tail f)))
map = \f l : map_ l f
filter_ = y (self : matchList
(_ : t)
(head tail f : matchBool (t head) id (f head) (self tail f)))
filter = f l : filter_ l f
filter_ = y (\self : matchList
(\_ : t)
(\head tail f : matchBool (t head) id (f head) (self tail f)))
filter = \f l : filter_ l f
foldl_ = y (self f l x : matchList (acc : acc) (head tail acc : self f tail (f acc head)) l x)
foldl = f x l : foldl_ f l x
foldl_ = y (\self f l x : matchList (\acc : acc) (\head tail acc : self f tail (f acc head)) l x)
foldl = \f x l : foldl_ f l x
foldr_ = y (self x f l : matchList x (head tail : f (self x f tail) head) l)
foldr = f x l : foldr_ x f l
foldr_ = y (\self x f l : matchList x (\head tail : f (self x f tail) head) l)
foldr = \f x l : foldr_ x f l
length = y (self : matchList
length = y (\self : matchList
0
(_ tail : succ (self tail)))
(\_ tail : succ (self tail)))
reverse = y (self : matchList
reverse = y (\self : matchList
t
(head tail : append (self tail) (pair head t)))
(\head tail : append (self tail) (pair head t)))
snoc = y (self x : matchList
snoc = y (\self x : matchList
(pair x t)
(h z : pair h (self x z)))
(\h z : pair h (self x z)))
count = y (self x : matchList
count = y (\self x : matchList
0
(h z : matchBool
(\h z : matchBool
(succ (self x z))
(self x z)
(equal? x h)))
last = y (self : matchList
last = y (\self : matchList
t
(hd tl : matchBool
(\hd tl : matchBool
hd
(self tl)
(emptyList? tl)))
all? = y (self pred : matchList
all? = y (\self pred : matchList
true
(h z : and? (pred h) (self pred z)))
(\h z : and? (pred h) (self pred z)))
any? = y (self pred : matchList
any? = y (\self pred : matchList
false
(h z : or? (pred h) (self pred z)))
(\h z : or? (pred h) (self pred z)))
intersect = xs ys : filter (x : lExist? x ys) xs
intersect = \xs ys : filter (\x : lExist? x ys) xs

View File

@ -1,24 +1,36 @@
!import "base.tri" !Local
!import "list.tri" List
!import "list.tri" !Local
match_ = y (self value patterns :
match_ = y (\self value patterns :
triage
t
(_ : t)
(pattern rest :
(\_ : t)
(\pattern rest :
triage
t
(_ : t)
(test result :
(\_ : t)
(\test result :
if (test value)
(result value)
(self value rest))
pattern)
patterns)
match = (value patterns :
match_ value (List.map (sublist :
pair (List.head sublist) (List.head (List.tail sublist)))
match = (\value patterns :
match_ value (map (\sublist :
pair (head sublist) (head (tail sublist)))
patterns))
otherwise = const (t t)
matchExample = (\x : match x
[[(equal? 1) (\_ : "one")]
[(equal? 2) (\_ : "two")]
[(equal? 3) (\_ : "three")]
[(equal? 4) (\_ : "four")]
[(equal? 5) (\_ : "five")]
[(equal? 6) (\_ : "six")]
[(equal? 7) (\_ : "seven")]
[(equal? 8) (\_ : "eight")]
[(equal? 9) (\_ : "nine")]
[(equal? 10) (\_ : "ten")]
[ otherwise (\_ : "I ran out of fingers!")]])

View File

@ -41,6 +41,7 @@ tricuLexer = do
, try stringLiteral
, assign
, colon
, backslash
, openParen
, closeParen
, openBracket
@ -93,6 +94,9 @@ assign = char '=' $> LAssign
colon :: Lexer LToken
colon = char ':' $> LColon
backslash :: Lexer LToken
backslash = char '\\' $> LBackslash
openParen :: Lexer LToken
openParen = char '(' $> LOpenParen
@ -122,22 +126,7 @@ integerLiteral = do
stringLiteral :: Lexer LToken
stringLiteral = do
char '"'
content <- manyTill Lexer.charLiteral (char '"')
content <- many (noneOf ['"'])
char '"' --"
return (LStringLiteral content)
charLiteral :: Lexer Char
charLiteral = escapedChar <|> normalChar
where
normalChar = noneOf ['"', '\\']
escapedChar = do
void $ char '\\'
c <- oneOf ['n', 't', 'r', 'f', 'b', '\\', '"', '\'']
return $ case c of
'n' -> '\n'
't' -> '\t'
'r' -> '\r'
'f' -> '\f'
'b' -> '\b'
'\\' -> '\\'
'"' -> '"'
'\'' -> '\''

View File

@ -130,6 +130,7 @@ parseFunctionM = do
parseLambdaM :: ParserM TricuAST
parseLambdaM = do
let ident = (\case LIdentifier _ -> True; _ -> False)
_ <- satisfyM (== LBackslash)
params <- some (satisfyM ident)
_ <- satisfyM (== LColon)
scnParserM
@ -144,11 +145,11 @@ parseLambdaExpressionM = choice
parseAtomicLambdaM :: ParserM TricuAST
parseAtomicLambdaM = choice
[ try parseLambdaM
, parseVarM
[ parseVarM
, parseTreeLeafM
, parseLiteralM
, parseListLiteralM
, try parseLambdaM
, between (satisfyM (== LOpenParen)) (satisfyM (== LCloseParen)) parseLambdaExpressionM
]
@ -204,8 +205,7 @@ parseTreeLeafOrParenthesizedM = choice
parseAtomicM :: ParserM TricuAST
parseAtomicM = choice
[ try parseLambdaM
, parseVarM
[ parseVarM
, parseTreeLeafM
, parseListLiteralM
, parseGroupedM

View File

@ -6,23 +6,24 @@ import Lexer
import Parser
import Research
import Control.Exception (IOException, SomeException, catch
, displayException)
import Control.Exception (IOException, SomeException, catch, displayException)
import Control.Monad (forM_)
import Control.Monad.Catch (handle, MonadCatch)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Catch (handle, MonadCatch)
import Control.Monad.Trans.Class (lift)
import Control.Monad.Trans.Maybe (MaybeT(..), runMaybeT)
import Data.Char (isSpace, isUpper)
import Data.List (dropWhile, dropWhileEnd, isPrefixOf)
import Data.Version (showVersion)
import Paths_tricu (version)
import Data.List ( dropWhile
, dropWhileEnd
, isPrefixOf)
import System.Console.Haskeline
import qualified Data.Map as Map
import Paths_tricu (version)
import Data.Version (showVersion)
import qualified Data.Text as T
import qualified Data.Text.IO as T
import qualified Data.Map as Map
repl :: Env -> IO ()
repl env = runInputT settings (withInterrupt (loop env Decode))
where

View File

@ -38,6 +38,7 @@ data LToken
| LAssign
| LColon
| LDot
| LBackslash
| LOpenParen
| LCloseParen
| LOpenBracket

View File

@ -51,22 +51,7 @@ lexer = testGroup "Lexer Tests"
, testCase "Lex escaped characters in strings" $ do
let input = "\"hello\\nworld\""
expect = Right [LStringLiteral "hello\nworld"]
runParser tricuLexer "" input @?= expect
, testCase "Lex multiple escaped characters in strings" $ do
let input = "\"tab:\\t newline:\\n quote:\\\" backslash:\\\\\""
expect = Right [LStringLiteral "tab:\t newline:\n quote:\" backslash:\\"]
runParser tricuLexer "" input @?= expect
, testCase "Lex escaped characters in string literals" $ do
let input = "x = \"line1\\nline2\\tindented\""
expect = Right [LIdentifier "x", LAssign, LStringLiteral "line1\nline2\tindented"]
runParser tricuLexer "" input @?= expect
, testCase "Lex empty string with escape sequence" $ do
let input = "\"\\\"\""
expect = Right [LStringLiteral "\""]
expect = Right [LStringLiteral "hello\\nworld"]
runParser tricuLexer "" input @?= expect
, testCase "Lex mixed literals" $ do
@ -102,7 +87,7 @@ parser = testGroup "Parser Tests"
Right _ -> assertFailure "Expected failure when trying to assign the value of T"
, testCase "Parse function definitions" $ do
let input = "x = (a b c : a)"
let input = "x = (\\a b c : a)"
expect = SDef "x" [] (SLambda ["a"] (SLambda ["b"] (SLambda ["c"] (SVar "a"))))
parseSingle input @?= expect
@ -122,7 +107,7 @@ parser = testGroup "Parser Tests"
parseSingle input @?= expect
, testCase "Parse function with applications" $ do
let input = "f = (x : t x)"
let input = "f = (\\x : t x)"
expect = SDef "f" [] (SLambda ["x"] (SApp TLeaf (SVar "x")))
parseSingle input @?= expect
@ -164,22 +149,22 @@ parser = testGroup "Parser Tests"
parseSingle input @?= expect
, 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 = SDef "f" [] (SLambda ["x"] (SApp TLeaf (SApp TLeaf (SApp TLeaf TLeaf))))
parseSingle input @?= expect
, testCase "Parse lambda abstractions" $ do
let input = "(a : a)"
let input = "(\\a : a)"
expect = (SLambda ["a"] (SVar "a"))
parseSingle input @?= expect
, testCase "Parse multiple arguments to lambda abstractions" $ do
let input = "x = (a b : a)"
let input = "x = (\\a b : a)"
expect = SDef "x" [] (SLambda ["a"] (SLambda ["b"] (SVar "a")))
parseSingle input @?= expect
, 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 = [SDef "x" [] (SLambda ["a"] (SVar "a")),SApp (SVar "x") TLeaf]
parseTricu input @?= expect
@ -274,7 +259,7 @@ simpleEvaluation = testGroup "Evaluation Tests"
, testCase "Apply identity to Boolean Not" $ do
let not = "(t (t (t t) (t t t)) t)"
let input = "x = (a : a)\nx " ++ not
let input = "x = (\\a : a)\nx " ++ not
env = evalTricu Map.empty (parseTricu input)
result env @?= Fork (Fork (Stem Leaf) (Fork Leaf Leaf)) Leaf
]
@ -282,84 +267,84 @@ simpleEvaluation = testGroup "Evaluation Tests"
lambdas :: TestTree
lambdas = testGroup "Lambda Evaluation Tests"
[ testCase "Lambda Identity Function" $ do
let input = "id = (x : x)\nid t"
let input = "id = (\\x : x)\nid t"
runTricu input @?= "Leaf"
, testCase "Lambda Constant Function (K combinator)" $ do
let input = "k = (x y : x)\nk t (t t)"
let input = "k = (\\x y : x)\nk t (t t)"
runTricu input @?= "Leaf"
, testCase "Lambda Application with Variable" $ do
let input = "id = (x : x)\nval = t t\nid val"
let input = "id = (\\x : x)\nval = t t\nid val"
runTricu input @?= "Stem Leaf"
, testCase "Lambda Application with Multiple Arguments" $ do
let input = "apply = (f x y : f x y)\nk = (a b : a)\napply k t (t t)"
let input = "apply = (\\f x y : f x y)\nk = (\\a b : a)\napply k t (t t)"
runTricu input @?= "Leaf"
, testCase "Nested Lambda Application" $ do
let input = "apply = (f x y : f x y)\nid = (x : x)\napply (f x : f x) id t"
let input = "apply = (\\f x y : f x y)\nid = (\\x : x)\napply (\\f x : f x) id t"
runTricu input @?= "Leaf"
, testCase "Lambda with a complex body" $ do
let input = "f = (x : t (t x))\nf t"
let input = "f = (\\x : t (t x))\nf t"
runTricu input @?= "Stem (Stem Leaf)"
, testCase "Lambda returning a function" $ do
let input = "f = (x : (y : x))\ng = f t\ng (t t)"
let input = "f = (\\x : (\\y : x))\ng = f t\ng (t t)"
runTricu input @?= "Leaf"
, testCase "Lambda with Shadowing" $ do
let input = "f = (x : (x : x))\nf t (t t)"
let input = "f = (\\x : (\\x : x))\nf t (t t)"
runTricu input @?= "Stem Leaf"
, testCase "Lambda returning another lambda" $ do
let input = "k = (x : (y : x))\nk_app = k t\nk_app (t t)"
let input = "k = (\\x : (\\y : x))\nk_app = k t\nk_app (t t)"
runTricu input @?= "Leaf"
, testCase "Lambda with free variables" $ do
let input = "y = t t\nf = (x : y)\nf t"
let input = "y = t t\nf = (\\x : y)\nf t"
runTricu input @?= "Stem Leaf"
, testCase "SKI Composition" $ do
let input = "s = (x y z : x z (y z))\nk = (x y : x)\ni = (x : x)\ncomp = s k i\ncomp t (t t)"
let input = "s = (\\x y z : x z (y z))\nk = (\\x y : x)\ni = (\\x : x)\ncomp = s k i\ncomp t (t t)"
runTricu input @?= "Stem (Stem Leaf)"
, testCase "Lambda with multiple parameters and application" $ do
let input = "f = (a b c : t a b c)\nf t (t t) (t t t)"
let input = "f = (\\a b c : t a b c)\nf t (t t) (t t t)"
runTricu input @?= "Stem Leaf"
, testCase "Lambda with nested application in the body" $ do
let input = "f = (x : t (t (t x)))\nf t"
let input = "f = (\\x : t (t (t x)))\nf t"
runTricu input @?= "Stem (Stem (Stem Leaf))"
, testCase "Lambda returning a function and applying it" $ do
let input = "f = (x : (y : t x y))\ng = f t\ng (t t)"
let input = "f = (\\x : (\\y : t x y))\ng = f t\ng (t t)"
runTricu input @?= "Fork Leaf (Stem Leaf)"
, testCase "Lambda applying a variable" $ do
let input = "id = (x : x)\na = t t\nid a"
let input = "id = (\\x : x)\na = t t\nid a"
runTricu input @?= "Stem Leaf"
, testCase "Nested lambda abstractions in the same expression" $ do
let input = "f = (x : (y : x y))\ng = (z : z)\nf g t"
let input = "f = (\\x : (\\y : x y))\ng = (\\z : z)\nf g t"
runTricu input @?= "Leaf"
, testCase "Lambda applied to string literal" $ do
let input = "f = (x : x)\nf \"hello\""
let input = "f = (\\x : x)\nf \"hello\""
runTricu input @?= "Fork (Fork Leaf (Fork Leaf (Fork Leaf (Fork (Stem Leaf) (Fork Leaf (Fork (Stem Leaf) (Fork (Stem Leaf) Leaf))))))) (Fork (Fork (Stem Leaf) (Fork Leaf (Fork (Stem Leaf) (Fork Leaf (Fork Leaf (Fork (Stem Leaf) (Fork (Stem Leaf) Leaf))))))) (Fork (Fork Leaf (Fork Leaf (Fork (Stem Leaf) (Fork (Stem Leaf) (Fork Leaf (Fork (Stem Leaf) (Fork (Stem Leaf) Leaf))))))) (Fork (Fork Leaf (Fork Leaf (Fork (Stem Leaf) (Fork (Stem Leaf) (Fork Leaf (Fork (Stem Leaf) (Fork (Stem Leaf) Leaf))))))) (Fork (Fork (Stem Leaf) (Fork (Stem Leaf) (Fork (Stem Leaf) (Fork (Stem Leaf) (Fork Leaf (Fork (Stem Leaf) (Fork (Stem Leaf) Leaf))))))) Leaf))))"
, testCase "Lambda applied to integer literal" $ do
let input = "f = (x : x)\nf 42"
let input = "f = (\\x : x)\nf 42"
runTricu input @?= "Fork Leaf (Fork (Stem Leaf) (Fork Leaf (Fork (Stem Leaf) (Fork Leaf (Fork (Stem Leaf) Leaf)))))"
, testCase "Lambda applied to list literal" $ do
let input = "f = (x : x)\nf [t (t t)]"
let input = "f = (\\x : x)\nf [t (t t)]"
runTricu input @?= "Fork Leaf (Fork (Stem Leaf) Leaf)"
, testCase "Lambda containing list literal" $ do
let input = "(a : [(a)]) 1"
let input = "(\\a : [(a)]) 1"
runTricu input @?= "Fork (Fork (Stem Leaf) Leaf) Leaf"
]
@ -434,7 +419,7 @@ providedLibraries = testGroup "Library Tests"
, testCase "List map" $ do
library <- evaluateFile "./lib/list.tri"
let input = "head (tail (map (a : (t t t)) [(t) (t) (t)]))"
let input = "head (tail (map (\\a : (t t t)) [(t) (t) (t)]))"
env = evalTricu library (parseTricu input)
result env @?= Fork Leaf Leaf

View File

@ -1,9 +1,9 @@
-- This is a tricu comment!
-- t (t t) (t (t t t))
-- t (t t t) (t t)
-- x = (a : a)
-- x = (\a : a)
main = t (t t) t -- Fork (Stem Leaf) Leaf
-- t t
-- x
-- x = (a : a)
-- x = (\a : a)
-- t

View File

@ -1 +1 @@
main = (x : x) t
main = (\x : x) t

View File

@ -1,2 +1,2 @@
x = map (i : append "Successfully concatenated " i) [("two strings!")]
x = map (\i : append "Successfully concatenated " i) [("two strings!")]
main = equal? x [("Successfully concatenated two strings!")]

View File

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

View File

@ -1 +1 @@
head (map (i : append "String " i) [("test!")])
head (map (\i : append "String " i) [("test!")])

View File

@ -1 +1 @@
y = x : x
y = \x : x

View File

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