aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMarvin Borner2024-03-25 23:54:19 +0100
committerMarvin Borner2024-03-25 23:54:19 +0100
commit5a2dd4a7e8a6857e8cf32b6fe1524f04962c54cb (patch)
tree2440ddebde48d1cb2ddaba4b7042544f74f48e50
parentd13df6b34ebdc6a2d3dd01b081617fe6e88feda8 (diff)
Add support for context-dependent imports / generics
-rw-r--r--bruijn.cabal2
-rw-r--r--src/Eval.hs30
-rw-r--r--std/Generic/Number.bruijn66
-rw-r--r--std/Number/Binary.bruijn286
-rw-r--r--std/Number/Ternary.bruijn273
-rw-r--r--std/Number/Unary.bruijn126
-rwxr-xr-xstd/test_all.sh2
7 files changed, 310 insertions, 475 deletions
diff --git a/bruijn.cabal b/bruijn.cabal
index e2909c1..f7ea587 100644
--- a/bruijn.cabal
+++ b/bruijn.cabal
@@ -35,7 +35,9 @@ data-files:
std/String.bruijn
std/test_all.sh
std/AIT/Beavers.bruijn
+ std/Generic/Number.bruijn
std/Logic/Binary.bruijn
+ std/Logic/Linear.bruijn
std/Logic/Ternary.bruijn
std/Number/Binary.bruijn
std/Number/Bruijn.bruijn
diff --git a/src/Eval.hs b/src/Eval.hs
index 0a5e8c7..eae03b1 100644
--- a/src/Eval.hs
+++ b/src/Eval.hs
@@ -55,8 +55,8 @@ split a@(_ : _) b@(c : _)
where rest = split a $ tail b
-- TODO: Force naming convention for namespaces/files
-loadFile :: EvalConf -> EnvCache -> IO EnvState
-loadFile conf cache = do
+loadFile :: EvalConf -> EnvCache -> Environment -> IO EnvState
+loadFile conf cache env = do
f <- try $ readFile (_path conf) :: IO (Either IOError String)
case f of
Left exception ->
@@ -64,11 +64,11 @@ loadFile conf cache = do
(ContextualError (ImportError $ show (exception :: IOError))
(Context "" $ _nicePath conf)
)
- >> pure (EnvState (Environment M.empty) conf cache)
+ >> pure (EnvState env conf cache)
Right f' -> eval
(filter (not . null) $ split "\n\n" f')
(EnvState
- (Environment M.empty)
+ env
(conf { _isRepl = False, _evalPaths = _path conf : _evalPaths conf })
cache
)
@@ -200,19 +200,18 @@ evalCommand inp s@(EnvState env@(Environment envDefs) conf cache) = \case
print
(ContextualError (ImportError path) (Context inp $ _nicePath conf))
>> pure s
+ -- paths can never be cached upon input since they may depend on context
+ -- BUT inputs can be loaded from import cache since they would've had missing definitions!
else if M.member path (_imported cache)
then
let (Environment env') = fromJust $ M.lookup path (_imported cache)
in pure $ s { _env = Environment $ M.union env' envDefs }
else do
- EnvState (Environment env') _ cache' <- loadFile
+ EnvState env' _ _ <- loadFile
(conf { _nicePath = path, _path = full })
cache -- TODO: Fix wrong `within` in import error
- let cache'' = cache
- { _imported = M.insert path (Environment env')
- $ M.union (_imported cache) (_imported cache')
- }
- pure $ EnvState (Environment $ M.union env' envDefs) conf cache'' -- import => _isRepl = False
+ env
+ pure $ EnvState env' conf cache -- import => _isRepl = False
Watch path ->
let
monitor mtime = do
@@ -255,6 +254,7 @@ evalCommand inp s@(EnvState env@(Environment envDefs) conf cache) = \case
EnvState (Environment env') _ cache' <- loadFile
(conf { _nicePath = path, _path = full })
cache -- TODO: Fix wrong `within` in import error
+ (Environment M.empty)
let
cache'' = cache
{ _imported = M.insert path (Environment env')
@@ -405,7 +405,9 @@ eval (block : bs) s@(EnvState _ conf _) =
dumpFile :: EvalConf -> (a -> IO ()) -> (Expression -> a) -> IO ()
dumpFile conf wr conv = do
- EnvState (Environment env) _ _ <- loadFile conf (EnvCache M.empty)
+ EnvState (Environment env) _ _ <- loadFile conf
+ (EnvCache M.empty)
+ (Environment M.empty)
case M.lookup entryFunction env of
Nothing -> print $ ContextualError (UndefinedIdentifier entryFunction)
(Context "" (_nicePath conf))
@@ -413,8 +415,10 @@ dumpFile conf wr conv = do
evalFileConf :: EvalConf -> IO ()
evalFileConf conf = do
- EnvState (Environment env) _ _ <- loadFile conf (EnvCache M.empty)
- arg <- encodeStdin
+ EnvState (Environment env) _ _ <- loadFile conf
+ (EnvCache M.empty)
+ (Environment M.empty)
+ arg <- encodeStdin
case M.lookup entryFunction env of
Nothing -> print $ ContextualError (UndefinedIdentifier entryFunction)
(Context "" (_nicePath conf))
diff --git a/std/Generic/Number.bruijn b/std/Generic/Number.bruijn
new file mode 100644
index 0000000..e39fc91
--- /dev/null
+++ b/std/Generic/Number.bruijn
@@ -0,0 +1,66 @@
+# MIT License, Copyright (c) 2024 Marvin Borner
+# generic number template, meant to be :input-ted
+# assumes: zero?, even?, gt?, zero?, eq?, add, compare-case
+
+# TODO: also include std/Number more std/Math etc.? Requires solution for recursive imports
+# then: give numeral systems unary id, match with index-unary
+
+:import std/Combinator .
+:import std/Logic .
+
+# returns true if number is not zero
+not-zero? not! ∘∘ zero? ⧗ Generic → Boolean
+
+≠?‣ not-zero?
+
+# returns true if two numbers are not equal
+not-eq? not! ∘∘ eq? ⧗ Generic → Generic → Boolean
+
+…≠?… not-eq?
+
+# prefix for comparing functions
+?‣ &eq?
+
+# returns true if number is lts than other number
+lt? \gt? ⧗ Generic → Generic → Boolean
+
+…<?… lt?
+
+# returns true if number is lts than or equal to other number
+le? not! ∘∘ gt? ⧗ Generic → Generic → Boolean
+
+…≤?… le?
+
+# returns true if number is gtater than or equal to other number
+ge? \le? ⧗ Generic → Generic → Boolean
+
+…≥?… ge?
+
+# returns 1 if a>b, -1 if a<b and 0 if a=b
+# also: spaceship operator
+compare compare-case (+0) (+1) (-1) ⧗ Generic → Generic → Generic
+
+…<=>… compare
+
+<=>‣ &compare
+
+# returns true if comparison result is equal (EQ)
+c-eq? eq? (+0) ⧗ Generic → Generic
+
+# returns true if comparison result is lts than (LT)
+c-lt? eq? (-1) ⧗ Generic → Generic
+
+# returns true if comparison result is gtater than (GT)
+c-gt? eq? (+1) ⧗ Generic → Generic
+
+# returns max number of two
+max [[(1 ≤? 0) 0 1]] ⧗ Generic → Generic → Generic
+
+# returns min number of two
+min [[(1 ≤? 0) 1 0]] ⧗ Generic → Generic → Generic
+
+# clamps a number between two numbers
+clamp [[[min 1 (max 0 2)]]] ⧗ Generic → Generic → Generic
+
+# returns true if the number is odd (remainder mod 2 == 1)
+odd? ¬‣ ∘ even? ⧗ Generic → Boolean
diff --git a/std/Number/Binary.bruijn b/std/Number/Binary.bruijn
index eb63fe1..87f7312 100644
--- a/std/Number/Binary.bruijn
+++ b/std/Number/Binary.bruijn
@@ -45,33 +45,6 @@ up [[[[[4 1 0 (3 2 1 0)]]]]] ⧗ Bit → Binary → Binary
:test (up b¹ [[[0 2]]]) ([[[1 (0 2)]]])
:test (up b⁰ (+1b)) ((+2b))
-# converts a binary number to a list of bits
-list! [0 z a¹ a⁰] ⧗ Binary → (List Bit)
- z empty
- a¹ [b¹ : 0]
- a⁰ [b⁰ : 0]
-
-:test (list! (+0b)) (empty)
-:test (list! (+6b)) (b⁰ : (b¹ : {}b¹))
-
-# converts a list of bits to a binary number
-binary! foldr up (+0b) ⧗ (List Bit) → Binary
-
-:test (binary! (list! (+0b))) ((+0b))
-:test (binary! (list! (+42b))) ((+42b))
-
-# strips leading 0s from a binary number
-strip [^(0 z a¹ a⁰)] ⧗ Binary → Binary
- z (+0b) : true
- a¹ &[[↑¹1 : false]]
- a⁰ &[[(0 (+0b) ↑⁰1) : 0]]
-
-%‣ strip
-
-:test (%[[[0 2]]]) ((+0b))
-:test (%[[[1 (0 (0 (0 (0 2))))]]]) ((+1b))
-:test (%(+2b)) ((+2b))
-
# returns true if a binary number is zero
zero? [0 true [false] i] ⧗ Binary → Boolean
@@ -88,36 +61,15 @@ lsb [0 b⁰ [b¹] [b⁰]] ⧗ Binary → Bit
:test (lsb (+1b)) (b¹)
:test (lsb (+42b)) (b⁰)
-# extracts most significant bit from a binary number
-# not really useful for binary numbers, but part of interface
-msb [=?0 b⁰ b¹] ⧗ Binary → Bit
-
-:test (msb (+0b)) (b⁰)
-:test (msb (+1b)) (b¹)
-:test (msb (+42b)) (b¹)
-
-# extracts nth bit from a binary number
-nth …!!… ∘ list! ⧗ Binary → Number → Bit
-
-# logical and on two binary numbers
-and! binary! ∘∘ (ψ* zip-with …⋀?… list!) ⧗ Binary → Binary → Binary
-
-…⋀!… and!
-
-:test (and! (+1b) (+0b)) ((+0b))
-:test (and! (+5b) (+4b)) ((+4b))
-:test (and! (+10b) (+12b)) ((+8b))
-
-# logical or on two binary numbers
-# TODO: Fix for numbers with different length (→ zero padding?)
-or! binary! ∘∘ (ψ* zip-with …⋁?… list!) ⧗ Binary → Binary → Binary
-
-…⋁!… or!
+# returns true if the number is even (remainder mod 2 == 0)
+even? ¬‣ ∘ lsb ⧗ Binary → Boolean
-:test (or! (+10b) (+12b)) ((+14b))
+=²?‣ even?
-# :test (or! (+1b) (+0b)) ((+1b))
-# :test (or! (+5b) (+3b)) ((+7b))
+:test (even? (+0b)) (true)
+:test (even? (+1b)) (false)
+:test (even? (+41b)) (false)
+:test (even? (+42b)) (true)
# converts the normal binary representation into abstract
abstract! [0 z a¹ a⁰] ⧗ Binary → AbstractBinary
@@ -154,28 +106,16 @@ eq? [[abs 1 →^0]] ⧗ Binary → Binary → Boolean
:test ([[[1 (0 2)]]] =? [[[1 (0 2)]]]) (true)
:test ([[[1 2]]] =? (+2b)) (false)
-# returns true if two binary numbers are not equal
-not-eq? not! ∘∘ eq? ⧗ Binary → Binary → Boolean
-
-…≠?… not-eq?
-
-:test ((+0b) ≠? (+0b)) (false)
-:test ([[[1 (0 2)]]] ≠? [[[1 (0 2)]]]) (false)
-:test ([[[1 (0 2)]]] ≠? (+2b)) (true)
-
-# prefix for comparing functions
-?‣ &eq?
-
-# adds 1 to a binary number (can introduce leading 0s)
-inc [~(0 z a¹ a⁰)] ⧗ Binary → Binary
- z (+0b) : (+1b)
- a¹ &[[↑¹1 : ↑⁰0]]
- a⁰ &[[↑⁰1 : ↑¹1]]
+# rshifts least significant bit of a binary number
+div² [~(0 z a¹ a⁰)] ⧗ Binary → Binary
+ z (+0b) : (+0b)
+ a¹ &[[↑¹1 : 1]]
+ a⁰ &[[↑⁰1 : 1]]
-++‣ inc
+/²‣ div²
-:test (++(+0b)) ((+1b))
-:test (++(+2b)) ((+3b))
+:test (/²(+6b) =? (+3b)) (true)
+:test (/²(+5b) =? (+2b)) (true)
# subs 1 from a binary number (can introduce leading 0s)
dec [~(0 z a¹ a⁰)] ⧗ Binary → Binary
@@ -189,6 +129,101 @@ dec [~(0 z a¹ a⁰)] ⧗ Binary → Binary
:test (--(+1b)) ([[[0 2]]])
:test (--(+3b)) ((+2b))
+# TODO: Remove (duplicate of std/Conversion because of dep loop)
+binary→ternary [y [[[rec]]] [0] 0 (+0t)] ⧗ Binary → Ternary
+ rec zero? 0 case-end case-rec
+ case-rec even? 0 (2 (1 ∘ (T.mul (+2t))) (div² 0)) (2 (1 ∘ T.inc) (dec 0))
+ case-end 1
+
+# returns eq, gt, lt depending on comparison of two numbers
+# TODO: remove ternary conversion
+compare-case [[[(T.compare-case 2 1 0) ⋔ binary→ternary]]] ⧗ a → b → c → Binary → Binary → d
+
+# returns true if number is greater than other number
+# TODO: remove ternary conversion
+gt? T.gt? ⋔ binary→ternary ⧗ Binary → Binary → Boolean
+
+…>?… gt?
+
+:test ((+1b) >? (+2b)) (false)
+:test ((+2b) >? (+2b)) (false)
+:test ((+3b) >? (+2b)) (true)
+
+# ============================================================================ #
+# most relevant functions are defined - we can now derive from Generic/Number! #
+# ============================================================================ #
+
+:input std/Generic/Number
+
+# converts a binary number to a list of bits
+list! [0 z a¹ a⁰] ⧗ Binary → (List Bit)
+ z empty
+ a¹ [b¹ : 0]
+ a⁰ [b⁰ : 0]
+
+:test (list! (+0b)) (empty)
+:test (list! (+6b)) (b⁰ : (b¹ : {}b¹))
+
+# converts a list of bits to a binary number
+binary! foldr up (+0b) ⧗ (List Bit) → Binary
+
+:test (binary! (list! (+0b))) ((+0b))
+:test (binary! (list! (+42b))) ((+42b))
+
+# strips leading 0s from a binary number
+strip [^(0 z a¹ a⁰)] ⧗ Binary → Binary
+ z (+0b) : true
+ a¹ &[[↑¹1 : false]]
+ a⁰ &[[(0 (+0b) ↑⁰1) : 0]]
+
+%‣ strip
+
+:test (%[[[0 2]]]) ((+0b))
+:test (%[[[1 (0 (0 (0 (0 2))))]]]) ((+1b))
+:test (%(+2b)) ((+2b))
+
+# extracts most significant bit from a binary number
+# not really useful for binary numbers, but part of interface
+msb [=?0 b⁰ b¹] ⧗ Binary → Bit
+
+:test (msb (+0b)) (b⁰)
+:test (msb (+1b)) (b¹)
+:test (msb (+42b)) (b¹)
+
+# extracts nth bit from a binary number
+nth …!!… ∘ list! ⧗ Binary → Number → Bit
+
+# logical and on two binary numbers
+and! binary! ∘∘ (ψ* zip-with …⋀?… list!) ⧗ Binary → Binary → Binary
+
+…⋀!… and!
+
+:test (and! (+1b) (+0b)) ((+0b))
+:test (and! (+5b) (+4b)) ((+4b))
+:test (and! (+10b) (+12b)) ((+8b))
+
+# logical or on two binary numbers
+# TODO: Fix for numbers with different length (→ zero padding?)
+or! binary! ∘∘ (ψ* zip-with …⋁?… list!) ⧗ Binary → Binary → Binary
+
+…⋁!… or!
+
+:test (or! (+10b) (+12b)) ((+14b))
+
+# :test (or! (+1b) (+0b)) ((+1b))
+# :test (or! (+5b) (+3b)) ((+7b))
+
+# adds 1 to a binary number (can introduce leading 0s)
+inc [~(0 z a¹ a⁰)] ⧗ Binary → Binary
+ z (+0b) : (+1b)
+ a¹ &[[↑¹1 : ↑⁰0]]
+ a⁰ &[[↑⁰1 : ↑¹1]]
+
+++‣ inc
+
+:test (++(+0b)) ((+1b))
+:test (++(+2b)) ((+3b))
+
# flips the bits of a binary number (1's complement)
complement [[[[3 2 0 1]]]] ⧗ Binary → Binary
@@ -271,17 +306,6 @@ mul [[1 z a¹ a⁰]] ⧗ Number → Number → Number
:test ((+42b) ⋅ (+0b) =? (+0b)) (true)
:test ((+3b) ⋅ (+11b) =? (+33b)) (true)
-# rshifts least significant bit of a binary number
-div² [~(0 z a¹ a⁰)] ⧗ Binary → Binary
- z (+0b) : (+0b)
- a¹ &[[↑¹1 : 1]]
- a⁰ &[[↑⁰1 : 1]]
-
-/²‣ div²
-
-:test (/²(+6b) =? (+3b)) (true)
-:test (/²(+5b) =? (+2b)) (true)
-
# ceiled integer log2 by counting bits
# also counts leading 0s
log2* [0 (+0b) inc inc] ⧗ Binary → Binary
@@ -295,93 +319,3 @@ log2 log2* ∘ strip ⧗ Binary → Binary
:test ((log2 (+4b)) =? (+3b)) (true)
:test ((log2 (+32b)) =? (+6b)) (true)
:test ((log2 (+48b)) =? (+6b)) (true)
-
-# returns true if the number is even (remainder mod 2 == 0)
-even? ¬‣ ∘ lsb ⧗ Binary → Boolean
-
-=²?‣ even?
-
-:test (even? (+0b)) (true)
-:test (even? (+1b)) (false)
-:test (even? (+41b)) (false)
-:test (even? (+42b)) (true)
-
-# returns true if the number is odd (remainder mod 2 == 1)
-odd? lsb ⧗ Binary → Boolean
-
-≠²?‣ odd?
-
-:test (odd? (+0b)) (false)
-:test (odd? (+1b)) (true)
-:test (odd? (+41b)) (true)
-:test (odd? (+42b)) (false)
-
-# TODO: Remove (duplicate of std/Conversion because of dep loop)
-binary→ternary [y [[[rec]]] [0] 0 (+0t)] ⧗ Binary → Ternary
- rec zero? 0 case-end case-rec
- case-rec odd? 0 (2 (1 ∘ T.inc) (dec 0)) (2 (1 ∘ (T.mul (+2t))) (div² 0))
- case-end 1
-
-# returns true if number is greater than other number
-# TODO: remove ternary conversion
-gt? T.gt? ⋔ binary→ternary ⧗ Binary → Binary → Boolean
-
-…>?… gt?
-
-:test ((+1b) >? (+2b)) (false)
-:test ((+2b) >? (+2b)) (false)
-:test ((+3b) >? (+2b)) (true)
-
-# returns true if number is less than other number
-lt? \gt? ⧗ Binary → Binary → Boolean
-
-…<?… lt?
-
-:test ((+1b) <? (+2b)) (true)
-:test ((+2b) <? (+2b)) (false)
-:test ((+3b) <? (+2b)) (false)
-
-# returns true if number is less than or equal to other number
-le? not! ∘∘ gt? ⧗ Binary → Binary → Boolean
-
-…≤?… le?
-
-:test ((+1b) ≤? (+2b)) (true)
-:test ((+2b) ≤? (+2b)) (true)
-:test ((+3b) ≤? (+2b)) (false)
-
-# returns true if number is greater than or equal to other number
-ge? \le? ⧗ Binary → Binary → Boolean
-
-…≥?… ge?
-
-:test ((+1b) ≥? (+2b)) (false)
-:test ((+2b) ≥? (+2b)) (true)
-:test ((+3b) ≥? (+2b)) (true)
-
-# returns eq, gt, lt depending on comparison of two numbers
-# TODO: remove ternary conversion
-compare-case [[[(T.compare-case 2 1 0) ⋔ binary→ternary]]] ⧗ a → b → c → Binary → Binary → d
-
-# returns 1 if a>b, -1 if a<b and 0 if a=b
-# also: spaceship operator
-compare compare-case (+0) (+1) (-1) ⧗ Binary → Binary → Number
-
-…<=>… compare
-
-<=>‣ &compare
-
-:test (compare (+2b) (+2b)) ((+0))
-:test (compare (+2b) (+1b)) ((+1))
-:test (compare (+1b) (+2b)) ((-1))
-
-# prefix for comparing functions
-# returns max number of two
-max [[(1 ≤? 0) 0 1]] ⧗ Binary → Binary → Binary
-
-:test (max (+5b) (+2b)) ((+5b))
-
-# returns min number of two
-min [[(1 ≤? 0) 1 0]] ⧗ Binary → Binary → Binary
-
-:test (min (+5b) (+2b)) ((+2b))
diff --git a/std/Number/Ternary.bruijn b/std/Number/Ternary.bruijn
index 03af0e9..27da643 100644
--- a/std/Number/Ternary.bruijn
+++ b/std/Number/Ternary.bruijn
@@ -79,61 +79,19 @@ t⁰? [0 false false true] ⧗ Trit → Boolean
# rshifts a zero trit into a balanced ternary number (pad)
→⁰‣ [[[[[4 (0 3) 2 1 0]]]]] ⧗ Number → Number
-# infinity
-# WARNING: using this mostly results in undefined behavior! (TODO?)
-infty z [[[[[1 (4 1)]]]]] ⧗ Number
-
-# negates a balanced ternary number
-negate [[[[[4 3 1 2 0]]]]] ⧗ Number → Number
-
--‣ negate
-
-:test (-(+0)) ((+0))
-:test (-(-1)) ((+1))
-:test (-(+42)) ((-42))
-
-# converts a balanced ternary number to a list of trits
-number→trits [0 z a⁻ a⁺ a⁰] ⧗ Number → (List Trit)
- z [[0]]
- a⁻ pair t⁻
- a⁺ pair t⁺
- a⁰ pair t⁰
-
-:test (number→trits (+0)) ([[0]])
-:test (number→trits (+5)) (t⁻ : (t⁻ : (t⁺ : [[0]])))
-
-# strips leading 0s from a balanced ternary number
-strip [^(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number
- z (+0) : true
- a⁻ &[[↑⁻1 : false]]
- a⁺ &[[↑⁺1 : false]]
- a⁰ &[[(0 (+0) ↑⁰1) : 0]]
-
-%‣ strip
-
-:test (%[[[[0 3]]]]) ((+0))
-:test (%[[[[2 (0 (0 (0 (0 3))))]]]]) ((-1))
-:test (%(+42)) ((+42))
-
-# returns true if balanced ternary number is zero
-zero? [0 true [false] [false] i] ⧗ Number → Boolean
-
-=?‣ zero?
-
-:test (=?(+0)) (true)
-:test (=?(-1)) (false)
-:test (=?(+1)) (false)
-:test (=?(+42)) (false)
-
-# returns true if balanced ternary number is not zero
-not-zero? [0 false [true] [true] i] ⧗ Number → Boolean
+# rshifts least significant trit of a balanced ternary number
+# WARNING: Not necessarily equivalent to (/ (+3)): e.g. /³(+5) == (+2)!
+div³ [~(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number
+ z (+0) : (+0)
+ a⁻ &[[↑⁻1 : 1]]
+ a⁺ &[[↑⁺1 : 1]]
+ a⁰ &[[↑⁰1 : 1]]
-≠?‣ not-zero?
+/³‣ div³
-:test (≠?(+0)) (false)
-:test (≠?(-1)) (true)
-:test (≠?(+1)) (true)
-:test (≠?(+42)) (true)
+:test (/³(+6)) ((+2))
+:test (/³(-6)) ((-2))
+:test (/³(+5)) ((+2))
# extracts least significant trit from a balanced ternary number
lst [0 t⁰ [t⁻] [t⁺] [t⁰]] ⧗ Number → Trit
@@ -169,25 +127,29 @@ mst [B.get t⁰ (0 z a⁻ a⁺ a⁰)] ⧗ Number → Trit
:test (mst (+1)) (t⁺)
:test (mst (+42)) (t⁺)
-# returns true if balanced ternary number is negative
-negative? t⁻? ∘ mst ⧗ Number → Boolean
+# returns true if balanced ternary number is zero
+zero? [0 true [false] [false] i] ⧗ Number → Boolean
-<?‣ negative?
+=?‣ zero?
-:test (<?(+0)) (false)
-:test (<?(-1)) (true)
-:test (<?(+1)) (false)
-:test (<?(+42)) (false)
+:test (=?(+0)) (true)
+:test (=?(-1)) (false)
+:test (=?(+1)) (false)
+:test (=?(+42)) (false)
-# returns true if balanced ternary number is positive
-positive? t⁺? ∘ mst ⧗ Number → Boolean
+# returns true if the number is even (remainder mod 2 == 0)
+# TODO: faster solution (using tupling?)
+even? z [[rec]] ⧗ Number → Boolean
+ rec =?0 case-end case-rec
+ case-rec t⁰? (lst 0) (1 /³0) ¬(1 /³0)
+ case-end true
->?‣ positive?
+=²?‣ even?
-:test (>?(+0)) (false)
-:test (>?(-1)) (false)
-:test (>?(+1)) (true)
-:test (>?(+42)) (true)
+:test (=²?(+0)) (true)
+:test (=²?(+1)) (false)
+:test (=²?(+41)) (false)
+:test (=²?(+42)) (true)
# converts the normal balanced ternary representation into abstract
# infinity can't be abstracted in finite time
@@ -228,25 +190,6 @@ eq? [[abs 1 →^0]] ⧗ Number → Number → Boolean
…=?… eq?
-# returns true if two balanced ternary numbers are not equal
-not-eq? not! ∘∘ eq? ⧗ Number → Number → Boolean
-
-…≠?… not-eq?
-
-:test ((-42) =? (-42)) (true)
-:test ((-1) =? (-1)) (true)
-:test ((-1) =? (+0)) (false)
-:test ((+0) =? (+0)) (true)
-:test ((+1) =? (+0)) (false)
-:test ((+1) =? (+1)) (true)
-:test ((+42) =? (+42)) (true)
-:test ([[[[(1 (0 (0 (0 (0 3)))))]]]] =? (+1)) (true)
-:test ((+1) ≠? (+0)) (true)
-:test ((-42) ≠? (+42)) (true)
-
-# prefix for comparing functions
-?‣ &eq?
-
# adds (+1) to a balanced ternary number (can introduce leading 0s)
inc [~(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number
z (+0) : (+1)
@@ -262,7 +205,7 @@ inc [~(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number
:test (++(++(++(++(++(+0))))) =? (+5)) (true)
:test (++(+42) =? (+43)) (true)
-# subs (+1) from a balanced ternary number (can introduce leading 0s)
+# subtracts (+1) from a balanced ternary number (can introduce leading 0s)
dec [~(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number
z (+0) : (-1)
a⁻ &[[↑⁻1 : ↑⁺0]]
@@ -300,78 +243,81 @@ add [[abs 1 →^0]] ⧗ Number → Number → Number
:test ((+1) + (+2) =? (+3)) (true)
:test ((+42) + (+1) =? (+43)) (true)
-# subs two balanced ternary numbers (can introduce leading 0s)
-sub [[1 + -0]] ⧗ Number → Number → Number
-
-…-… sub
+# returns true if balanced ternary number is negative
+negative? t⁻? ∘ mst ⧗ Number → Boolean
-:test ((-42) - (-1) =? (-41)) (true)
-:test ((-5) - (+6) =? (-11)) (true)
-:test ((-1) - (+0) =? (-1)) (true)
-:test ((+0) - (+0) =? (+0)) (true)
-:test ((+1) - (+2) =? (-1)) (true)
-:test ((+42) - (+1) =? (+41)) (true)
+<?‣ negative?
-# returns true if number is greater than other number
-gt? positive? ∘∘ sub ⧗ Number → Number → Boolean
+:test (<?(+0)) (false)
+:test (<?(-1)) (true)
+:test (<?(+1)) (false)
+:test (<?(+42)) (false)
-…>?… gt?
+# returns true if balanced ternary number is positive
+positive? t⁺? ∘ mst ⧗ Number → Boolean
-:test ((+1) >? (+2)) (false)
-:test ((+2) >? (+2)) (false)
-:test ((+3) >? (+2)) (true)
+>?‣ positive?
-# returns true if number is less than other number
-lt? \gt? ⧗ Number → Number → Boolean
+:test (>?(+0)) (false)
+:test (>?(-1)) (false)
+:test (>?(+1)) (true)
+:test (>?(+42)) (true)
-…<?… lt?
+# negates a balanced ternary number
+negate [[[[[4 3 1 2 0]]]]] ⧗ Number → Number
-:test ((+1) <? (+2)) (true)
-:test ((+2) <? (+2)) (false)
-:test ((+3) <? (+2)) (false)
+-‣ negate
-# returns true if number is less than or equal to other number
-le? not! ∘∘ gt? ⧗ Number → Number → Boolean
+:test (-(+0)) ((+0))
+:test (-(-1)) ((+1))
+:test (-(+42)) ((-42))
-…≤?… le?
+# subtracts two numbers
+sub [[1 + -0]] ⧗ Number → Number → Number
-:test ((+1) ≤? (+2)) (true)
-:test ((+2) ≤? (+2)) (true)
-:test ((+3) ≤? (+2)) (false)
+…-… sub
-# returns true if number is greater than or equal to other number
-ge? \le? ⧗ Number → Number → Boolean
+# returns true if number is greater than other number
+gt? positive? ∘∘ sub ⧗ Number → Number → Boolean
-…≥?… ge?
+…>?… gt?
-:test ((+1) ≥? (+2)) (false)
-:test ((+2) ≥? (+2)) (true)
-:test ((+3) ≥? (+2)) (true)
+:test ((+1) >? (+2)) (false)
+:test ((+2) >? (+2)) (false)
+:test ((+3) >? (+2)) (true)
# returns eq, gt, lt depending on comparison of two numbers
compare-case [[[[[go (1 - 0)]]]]] ⧗ a → b → c → Number → Number → d
go [=?0 5 (>?0 4 3)]
-# returns 1 if a>b, -1 if a<b and 0 if a=b
-# also: spaceship operator
-compare compare-case (+0) (+1) (-1) ⧗ Number → Number → Number
+# ============================================================================ #
+# most relevant functions are defined - we can now derive from Generic/Number! #
+# ============================================================================ #
-…<=>… compare
+:input std/Generic/Number
-<=>‣ &compare
+# converts a balanced ternary number to a list of trits
+number→trits [0 z a⁻ a⁺ a⁰] ⧗ Number → (List Trit)
+ z [[0]]
+ a⁻ pair t⁻
+ a⁺ pair t⁺
+ a⁰ pair t⁰
-:test (compare (+2) (+2)) ((+0))
-:test (compare (+2) (+1)) ((+1))
-:test (compare (+1) (+2)) ((-1))
+:test (number→trits (+0)) ([[0]])
+:test (number→trits (+5)) (t⁻ : (t⁻ : (t⁺ : [[0]])))
-# returns true if comparison result is equal (EQ)
-c-eq? eq? (+0) ⧗ Number → Number
+# strips leading 0s from a balanced ternary number
+strip [^(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number
+ z (+0) : true
+ a⁻ &[[↑⁻1 : false]]
+ a⁺ &[[↑⁺1 : false]]
+ a⁰ &[[(0 (+0) ↑⁰1) : 0]]
-# returns true if comparison result is less than (LT)
-c-lt? eq? (-1) ⧗ Number → Number
+%‣ strip
-# returns true if comparison result is greater than (GT)
-c-gt? eq? (+1) ⧗ Number → Number
+:test (%[[[[0 3]]]]) ((+0))
+:test (%[[[[2 (0 (0 (0 (0 3))))]]]]) ((-1))
+:test (%(+42)) ((+42))
# negates a balanced ternary number if <0
abs [<?0 -0 0] ⧗ Number → Number
@@ -382,23 +328,6 @@ abs [<?0 -0 0] ⧗ Number → Number
:test (|(-1)) ((+1))
:test (|(+42)) ((+42))
-# returns max number of two
-max [[(1 ≤? 0) 0 1]] ⧗ Number → Number → Number
-
-:test (max (+5) (+2)) ((+5))
-
-# returns min number of two
-min [[(1 ≤? 0) 1 0]] ⧗ Number → Number → Number
-
-:test (min (+5) (+2)) ((+2))
-
-# clamps a number between two numbers
-clamp [[[min 1 (max 0 2)]]] ⧗ Number → Number → Number
-
-:test (clamp (+0) (+5) (+3)) ((+3))
-:test (clamp (+0) (+5) (-2)) ((+0))
-:test (clamp (+0) (+5) (+7)) ((+5))
-
# apply a function n times to a value
# ~> substitute church numbers
apply z [[[rec]]] ⧗ Number → (a → a) → a → a
@@ -408,7 +337,7 @@ apply z [[[rec]]] ⧗ Number → (a → a) → a → a
:test (apply (+5) ++‣ (+3)) ((+8))
-# muls two balanced ternary numbers (can introduce leading 0s)
+# multplies two balanced ternary numbers (can introduce leading 0s)
mul [[1 z a⁻ a⁺ a⁰]] ⧗ Number → Number → Number
z (+0)
a⁻ [↑⁰0 - 1]
@@ -422,20 +351,6 @@ mul [[1 z a⁻ a⁺ a⁰]] ⧗ Number → Number → Number
:test ((+3) ⋅ (+11) =? (+33)) (true)
:test ((+42) ⋅ (-4) =? (-168)) (true)
-# rshifts least significant trit of a balanced ternary number
-# WARNING: Not necessarily equivalent to (/ (+3)): e.g. /³(+5) == (+2)!
-div³ [~(0 z a⁻ a⁺ a⁰)] ⧗ Number → Number
- z (+0) : (+0)
- a⁻ &[[↑⁻1 : 1]]
- a⁺ &[[↑⁺1 : 1]]
- a⁰ &[[↑⁰1 : 1]]
-
-/³‣ div³
-
-:test (/³(+6)) ((+2))
-:test (/³(-6)) ((-2))
-:test (/³(+5)) ((+2))
-
# divs a balanced ternary number by two (binary >>1)
div² [z [[[[rec]]]] (+0) 0 0] ⧗ Number → Number
rec =?1 case-end case-div
@@ -546,27 +461,3 @@ mod ~‣ ∘∘ quot-rem ⧗ Number → Number → Number
:test ((-5) % (-3) =? (-2)) (true)
:test ((-5) % (+3) =? (+1)) (true)
:test ((+5) % (-3) =? (-1)) (true)
-
-# returns true if the number is even (remainder mod 2 == 0)
-# TODO: faster solution (using tupling?)
-even? z [[rec]] ⧗ Number → Boolean
- rec =?0 case-end case-rec
- case-rec t⁰? (lst 0) (1 /³0) ¬(1 /³0)
- case-end true
-
-=²?‣ even?
-
-:test (=²?(+0)) (true)
-:test (=²?(+1)) (false)
-:test (=²?(+41)) (false)
-:test (=²?(+42)) (true)
-
-# returns true if the number is odd (remainder mod 2 == 1)
-odd? ¬‣ ∘ even? ⧗ Number → Boolean
-
-≠²?‣ odd?
-
-:test (≠²?(+0)) (false)
-:test (≠²?(+1)) (true)
-:test (≠²?(+41)) (true)
-:test (≠²?(+42)) (false)
diff --git a/std/Number/Unary.bruijn b/std/Number/Unary.bruijn
index bb3ef44..ae54c19 100644
--- a/std/Number/Unary.bruijn
+++ b/std/Number/Unary.bruijn
@@ -25,16 +25,25 @@ zero? [0 [(+0u)] true] ⧗ Unary → Boolean
:test (=?(+0u)) (true)
:test (=?(+42u)) (false)
-# adds 1 to a unary number
-inc [[[1 (2 1 0)]]] ⧗ Unary → Unary
+# returns remainder of integer division
+mod [[[[3 &k (3 [3 [[[0 (2 (5 1)) 1]]] [1] 1] [1]) ki]]]] ⧗ Unary → Unary → Unary
-++‣ inc
+…%… mod
-:test (++(+0u)) ((+1u))
-:test (++(+1u)) ((+2u))
-:test (++(+42u)) ((+43u))
+:test ((+10u) % (+3u)) ((+1u))
+:test ((+3u) % (+5u)) ((+3u))
+
+# returns true if the number is even (remainder mod 2 == 0)
+even? [=?(0 % (+2u))] ⧗ Unary → Boolean
+
+=²?‣ even?
+
+:test (=²?(+0u)) (true)
+:test (=²?(+1u)) (false)
+:test (=²?(+41u)) (false)
+:test (=²?(+42u)) (true)
-# subs 1 from a unary number
+# subtracts 1 from a unary number
dec [[[extract (2 inc const)]]] ⧗ Unary → Unary
extract &i
inc [&(0 2)]
@@ -46,6 +55,15 @@ dec [[[extract (2 inc const)]]] ⧗ Unary → Unary
:test (--(+1u)) ((+0u))
:test (--(+42u)) ((+41u))
+# adds 1 to a unary number
+inc [[[1 (2 1 0)]]] ⧗ Unary → Unary
+
+++‣ inc
+
+:test (++(+0u)) ((+1u))
+:test (++(+1u)) ((+2u))
+:test (++(+42u)) ((+43u))
+
# adds two unary numbers
add [[[[3 1 (2 1 0)]]]] ⧗ Unary → Unary → Unary
@@ -54,7 +72,7 @@ add [[[[3 1 (2 1 0)]]]] ⧗ Unary → Unary → Unary
:test ((+0u) + (+2u)) ((+2u))
:test ((+5u) + (+3u)) ((+8u))
-# subs two unary numbers
+# subtracts two unary numbers
sub [[0 dec 1]] ⧗ Unary → Unary → Unary
…-… sub
@@ -62,27 +80,8 @@ sub [[0 dec 1]] ⧗ Unary → Unary → Unary
:test ((+2u) - (+2u)) ((+0u))
:test ((+5u) - (+3u)) ((+2u))
-# returns true if number is less than or equal to other number
-le? zero? ∘∘ sub ⧗ Unary → Unary → Boolean
-
-…≤?… le?
-
-:test ((+1u) ≤? (+2u)) (true)
-:test ((+2u) ≤? (+2u)) (true)
-:test ((+3u) ≤? (+2u)) (false)
-
-# returns true if number is greater than or equal to other number
-ge? \le? ⧗ Unary → Unary → Boolean
-
-…≥?… ge?
-
-:test ((+1u) ≥? (+2u)) (false)
-:test ((+2u) ≥? (+2u)) (true)
-:test ((+3u) ≥? (+2u)) (true)
-
# returns true if number is greater than other number
-# larger numbers should be second argument (performance)
-gt? not! ∘∘ le? ⧗ Unary → Unary → Boolean
+gt? not! ∘∘ (zero? ∘∘ sub) ⧗ Unary → Unary → Boolean
…>?… gt?
@@ -90,16 +89,6 @@ gt? not! ∘∘ le? ⧗ Unary → Unary → Boolean
:test ((+2u) >? (+2u)) (false)
:test ((+3u) >? (+2u)) (true)
-# returns true if number is less than other number
-# smaller numbers should be second argument (performance)
-lt? \gt? ⧗ Unary → Unary → Boolean
-
-…<?… lt?
-
-:test ((+1u) <? (+2u)) (true)
-:test ((+2u) <? (+2u)) (false)
-:test ((+3u) <? (+2u)) (false)
-
# returns true if two unary numbers are equal
eq? [[=?(1 - 0) ⋀? =?(0 - 1)]] ⧗ Unary → Unary → Boolean
@@ -110,35 +99,17 @@ eq? [[=?(1 - 0) ⋀? =?(0 - 1)]] ⧗ Unary → Unary → Boolean
:test ((+1u) =? (+2u)) (false)
:test ((+42u) =? (+42u)) (true)
-# returns true if two unary numbers are not equal
-not-eq? not! ∘∘ eq? ⧗ Unary → Unary → Boolean
-
-…≠?… not-eq?
-
-:test ((+1u) ≠? (+0u)) (true)
-:test ((+1u) ≠? (+1u)) (false)
-:test ((+42u) ≠? (+42u)) (false)
-
-# prefix for comparing functions
-?‣ &eq?
-
# returns eq, lt, gt depending on comparison of two numbers
compare-case [[[[[go (1 - 0) (0 - 1)]]]]] ⧗ a → b → c → Unary → Unary → d
go [[=?0 (=?1 6 5) 4]]
-# returns ternary 1 if a>b, -1 if a<b and 0 if a=b
-# also: spaceship operator
-compare compare-case (+0) (+1) (-1) ⧗ Unary → Unary → Number
+# ============================================================================ #
+# most relevant functions are defined - we can now derive from Generic/Number! #
+# ============================================================================ #
-:test (compare (+2u) (+2u)) ((+0))
-:test (compare (+2u) (+1u)) ((+1))
-:test (compare (+1u) (+2u)) ((-1))
+:input std/Generic/Number
-…<=>… compare
-
-<=>‣ &compare
-
-# muls two unary numbers
+# multiplies two unary numbers
mul …∘… ⧗ Unary → Unary → Unary
…⋅… mul
@@ -160,39 +131,6 @@ div [[[[3 t [1] (3 [3 t [3 (0 1)] i] 0)]]]] ⧗ Unary → Unary → Unary
div* [z rec ++0] ⧗ Unary → Unary → Unary
rec [[[[[[=?0 ((+0u) 2 1) (2 (5 0 3 2 1))] (3 - 2)]]]]]
-# returns remainder of integer division
-mod [[[[3 &k (3 [3 [[[0 (2 (5 1)) 1]]] [1] 1] [1]) ki]]]] ⧗ Unary → Unary → Unary
-
-…%… mod
-
-:test ((+10u) % (+3u)) ((+1u))
-:test ((+3u) % (+5u)) ((+3u))
-
-# slower mod (more obvious impl)
-mod* [[1 &[[(0 ⋀? (2 ≤? 1)) case-rec case-end]] (1 : true) k]] ⧗ Unary → Unary → Unary
- case-rec (1 - 3) : true
- case-end 1 : false
-
-# returns true if the number is even (remainder mod 2 == 0)
-even? [=?(0 % (+2u))] ⧗ Unary → Boolean
-
-=²?‣ even?
-
-:test (=²?(+0u)) (true)
-:test (=²?(+1u)) (false)
-:test (=²?(+41u)) (false)
-:test (=²?(+42u)) (true)
-
-# returns true if the number is odd (remainder mod 2 == 1)
-odd? ¬‣ ∘ even? ⧗ Unary → Boolean
-
-≠²?‣ odd?
-
-:test (≠²?(+0u)) (false)
-:test (≠²?(+1u)) (true)
-:test (≠²?(+41u)) (true)
-:test (≠²?(+42u)) (false)
-
# exponentiates two unary number
# doesn't give correct results for x^0
pow* [[1 0]] ⧗ Unary → Unary → Unary
diff --git a/std/test_all.sh b/std/test_all.sh
index 32619f3..5792a4c 100755
--- a/std/test_all.sh
+++ b/std/test_all.sh
@@ -8,7 +8,7 @@ fi
echo "# useful for running all tests of the standard library" >All.bruijn
echo >>All.bruijn
-FILES="$(find * -type f -name "*.bruijn" ! -name "All.bruijn")"
+FILES="$(find * -type f -name "*.bruijn" ! -name "All.bruijn" ! -path "*Generic*")"
for f in $FILES; do
echo ":import std/${f%*.bruijn} ." >>All.bruijn