diff options
author | Marvin Borner | 2024-03-25 23:54:19 +0100 |
---|---|---|
committer | Marvin Borner | 2024-03-25 23:54:19 +0100 |
commit | 5a2dd4a7e8a6857e8cf32b6fe1524f04962c54cb (patch) | |
tree | 2440ddebde48d1cb2ddaba4b7042544f74f48e50 | |
parent | d13df6b34ebdc6a2d3dd01b081617fe6e88feda8 (diff) |
Add support for context-dependent imports / generics
-rw-r--r-- | bruijn.cabal | 2 | ||||
-rw-r--r-- | src/Eval.hs | 30 | ||||
-rw-r--r-- | std/Generic/Number.bruijn | 66 | ||||
-rw-r--r-- | std/Number/Binary.bruijn | 286 | ||||
-rw-r--r-- | std/Number/Ternary.bruijn | 273 | ||||
-rw-r--r-- | std/Number/Unary.bruijn | 126 | ||||
-rwxr-xr-x | std/test_all.sh | 2 |
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 |