From ca3907431bfde5aa0715945222ce777d72e6b411 Mon Sep 17 00:00:00 2001 From: Marvin Borner Date: Sat, 2 Mar 2024 16:16:51 +0100 Subject: [PATCH] Docs & samples --- docs/index.html | 6 +- docs/script.js | 3 +- docs/style.css | 2 +- readme.md | 2 + samples/rosetta/function_composition.bruijn | 21 ++++++ samples/rosetta/hailstone.bruijn | 21 ++++++ samples/rosetta/levenshtein_distance.bruijn | 10 +++ samples/rosetta/ternary_logic.bruijn | 71 +++++++++++++++++++++ std/List.bruijn | 9 ++- test/Spec.hs | 2 - 10 files changed, 135 insertions(+), 12 deletions(-) create mode 100644 samples/rosetta/function_composition.bruijn create mode 100644 samples/rosetta/hailstone.bruijn create mode 100644 samples/rosetta/levenshtein_distance.bruijn create mode 100644 samples/rosetta/ternary_logic.bruijn delete mode 100644 test/Spec.hs diff --git a/docs/index.html b/docs/index.html index 4b5bc6e..e8f807f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -108,13 +108,9 @@

bruijn

 > length `factorial
-> !(swap `((+2u) (+3u)))
+> !(swap `((+2u) (+3u)))
 > lhs (blc→meta "010000100000110")
 
- - - -
diff --git a/docs/script.js b/docs/script.js index 0b147f5..463badd 100644 --- a/docs/script.js +++ b/docs/script.js @@ -39,6 +39,7 @@ describe("left-abs", "The opening bracket of a function abstraction. It's basica describe("left-app", "The opening bracket of a function application."); describe("meta", "This is the quote operator. It converts any given expression to bruijn's meta encoding. The meta encoding can be used for self modification and can be turned back to normal bruijn code."); describe("mixfix", "This is a mixfix operator. They can be defined like …*… where the … can then be any other term. You can use them without the … as a notation of function application."); +describe("prefix", "This is a prefix operator. They can be defined like *‣ where the ‣ can then be any other term."); describe("repl", "This indicates a REPL input."); describe("right-abs", "The closing bracket of a function abstraction."); describe("right-app", "The closing bracket of a function application."); @@ -47,6 +48,6 @@ describe("string", "Syntactic sugar for a list of binary encoded chars.") describe("symbol", "This substitutes a previously defined term (for example from the standard library)."); describe("ternary", "Syntactic sugar for a balanced ternary number representation using abstractions as data. Needs a sign and brackets to differentiate it from De Bruijn indices."); describe("time", "Incredibly fast for lambda calculus standards."); -describe("unary", "Syntactic sugar for a unary number representation using abstractions as data. This is commonly also known as a Church numeral. Needs a sign and brackets to differentiate it from De Bruijn indices."); +describe("unary", "Syntactic sugar for a unary number representation using abstractions as data. This is commonly known as a Church numeral. Needs a sign and brackets to differentiate it from De Bruijn indices."); document.body.addEventListener("click", clearPopups, true) diff --git a/docs/style.css b/docs/style.css index 60e8fe5..b23edad 100644 --- a/docs/style.css +++ b/docs/style.css @@ -188,7 +188,7 @@ a { color: #b1ee13; } -.code .mixfix { +.code .mixfix, .code .prefix { color: #eee513; } diff --git a/readme.md b/readme.md index 6870a48..f457ba1 100644 --- a/readme.md +++ b/readme.md @@ -5,6 +5,8 @@ > A purely functional programming language based on lambda calculus and > De Bruijn indices written in Haskell. +Pronunciation: `/bɹaʊn/`. + Wiki, docs, articles, examples and more: [website](https://bruijn.marvinborner.de). Also: [Rosetta Code](https://rosettacode.org/wiki/Category:Bruijn). diff --git a/samples/rosetta/function_composition.bruijn b/samples/rosetta/function_composition.bruijn new file mode 100644 index 0000000..3415c5e --- /dev/null +++ b/samples/rosetta/function_composition.bruijn @@ -0,0 +1,21 @@ +:import std/Number . + +# composition, bluebird combinator +…∘… [[[2 (1 0)]]] + +:test (((inc ∘ (mul (+2))) (+3)) =? (+7)) ([[1]]) + +# 2x composition, blackbird combinator +…∘∘… [[[[3 (2 1 0)]]]] + +:test (((inc ∘∘ mul) (+2) (+3)) =? (+7)) ([[1]]) + +# 3x composition, bunting combinator +…∘∘∘… [[[[[4 (3 2 1 0)]]]]] + +:test (((inc ∘∘∘ (add ∘∘ mul)) (+1) (+2) (+4)) =? (+7)) ([[1]]) + +# reverse composition, queer bird combinator +…→… [[[1 (2 0)]]] + +:test ((((mul (+2)) → inc) (+3)) =? (+7)) ([[1]]) diff --git a/samples/rosetta/hailstone.bruijn b/samples/rosetta/hailstone.bruijn new file mode 100644 index 0000000..46cf8a2 --- /dev/null +++ b/samples/rosetta/hailstone.bruijn @@ -0,0 +1,21 @@ +:import std/Combinator . +:import std/List . +:import std/Math M +:import std/Number/Binary . + +# hailstone sequence using binary shifts +hailstone y [[(0 =? (+1b)) {}0 go]] + go 0 : (=²?0 (1 /²0) (1 (↑¹0 + 0))) + +# --- tests --- + +seq-27 hailstone (+27b) + +:test (∀seq-27) ((+112)) +:test (take (+4) seq-27) ((+27b) : ((+82b) : ((+41b) : {}(+124b)))) +:test (take (+4) <~>seq-27) ((+1b) : ((+2b) : ((+4b) : {}(+8b)))) + +all-below-100000 [0 : ∀(hailstone 0)] <$> seq + seq take (+1000) (iterate ++‣ (+1b)) + +main [head (max-by (M.compare ⋔ tail) all-below-100000)] diff --git a/samples/rosetta/levenshtein_distance.bruijn b/samples/rosetta/levenshtein_distance.bruijn new file mode 100644 index 0000000..2111ade --- /dev/null +++ b/samples/rosetta/levenshtein_distance.bruijn @@ -0,0 +1,10 @@ +:import std/Combinator . +:import std/Char C +:import std/List . +:import std/Math . + +levenshtein y [[[∅?1 ∀0 (∅?0 ∀1 (0 (1 [[[[go]]]])))]]] + go (C.eq? 3 1) (6 2 0) ++(lmin ((6 2 0) : ((6 5 0) : {}(6 2 4)))) + +:test ((levenshtein "rosettacode" "raisethysword") =? (+8)) ([[1]]) +:test ((levenshtein "kitten" "sitting") =? (+3)) ([[1]]) diff --git a/samples/rosetta/ternary_logic.bruijn b/samples/rosetta/ternary_logic.bruijn new file mode 100644 index 0000000..037ac41 --- /dev/null +++ b/samples/rosetta/ternary_logic.bruijn @@ -0,0 +1,71 @@ +true [[[0]]] + +maybe [[[1]]] + +false [[[2]]] + +¬‣ [0 true maybe false] + +:test (¬true) (false) +:test (¬maybe) (maybe) +:test (¬false) (true) + +…⋀… [[1 (0 1 1 1) (0 0 0 1) (0 0 0 0)]] + +:test (true ⋀ true) (true) +:test (true ⋀ maybe) (maybe) +:test (true ⋀ false) (false) +:test (maybe ⋀ true) (maybe) +:test (maybe ⋀ maybe) (maybe) +:test (maybe ⋀ false) (false) +:test (false ⋀ true) (false) +:test (false ⋀ maybe) (false) +:test (false ⋀ false) (false) + +…⋁… [[1 (0 0 0 0) (0 1 0 0) (0 1 1 1)]] + +:test (true ⋁ true) (true) +:test (true ⋁ maybe) (true) +:test (true ⋁ false) (true) +:test (maybe ⋁ true) (true) +:test (maybe ⋁ maybe) (maybe) +:test (maybe ⋁ false) (maybe) +:test (false ⋁ true) (true) +:test (false ⋁ maybe) (maybe) +:test (false ⋁ false) (false) + +…⊃… [[1 (0 true 0 1) (0 true 1 1) (0 1 1 1)]] + +:test (true ⊃ true) (true) +:test (true ⊃ maybe) (true) +:test (true ⊃ false) (true) +:test (maybe ⊃ true) (maybe) +:test (maybe ⊃ maybe) (maybe) +:test (maybe ⊃ false) (true) +:test (false ⊃ true) (false) +:test (false ⊃ maybe) (maybe) +:test (false ⊃ false) (true) + +…≡… [[1 (0 true 0 1) (0 1 1 1) (0 0 0 0)]] + +:test (true ≡ true) (true) +:test (true ≡ maybe) (maybe) +:test (true ≡ false) (false) +:test (maybe ≡ true) (maybe) +:test (maybe ≡ maybe) (maybe) +:test (maybe ≡ false) (maybe) +:test (false ≡ true) (false) +:test (false ≡ maybe) (maybe) +:test (false ≡ false) (true) + +# --- result samples --- + +:import std/List . + +main [[inp <> "=" <> !res ++ "\n"] <++> (cross3 ops trits trits)] + !‣ [0 "false" "maybe" "true"] + …<>… [[1 ++ " " ++ 0]] + inp 0 [[~1 <> (0 [[!1 <> (0 [[!1]])]])]] + res ^(^0) ^(~0) ^(~(~0)) + ops (…⋀… : "and") : ((…⋁… : "or") : ((…⊃… : "if") : {}(…≡… : "equiv"))) + trits true : (maybe : {}false) diff --git a/std/List.bruijn b/std/List.bruijn index fe4b6f9..56e9157 100644 --- a/std/List.bruijn +++ b/std/List.bruijn @@ -1,6 +1,7 @@ # MIT License, Copyright (c) 2022 Marvin Borner # Lists in Church/Boehm-Berarducci encoding using pairs # implementations are generally lazy (except when they're broken) +# TODO: look into https://hbr.github.io/Lambda-Calculus/lambda2/lambda.html#lists, has more elegant mapping :import std/Combinator . :import std/Pair P @@ -244,7 +245,9 @@ concat foldr append empty ⧗ (List a) → (List a) → (List a) # maps a function returning list of list and concatenates concat-map concat ∘∘ map ⧗ (a → (List b)) → (List a) → (List b) -:test (concat-map [-0 : {}0] ((+1) : {}(+2))) ((-1) : ((+1) : ((-2) : {}(+2)))) +…<++>… concat-map + +:test ([-0 : {}0] <++> ((+1) : {}(+2))) ((-1) : ((+1) : ((-2) : {}(+2)))) # zips two lists discarding excess elements zip z [[[rec]]] ⧗ (List a) → (List b) → (List (Pair a b)) @@ -314,13 +317,13 @@ drop-while z [[[rec]]] ⧗ (a → Boolean) → (List a) → (List a) :test (drop-while zero? ((+0) : ((+0) : {}(+1)))) ({}(+1)) # returns all combinations of two lists -cross [[concat-map [map [1 : 0] 1] 1]] ⧗ (List a) → (List b) → (List (Pair a b)) +cross [[[[1 : 0] <$> 1] <++> 1]] ⧗ (List a) → (List b) → (List (Pair a b)) :test (cross "ab" "cd") (('a' : 'c') : (('a' : 'd') : (('b' : 'c') : {}('b' : 'd')))) # returns all combinations of three lists # TODO: add/use triple type (list element types can be different) -cross3 [[[concat-map [concat-map [map [2 : (1 : {}0)] 2] 2] 2]]] ⧗ (List a) → (List a) → (List a) → (List (List a)) +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')))) diff --git a/test/Spec.hs b/test/Spec.hs deleted file mode 100644 index cd4753f..0000000 --- a/test/Spec.hs +++ /dev/null @@ -1,2 +0,0 @@ -main :: IO () -main = putStrLn "Test suite not yet implemented"