forked from Orchid/orchid
Backup commit before crunch
This commit is contained in:
54
notes/papers/report/parts/examples/+index.md
Normal file
54
notes/papers/report/parts/examples/+index.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Examples
|
||||
|
||||
The following examples all work in the submitted version of Orchid, they're included in various subdircetories of `examples`.
|
||||
|
||||
## Prelude
|
||||
|
||||
All code files implicitly include the head statement
|
||||
|
||||
```
|
||||
import prelude::*
|
||||
```
|
||||
|
||||
The `prelude` module is a string literal compiled into the interpreter. Its contents are as follows:
|
||||
|
||||
```rs
|
||||
static PRELUDE_TXT:&str = r#"
|
||||
import std::(
|
||||
add, subtract, multiply, remainder, divide,
|
||||
equals, ifthenelse,
|
||||
concatenate
|
||||
)
|
||||
|
||||
export ...$a + ...$b =1001=> (add (...$a) (...$b))
|
||||
export ...$a - ...$b:1 =1001=> (subtract (...$a) (...$b))
|
||||
export ...$a * ...$b =1000=> (multiply (...$a) (...$b))
|
||||
export ...$a % ...$b:1 =1000=> (remainder (...$a) (...$b))
|
||||
export ...$a / ...$b:1 =1000=> (divide (...$a) (...$b))
|
||||
export ...$a == ...$b =1002=> (equals (...$a) (...$b))
|
||||
export ...$a ++ ...$b =1003=> (concatenate (...$a) (...$b))
|
||||
|
||||
export do { ...$statement ; ...$rest:1 } =0x2p543=> (
|
||||
statement (...$statement) do { ...$rest }
|
||||
)
|
||||
export do { ...$return } =0x1p543=> (...$return)
|
||||
|
||||
export statement (let $name = ...$value) ...$next =0x1p1000=> (
|
||||
(\$name. ...$next) (...$value)
|
||||
)
|
||||
export statement (cps $name = ...$operation) ...$next =0x2p1000=> (
|
||||
(...$operation) \$name. ...$next
|
||||
)
|
||||
export statement (cps ...$operation) ...$next =0x1p1000=> (
|
||||
(...$operation) (...$next)
|
||||
)
|
||||
|
||||
export if ...$cond then ...$true else ...$false:1 =0x1p320=> (
|
||||
ifthenelse (...$cond) (...$true) (...$false)
|
||||
)
|
||||
|
||||
export ::(,)
|
||||
"#;
|
||||
```
|
||||
|
||||
The meaning of each of these rules is explained in the [calculator example](./calculator.md). The exact file is included here just as a reference while reading the other examples.
|
||||
@@ -1,24 +1,7 @@
|
||||
This example showcases common list processing functions and some functional programming utilities. It is also the first multi-file demo.
|
||||
# Fn
|
||||
|
||||
_in main.orc_
|
||||
```
|
||||
import std::(to_string, print)
|
||||
import super::list
|
||||
import fn::*
|
||||
This file contains a variety of utilities for functional programming
|
||||
|
||||
export main := do{
|
||||
let foo = list::new[1, 2, 3, 4, 5, 6];
|
||||
let bar = list::map foo n => n * 2;
|
||||
let sum = bar
|
||||
|> list::skip 2
|
||||
|> list::take 3
|
||||
|> list::reduce 0 (a b) => a + b;
|
||||
cps print $ to_string sum ++ "\n";
|
||||
0
|
||||
}
|
||||
```
|
||||
|
||||
_in fn.orc_
|
||||
```
|
||||
export Y := \f.(\x.f (x x))(\x.f (x x))
|
||||
|
||||
@@ -37,70 +20,11 @@ export (...$argv) => ...$body =0x2p512=> (bind_names (...$argv) (...$body))
|
||||
$name => ...$body =0x1p512=> (\$name. ...$body)
|
||||
```
|
||||
|
||||
_in list.orc_
|
||||
```
|
||||
import option
|
||||
import super::fn::*
|
||||
|
||||
pair := \a.\b. \f. f a b
|
||||
|
||||
-- Constructors
|
||||
|
||||
export cons := \hd.\tl. option::some (pair hd tl)
|
||||
export end := option::none
|
||||
|
||||
export pop := \list.\default.\f. list default \cons.cons f
|
||||
|
||||
-- Operators
|
||||
|
||||
export reduce := \list.\acc.\f. (
|
||||
loop r on (list acc) with
|
||||
pop list acc \head.\tail. r tail (f acc head)
|
||||
)
|
||||
|
||||
export map := \list.\f. (
|
||||
loop r on (list) with
|
||||
pop list end \head.\tail. cons (f head) (r tail)
|
||||
)
|
||||
|
||||
export skip := \list.\n. (
|
||||
loop r on (list n) with
|
||||
if n == 0 then list
|
||||
else pop list end \head.\tail. r tail (n - 1)
|
||||
)
|
||||
|
||||
export take := \list.\n. (
|
||||
loop r on (list n) with
|
||||
if n == 0 then end
|
||||
else pop list end \head.\tail. cons head $ r tail $ n - 1
|
||||
)
|
||||
|
||||
new[...$item, ...$rest:1] =0x2p333=> (cons (...$item) new[...$rest])
|
||||
new[...$end] =0x1p333=> (cons (...$end) end)
|
||||
new[] =0x1p333=> end
|
||||
|
||||
export ::(new)
|
||||
```
|
||||
|
||||
_in option.orc_
|
||||
```
|
||||
export some := \v. \d.\f. f v
|
||||
export none := \d.\f. d
|
||||
|
||||
export map := \option.\f. option none f
|
||||
export flatten := \option. option none \opt. opt
|
||||
export flatmap := \option.\f. option none \opt. map opt f
|
||||
```
|
||||
|
||||
The `main` function uses a `do{}` block to enclose a series of name bindings. It imports `list` as a sibling module and `fn` as a top-level file. These files are in identical position, the purpose of this is just to test various ways to reference modules.
|
||||
|
||||
## fn
|
||||
|
||||
### bind_names
|
||||
## bind_names
|
||||
|
||||
This is a utility macro for binding a list of names on an expression. It demonstrates how to extract reusable macro program fragments to simplify common tasks. This demonstrative version simply takes a sequence of name tokens without any separators or custom programming, but its functionality can be extended in the future to include eg. destructuring.
|
||||
|
||||
### arrow functions
|
||||
## arrow functions
|
||||
|
||||
The arrow `=>` operator here is used to define inline functions. It is very similar to the native `\x.` lambda, except that native lambdas use higher priority than any macro so they can't appear inside a `do{}` block as all of the subsequent lines would be consumed by them. It is parsed using the following rules:
|
||||
```
|
||||
@@ -108,7 +32,7 @@ export (...$argv) => ...$body =0x2p512=> (bind_names (...$argv) (...$body))
|
||||
$name => ...$body =0x1p512=> (\$name. ...$body)
|
||||
```
|
||||
|
||||
### pipelines
|
||||
## pipelines
|
||||
|
||||
This is a concept borrowed from Elixir. The `|>` operator simply inserts the output of the previous expression to the first argument of the following function.
|
||||
```
|
||||
@@ -117,11 +41,11 @@ export ...$prefix |> $fn ..$suffix:1 =0x2p130=> $fn (...$prefix) ..$suffix
|
||||
|
||||
It is processed left-to-right, but leaves the suffix on the same level as the function and sinks the prefix, which means that long pipelines eventually become left associative despite the inverted processing order.
|
||||
|
||||
### right-associative function call operator
|
||||
## right-associative function call operator
|
||||
|
||||
The `$` operator is analogous to its Haskell counterpart. It is right-associative and very low priority. Its purpose is to eliminate trailing parentheses.
|
||||
|
||||
### Loop expression
|
||||
## Loop expression
|
||||
|
||||
Recursion in lambda calculus is achieved using a fixpoint combinator. The classic version of this combinator described by Church is the [Y-combinator][hb_tlc], defined like so:
|
||||
```
|
||||
71
notes/papers/report/parts/examples/list-processing/list.md
Normal file
71
notes/papers/report/parts/examples/list-processing/list.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# List
|
||||
|
||||
These files demonstrate building datastructures using closures.
|
||||
|
||||
## Option.orc
|
||||
|
||||
Option is among the simplest datastructures. It either stores a value or nothing. To interact with it, one must provide a default value and a selector.
|
||||
|
||||
```
|
||||
export some := \v. \d.\f. f v
|
||||
export none := \d.\f. d
|
||||
|
||||
export map := \option.\f. option none f
|
||||
export flatten := \option. option none \opt. opt
|
||||
export flatmap := \option.\f. option none \opt. map opt f
|
||||
```
|
||||
|
||||
The selector is required in lambda calculus because the only way to obtain information about values is to evaluate them, but it's not actually necessary in Orchid because it's always possible to pass a primitive of incompatible type as the default value and then use equality comparison to decide whether we got the value in the option or our dud. Regardless, this interface is vastly more convenient and probably more familiar to programmers coming from functional languages.
|
||||
|
||||
## List.orc
|
||||
|
||||
The linked list is an outstandingly powerful and versatile datastructure and the backbone of practical functional programming. This implementation uses a locally defined church pair and the option defined above in an effort to be more transparent, although this means that the essential operation of splitting the head and tail or returning a default value becomes an explicit function (here named `pop`) instead of the intrinsic interface of the list itself.
|
||||
|
||||
_in list.orc_
|
||||
```
|
||||
import option
|
||||
import super::fn::*
|
||||
|
||||
pair := \a.\b. \f. f a b
|
||||
|
||||
-- Constructors
|
||||
|
||||
export cons := \hd.\tl. option::some (pair hd tl)
|
||||
export end := option::none
|
||||
|
||||
-- Operators
|
||||
|
||||
export pop := \list.\default.\f. list default \cons.cons f
|
||||
|
||||
export reduce := \list.\acc.\f. (
|
||||
loop r on (list acc) with
|
||||
pop list acc \head.\tail. r tail (f acc head)
|
||||
)
|
||||
|
||||
export map := \list.\f. (
|
||||
loop r on (list) with
|
||||
pop list end \head.\tail. cons (f head) (r tail)
|
||||
)
|
||||
|
||||
export skip := \list.\n. (
|
||||
loop r on (list n) with
|
||||
if n == 0 then list
|
||||
else pop list end \head.\tail. r tail (n - 1)
|
||||
)
|
||||
|
||||
export take := \list.\n. (
|
||||
loop r on (list n) with
|
||||
if n == 0 then end
|
||||
else pop list end \head.\tail. cons head $ r tail $ n - 1
|
||||
)
|
||||
|
||||
new[...$item, ...$rest:1] =0x2p333=> (cons (...$item) new[...$rest])
|
||||
new[...$end] =0x1p333=> (cons (...$end) end)
|
||||
new[] =0x1p333=> end
|
||||
|
||||
export ::(new)
|
||||
```
|
||||
|
||||
Most of these operations should be self-explanatory in the context of the parts defined in [fn.md](./fn.md).
|
||||
|
||||
The `new[]` macro builds a list from data. Because they are expected to contain expressions, the fields here are comma separated unlike in `fn::=>` and `fn::loop`. I did not find this inconsistency jarring during initial testing, but it may be updated if further improvements to `loop` and `=>`'s syntax open up the possibility of multi-token field descriptions.
|
||||
30
notes/papers/report/parts/examples/list-processing/main.md
Normal file
30
notes/papers/report/parts/examples/list-processing/main.md
Normal file
@@ -0,0 +1,30 @@
|
||||
This example showcases common list processing functions and some functional programming utilities. It is also the first multi-file demo.
|
||||
|
||||
_in main.orc_
|
||||
```
|
||||
import std::(to_string, print)
|
||||
import super::list
|
||||
import fn::*
|
||||
|
||||
export main := do{
|
||||
let foo = list::new[1, 2, 3, 4, 5, 6];
|
||||
let bar = list::map foo n => n * 2;
|
||||
let sum = bar
|
||||
|> list::skip 2
|
||||
|> list::take 3
|
||||
|> list::reduce 0 (a b) => a + b;
|
||||
cps print $ to_string sum ++ "\n";
|
||||
0
|
||||
}
|
||||
```
|
||||
|
||||
This file imports `list` as a sibling module and `fn` as a top-level file. These files are in identical position, the purpose of this is just to test various ways to reference modules.
|
||||
|
||||
- The contents of _fn.orc_ are described in [fn](./fn.md)
|
||||
- _list.orc_ and its dependency, _option.orc_ are described in [list](./list.md)
|
||||
|
||||
---
|
||||
|
||||
The `main` function uses a `do{}` block to enclose a series of name bindings. It constructs a list of numbers 1-6. This is done eagerly, or at least a linked list of the same size is constructed eagerly, although the `cons` calls are left until the first read. Due to Orchid's laziness, `bar` gets assigned the `map` call as-is. `sum` is assigned from the `|>` pipe chain, which is essentially the same as a chain of further name bindings; the return value of each function is passed as the first argument of the next, pushing subsequent arguments out of the way.
|
||||
|
||||
When the `print` expression is evaluated, the updates are applied as needed; the mapping is never applied to 1 and 2, and none of the loops in the list processing functions execute their body on the list object containing 6.
|
||||
Reference in New Issue
Block a user