Skip to content

Commit

Permalink
Samples and std additions
Browse files Browse the repository at this point in the history
  • Loading branch information
marvinborner committed Mar 10, 2024
1 parent 6ae44d0 commit e4dc591
Show file tree
Hide file tree
Showing 18 changed files with 301 additions and 63 deletions.
1 change: 1 addition & 0 deletions bruijn.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ data-files:
std/test_all.sh
std/AIT/Beavers.bruijn
std/Number/Binary.bruijn
std/Number/Bruijn.bruijn
std/Number/Conversion.bruijn
std/Number/Pairing.bruijn
std/Number/Ternary.bruijn
Expand Down
4 changes: 2 additions & 2 deletions docs/wiki_src/coding/recursion.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ g [[[=?0 true (1 --0)]]]
# the even? recursive call will be the first argument (2)
h [[[=?0 false (2 --0)]]]
even? head (y* g h) ⧗ Number → Boolean
even? head (y* (g : {}h)) ⧗ Number → Boolean
odd? tail (y* g h) ⧗ Number → Boolean
odd? tail (y* (g : {}h)) ⧗ Number → Boolean
```

Read more about this in the blog post [Variadic fixed-point
Expand Down
15 changes: 15 additions & 0 deletions samples/rosetta/de_bruijn_sequence.bruijn
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# TODO: Too slow to be published. Probably needs Maps/Sets/Vectors/sth.

:import std/Combinator .
:import std/Char C
:import std/Math .
:import std/List .

# very slow but elegant
de-bruijn y [[[C.?infix? (take 0 1) ~1 case-end case-rec]]]
case-rec max-by (compare ⋔ length) ([3 (0 : 2) 1] <$> (C.?nub 1))
case-end drop 0 1

:test (de-bruijn "abcd" (+2)) ("dccaadbbacbdabcd")

main [[0]]
3 changes: 3 additions & 0 deletions samples/rosetta/halt_and_catch_fire.bruijn
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:test ([[0]]) ([[1]])

main [[0 0] [0 0]]
7 changes: 7 additions & 0 deletions samples/rosetta/higher_order_functions.bruijn
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
first [0 [[0]]]

second [first [[1]]]

:test (second) ([[[[0]]]])

main [[0]]
14 changes: 14 additions & 0 deletions samples/rosetta/luhn_test_of_credit_card_numbers.bruijn
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
:import std/Combinator .
:import std/Math .
:import std/List .

luhn number→list → reverse → check → (\mod (+10)) → zero?
check y [[[[0 [[[6 \5 (4 + (5 odd even)) 1]]] 1]]]] k (+0)
odd 2
even digit-sum (2 ⋅ (+2))

:test (luhn (+61789372994)) ([[1]])
:test (luhn (+49927398716)) ([[1]])
:test (luhn (+49927398717)) ([[0]])
:test (luhn (+1234567812345678)) ([[0]])
:test (luhn (+1234567812345670)) ([[1]])
4 changes: 2 additions & 2 deletions samples/rosetta/sorting_quicksort.bruijn
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

sort y [[0 [[[case-sort]]] case-end]]
case-sort (4 lesser) ++ (2 : (4 greater))
lesser 1 <#> (\les? 2)
greater 1 <#> (\geq? 2)
lesser (\les? 2) <#> 1
greater (\geq? 2) <#> 1
case-end empty

:test (sort ((+3) : ((+2) : {}(+1)))) ((+1) : ((+2) : {}(+3)))
Expand Down
6 changes: 6 additions & 0 deletions samples/rosetta/sum_and_product_of_an_array.bruijn
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
:import std/List .
:import std/Math .

arr (+1) : ((+2) : ((+3) : {}(+4)))

main [∑arr : ∏arr]
30 changes: 30 additions & 0 deletions samples/rosetta/validate_isin.bruijn
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
:import luhn_test_of_credit_card_numbers .

:import std/Number/Conversion .
:import std/Combinator .
:import std/String .
:import std/Char .
:import std/Logic .
:import std/Number .

# verifies ISIN format
format? [len ⋀? country ⋀? security ⋀? checksum]
len (length 0) =? (+12)
country all? uppercase? (take (+2) 0)
security all? (φ or? uppercase? numeric?) (take (+9) (drop (+2) 0))
checksum numeric? _0

# performs luhn test
checksum? (map (from-base36 → number→string)) → concat → string→number → luhn
from-base36 binary→ternary → [(0 - (0 ≥? (+65) ((+65) - (+10)) (+48)))]

# performs format and checksum test
validate φ and? format? checksum?

:test (validate "US0378331005") (true)
:test (validate "US0373831005") (false)
:test (validate "U50378331005") (false)
:test (validate "US03378331005") (false)
:test (validate "AU0000XVGZA3") (true)
:test (validate "AU0000VXGZA3") (true)
:test (validate "FR0000988040") (true)
57 changes: 55 additions & 2 deletions std/Char.bruijn
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,61 @@

:import std/Number/Conversion .

# prefix for comparing functions
?‣ &eq?

# converts a char to a balanced ternary number
char→number [binary→ternary (0 - '0')] ⧗ Char → Number
char→number (\sub '0') → binary→ternary ⧗ Char → Number

:test (char→number '0') ((+0))

# converts a balanced ternary number to a char
number→char ['0' + (ternary→binary 0)] ⧗ Number → Char
number→char ternary→binary → (add '0') ⧗ Number → Char

:test (number→char (+0)) ('0')
:test (number→char (+9)) ('9')

# returns true if char is in A-Z
uppercase? φ and? (\geq? 'A') (\leq? 'Z') ⧗ Char → Boolean

:test (uppercase? 'a') (false)
:test (uppercase? 'z') (false)
:test (uppercase? 'A') (true)
:test (uppercase? 'Z') (true)
:test (uppercase? '0') (false)

# returns true if char is in a-z
lowercase? φ and? (\geq? 'a') (\leq? 'z') ⧗ Char → Boolean

:test (lowercase? 'a') (true)
:test (lowercase? 'z') (true)
:test (lowercase? 'A') (false)
:test (lowercase? 'Z') (false)
:test (lowercase? '0') (false)

# returns true if char is in a-zA-Z
alpha? φ or? lowercase? uppercase? ⧗ Char → Boolean

:test (alpha? 'a') (true)
:test (alpha? 'z') (true)
:test (alpha? 'A') (true)
:test (alpha? 'Z') (true)
:test (alpha? '0') (false)

# returns true if char is in 0-9
numeric? φ and? (\geq? '0') (\leq? '9') ⧗ Char → Boolean

:test (numeric? '0') (true)
:test (numeric? '9') (true)
:test (numeric? 'a') (false)

# returns true if char is in a-zA-Z0-9
alpha-numeric? φ or? numeric? alpha? ⧗ Char → Boolean

:test (alpha-numeric? 'a') (true)
:test (alpha-numeric? 'z') (true)
:test (alpha-numeric? 'A') (true)
:test (alpha-numeric? 'Z') (true)
:test (alpha-numeric? '0') (true)
:test (alpha-numeric? '9') (true)
:test (alpha-numeric? '$') (false)
42 changes: 32 additions & 10 deletions std/List.bruijn
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,9 @@ filter z [[[rec]]] ⧗ (a → Boolean) → (List a) → (List a)
case-filter 4 2 (cons 2) i (5 4 1)
case-end empty

…<#>… \filter
…<#>… filter

:test (((+1) : ((+0) : {}(+3))) <#> zero?) ({}(+0))
:test (zero? <#> ((+1) : ((+0) : {}(+3)))) ({}(+0))

# returns the last element of a list
last ^‣ ∘ <~>‣ ⧗ (List a) → a
Expand Down Expand Up @@ -315,6 +315,12 @@ drop-while z [[[rec]]] ⧗ (a → Boolean) → (List a) → (List a)

:test (drop-while zero? ((+0) : ((+0) : {}(+1)))) ({}(+1))

# returns all tails of a list
tails z [[rec]] ⧗ (List a) → (List a)
rec ∅?0 {}empty (0 : (1 ~0))

:test (tails "abc") ("abc" : ("bc" : ("c" : {}empty)))

# returns all combinations of two lists
cross [[[[1 : 0] <$> 1] <++> 1]] ⧗ (List a) → (List b) → (List (Pair a b))

Expand All @@ -324,8 +330,6 @@ cross [[[[1 : 0] <$> 1] <++> 1]] ⧗ (List a) → (List b) → (List (Pair a b))
# TODO: add/use triple type (list element types can be different)
cross3 [[[[[[2 : (1 : {}0)] <$> 2] <++> 2] <++> 2]]] ⧗ (List a) → (List a) → (List a) → (List (List a))

# :test (cross "ab" "cd") (('a' : 'c') : (('a' : 'd') : (('b' : 'c') : {}('b' : 'd'))))

# returns pair of take-while and drop-while
span [[(take-while 1 0) : (drop-while 1 0)]] ⧗ (a → Boolean) → (List a) → (Pair (List a) (List a))

Expand Down Expand Up @@ -369,8 +373,8 @@ split-list-by z [[[rec]]] ⧗ (a → Boolean) → (List a) → (List (List a))
sort-asc z [[rec]]
rec 0 [[[case-sort]]] case-end
case-sort (4 lesser) ++ {}(2) ++ (4 greater)
lesser 1 <#> (\les? 2)
greater 1 <#> (\geq? 2)
lesser (\les? 2) <#> 1
greater (\geq? 2) <#> 1
case-end empty

:test (sort-asc ((+3) : ((+2) : {}(+1)))) ((+1) : ((+2) : {}(+3)))
Expand All @@ -379,8 +383,8 @@ sort-asc z [[rec]]
sort-desc z [[rec]]
rec 0 [[[case-sort]]] case-end
case-sort (4 greater) ++ {}(2) ++ (4 lesser)
greater 1 <#> (\geq? 2)
lesser 1 <#> (\les? 2)
greater (\geq? 2) <#> 1
lesser (\les? 2) <#> 1
case-end empty

:test (sort-desc ((+1) : ((+2) : {}(+3)))) ((+3) : ((+2) : {}(+1)))
Expand Down Expand Up @@ -416,6 +420,24 @@ eq? ⋀?‣ ∘∘∘ zip-with ⧗ (a → a → Boolean) → (List a) → Boolea
:test (eq? …=?… ((+1) : {}(+2)) ((+2) : {}(+2))) (false)
:test (eq? …=?… empty empty) (true)

# returns true if list is prefix of other list
prefix? z [[[[rec]]]] ⧗ (a → a → Boolean) → (List a) → (List a) → Boolean
rec ∅?1 true (∅?0 false go)
go 1 [[2 [[(6 3 1) ⋀? (7 6 2 0)]]]]

:test (prefix? …=?… ((+1) : {}(+2)) ((+1) : {}(+2))) (true)
:test (prefix? …=?… ((+1) : {}(+2)) ((+0) : ((+1) : {}(+2)))) (false)
:test (prefix? …=?… ((+1) : {}(+2)) ((+2) : {}(+2))) (false)
:test (prefix? …=?… empty empty) (true)

# returns true if list is within other list
infix? [[[any? (prefix? 2 1) (tails 0)]]] ⧗ (a → a → Boolean) → (List a) → (List a) → Boolean

:test (infix? …=?… ((+1) : {}(+2)) ((+1) : {}(+2))) (true)
:test (infix? …=?… ((+1) : {}(+2)) ((+0) : ((+1) : {}(+2)))) (true)
:test (infix? …=?… ((+1) : {}(+2)) ((+2) : {}(+2))) (false)
:test (infix? …=?… empty empty) (true)

# finds the first index that matches a predicate
find-index z [[[rec]]] ⧗ (a → Boolean) → (List a) → Number
rec 0 [[[case-find]]] case-end
Expand All @@ -426,7 +448,7 @@ find-index z [[[rec]]] ⧗ (a → Boolean) → (List a) → Number
:test (find-index (…=?… (+2)) ((+1) : ((+2) : ((+3) : {}(+2))))) ((+1))
:test (find-index (…=?… (+4)) ((+1) : ((+2) : ((+3) : {}(+2))))) ((-1))

# removes first element that match an eq predicate
# removes first element that matches an eq predicate
remove z [[[[rec]]]] ⧗ (a → a → Boolean) → a → (List a) → (List a)
rec 0 [[[case-remove]]] case-end
case-remove (5 2 4) 1 (2 : (6 5 4 1))
Expand All @@ -437,7 +459,7 @@ remove z [[[[rec]]]] ⧗ (a → a → Boolean) → a → (List a) → (List a)
# removes duplicates from list based on eq predicate (keeps first occurrence)
nub z [[[rec]]] ⧗ (a → a → Boolean) → (List a) → (List a)
rec 0 [[[case-nub]]] case-end
case-nub 2 : (5 4 (1 <#> [¬(5 0 3)]))
case-nub 2 : (5 4 ([¬(5 0 3)] <#> 1))
case-end empty

:test (nub …=?… ((+1) : ((+2) : {}(+3)))) ((+1) : ((+2) : {}(+3)))
Expand Down
15 changes: 7 additions & 8 deletions std/Math.bruijn
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ sum foldl add (+0) ⧗ (List Number) → Number

:test (∑((+1) : ((+2) : {}(+3)))) ((+6))

# digit sum of all values
digit-sum sum ∘ number→list ⧗ Number → Number

:test ((digit-sum (+0)) =? (+0)) (true)
:test ((digit-sum (+10)) =? (+1)) (true)
:test ((digit-sum (+19)) =? (+10)) (true)

# returns max value of list
lmax foldl1 max ⧗ (List Number) → Number

Expand All @@ -22,14 +29,6 @@ lmin foldl1 min ⧗ (List Number) → Number

:test (lmin ((+2) : ((+1) : {}(+0)))) ((+0))

# converts number to list of its digits
digits z [[rec]] ⧗ Number → (List Number)
rec =?0 case-end case-rec
case-rec (1 (0 / (+10))) ; (0 % (+10))
case-end empty

:test (digits (+0)) (empty)

# list from num to num
{…→…} z [[[rec]]] ⧗ Number → Number → (List Number)
rec (1 =? ++0) case-end case-list
Expand Down
15 changes: 11 additions & 4 deletions std/Number.bruijn
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,16 @@

# the following functions are only here because of recursive imports of list/ternary

# converts a list of digits into a balanced ternary number
from-digits foldl [[(+10) ⋅ 1 + 0]] (+0)
# converts number to list of its digits
number→list [=?0 {}(+0) (z [[rec]] 0)] ⧗ Number → (List Number)
rec =?0 case-end case-rec
case-rec (1 (0 / (+10))) ; (0 % (+10))
case-end empty

:test (number→list (+0)) ({}(+0))

:test (from-digits ((+4) : ((+2) : {}(+0)))) ((+420))
:test (from-digits empty) ((+0))
# converts a list of digits into a balanced ternary number
list→number foldl [[(+10) ⋅ 1 + 0]] (+0) ⧗ (List Number) → Number

:test (list→number ((+4) : ((+2) : {}(+0)))) ((+420))
:test (list→number empty) ((+0))
27 changes: 22 additions & 5 deletions std/Number/Binary.bruijn
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ not-eq? not! ∘∘ eq? ⧗ Binary → Binary → Boolean
: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)
Expand Down Expand Up @@ -196,17 +199,17 @@ complement [[[[3 2 0 1]]]] ⧗ Binary → Binary
:test (-*(+42b)) ([[[1 (0 (1 (0 (1 (0 2)))))]]])

# inverts a binary number by complementing and incrementing (2's complement)
# don't forget to pad the number with zeroes if needed
# don't forget to pad the number with 0s if needed
invert ++‣ ∘ -*‣ ⧗ Binary → Binary

-‣ invert

:test (-(+0b)) ((+1b))
:test (-(+1b)) ((+1b))

# pads a binary number with zeroes until its as long a another binary number
# TODO: this could probably be done without list magic
pad [[binary! (pad-right ∀(list! %1) b⁰ (list! 0))]] ⧗ Binary → Binary → Binary
# pads a binary number with 0s until it's as long a another binary number
# TODO: this could be done without list magic (see Ternary)
pad [[binary! (pad-right ∀(list! %1) b⁰ (list! %0))]] ⧗ Binary → Binary → Binary

:test (pad (+5b) [[[1 2]]]) ([[[1 (0 (0 2))]]])

Expand Down Expand Up @@ -248,7 +251,7 @@ sub* [[abs 1 →^0]] ⧗ Binary → Binary → Binary
# subs two binary numbers
# uses addition but with two's complement
# TODO: isn't very performant ⇒ replace with sub*
# TODO: gives wrong results if b>a in a-b
# TODO: gives fun results if b>a in a-b
sub [[(0 =? 1) (+0b) -((pad 1 0) + -(pad 0 1))]] ⧗ Binary → Binary → Binary

…-… sub
Expand Down Expand Up @@ -279,6 +282,20 @@ div² [~(0 z a¹ a⁰)] ⧗ Binary → Binary
: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

# ceiled integer log2 by counting bits
log2 log2* ∘ strip ⧗ Binary → Binary

:test ((log2 (+1b)) =? (+1b)) (true)
:test ((log2 (+2b)) =? (+2b)) (true)
:test ((log2 (+3b)) =? (+2b)) (true)
: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

Expand Down
Loading

0 comments on commit e4dc591

Please sign in to comment.