├── .gitattributes
├── .gitignore
├── extra
└── site-demo.gif
├── src
├── encode.rs
├── parse.lalrpop
├── encode
│ ├── function.rs
│ ├── numerals.rs
│ └── boolean.rs
├── wasm.rs
├── macros.rs
├── lib.rs
└── normal.rs
├── examples
├── fv.rs
├── site
│ ├── index.html
│ ├── package.json
│ ├── index.css
│ ├── webpack.config.js
│ └── index.js
├── y.rs
├── fn.rs
├── encode.rs
├── env.rs
├── macros.rs
└── parse.rs
├── benches
├── numerals.rs
└── baselines
│ ├── v0.3.0_bench.json
│ └── v0.4.0_bench.json
├── deploy.sh
├── Cargo.toml
├── LICENSE
├── .travis.yml
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | src/parse.lalrpop linguist-language=rust
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | **/*.rs.bk
3 | examples/site/node_modules
4 |
5 | Cargo.lock
6 |
--------------------------------------------------------------------------------
/extra/site-demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nixpulvis/lalrpop-lambda/HEAD/extra/site-demo.gif
--------------------------------------------------------------------------------
/src/encode.rs:
--------------------------------------------------------------------------------
1 | // Functions themselves
2 | mod function;
3 |
4 | // Church booleans
5 | mod boolean;
6 |
7 | // Church numerals
8 | mod numerals;
9 |
--------------------------------------------------------------------------------
/examples/fv.rs:
--------------------------------------------------------------------------------
1 | #![feature(box_syntax)]
2 |
3 | #[macro_use]
4 | extern crate lalrpop_lambda;
5 |
6 | fn main() {
7 | dbg!(app!(abs!{x.app!(x,y)}, abs!{y.app!(x,y)}).free_variables());
8 | dbg!(app!(abs!{f.abs!{x.app!(f,x)}}, abs!{x.x}).free_variables());
9 | }
10 |
--------------------------------------------------------------------------------
/examples/site/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | λ-calculus
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/examples/y.rs:
--------------------------------------------------------------------------------
1 | #![feature(non_ascii_idents)]
2 | extern crate lalrpop_lambda;
3 |
4 | use lalrpop_lambda::parse::ExpressionParser;
5 |
6 | fn main() {
7 | let parser = ExpressionParser::new();
8 |
9 | // Make the Y combinator.
10 | println!("ω = {}", parser.parse(r"λx.(x x)").unwrap());
11 | println!("Ω = {}", parser.parse(r"(λx.(x x)) (λx.(x x))").unwrap());
12 | println!("W = {}", parser.parse(r"λf.λx. f x x").unwrap());
13 | println!("Y = {}", parser.parse(r"λf.(λx.f (x x)) (λx.f (x x))").unwrap());
14 | }
15 |
--------------------------------------------------------------------------------
/examples/site/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "serve": "webpack-dev-server"
4 | },
5 | "dependencies": {
6 | "@babel/core": "^7.9.0",
7 | "@babel/preset-env": "^7.9.0",
8 | "@babel/preset-react": "^7.9.4",
9 | "babel-loader": "^8.1.0",
10 | "lalrpop-lambda": "file:../../pkg",
11 | "react": "^16.13.1",
12 | "react-dom": "^16.13.1"
13 | },
14 | "devDependencies": {
15 | "babel-plugin-syntax-dynamic-import": "^6.18.0",
16 | "webpack": "^4.42.1",
17 | "webpack-cli": "^3.3.11",
18 | "webpack-dev-server": "^3.10.3"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/examples/fn.rs:
--------------------------------------------------------------------------------
1 | #![feature(box_syntax)]
2 |
3 | #[macro_use]
4 | extern crate lalrpop_lambda;
5 |
6 | use lalrpop_lambda::Expression;
7 |
8 | fn main() {
9 | let two = abs!{f.abs!{x.app!(var!(f), app!(var!(f), var!(x)))}};
10 | println!("{}", two(var!(x))(var!(x)));
11 | println!("{}", var!(x)(var!(y)));
12 | println!("{}", app!(var!(x),var!(y))(var!(z)));
13 |
14 | println!("{:?}", λ!{x.x}(1));
15 |
16 | let id: fn(u64) -> u64 = |x| x;
17 | println!("{}", Expression::from(id));
18 | let f = u64>::from(abs!{x.x});
19 | println!("{}", Expression::from(f));
20 | }
21 |
--------------------------------------------------------------------------------
/examples/site/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 10px 20px;
3 | }
4 |
5 | .inputs * {
6 | display: block;
7 | }
8 |
9 | textarea {
10 | border: 2px dashed black;
11 | color: black;
12 | font-size: 16px;
13 | font-family: monospace;
14 | height: 3in;
15 | overflow: auto;
16 | width: 100%;
17 | margin-bottom: 5px;
18 | }
19 |
20 | table {
21 | border-spacing: 5px 0;
22 | }
23 |
24 | table th {
25 | text-align: right;
26 | }
27 |
28 | code {
29 | padding: 0 3px;
30 | background: #ddd;
31 | font-size: 16px;
32 | }
33 |
34 | p strong + code {
35 | margin-left: 3px;
36 | }
37 |
38 | code.error {
39 | background: #f25;
40 | }
41 |
--------------------------------------------------------------------------------
/examples/site/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | module.exports = {
3 | mode: "development",
4 | entry: "./index.js",
5 | output: {
6 | path: path.resolve(__dirname, "dist"),
7 | filename: "index.js",
8 | },
9 | module: {
10 | rules: [
11 | {
12 | test: /.(js|jsx)$/,
13 | exclude: /node_modules/,
14 | use: {
15 | loader: 'babel-loader',
16 | options: {
17 | presets: ['@babel/preset-env',
18 | '@babel/preset-react'],
19 | plugins: ['syntax-dynamic-import']
20 | }
21 | }
22 | }
23 | ]
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/benches/numerals.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate criterion;
3 | extern crate lalrpop_lambda;
4 |
5 | use criterion::Criterion;
6 | use lalrpop_lambda::Expression;
7 |
8 | fn compare_benchmark(c: &mut Criterion) {
9 | c.bench_function_over_inputs("native addition", |b, &n| {
10 | b.iter(|| {
11 | n + n
12 | })
13 | }, &[0,1,2,4,8,16,32]);
14 |
15 | c.bench_function_over_inputs("λ-expression addition", |b, &n| {
16 | b.iter(|| {
17 | let e = Expression::from(*n);
18 | u64::from(e.clone() + e)
19 | })
20 | }, &[0,1,2,4,8,16,32]);
21 | }
22 |
23 | criterion_group!(benches, compare_benchmark);
24 | criterion_main!(benches);
25 |
--------------------------------------------------------------------------------
/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Get the current git revision short name.
4 | rev=$(git rev-parse --short HEAD)
5 |
6 | # Assume the docs are already built...
7 | cd target/doc
8 |
9 | # Create a new clone of the git repository here.
10 | git init
11 | # TODO: Deploy as a deployer, or others?
12 | git config user.name "Nathan Lilienthal"
13 | git config user.email "nathan@nixpulvis.com"
14 | # Create a remote to the GitHub repository.
15 | git remote add upstream "https://$GH_TOKEN@github.com/nixpulvis/lalrpop-lambda"
16 | # Fetch, and checkout to the GitHub Pages branch.
17 | git fetch upstream && git reset upstream/gh-pages
18 |
19 | touch .
20 | git add -A .
21 |
22 | # Commit the new build.
23 | git commit -m "rebuild pages at ${rev}"
24 | # Push the new build.
25 | git push -q upstream HEAD:gh-pages
26 |
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "lalrpop-lambda"
3 | description = "A λ-calculus grammar writting with LALRPOP."
4 | repository = "https://github.com/nixpulvis/lalrpop-lambda"
5 | version = "0.6.1"
6 | authors = ["Nathan Lilienthal "]
7 | license = "MIT"
8 | edition = "2018"
9 | build = "build.rs"
10 |
11 | [features]
12 | default = ["wasm"]
13 | wasm = ["wasm-bindgen"]
14 |
15 | [lib]
16 | crate-type = ["rlib", "cdylib"]
17 |
18 | [dependencies]
19 | lalrpop-util = "0.18.1"
20 | regex = "1.3.6"
21 | wasm-bindgen = { version = "0.2.60", optional = true }
22 | pretty_assertions = "0.6.1"
23 |
24 | [build-dependencies]
25 | lalrpop = { version = "0.18.1", features = ["lexer"] }
26 |
27 | [dev-dependencies]
28 | criterion = "0.3.1"
29 |
30 | [[bench]]
31 | name = "numerals"
32 | harness = false
33 |
--------------------------------------------------------------------------------
/examples/encode.rs:
--------------------------------------------------------------------------------
1 | #![feature(non_ascii_idents, box_syntax)]
2 | extern crate lalrpop_lambda;
3 |
4 | use lalrpop_lambda::Expression;
5 |
6 | fn main() {
7 | let n = 0;
8 | let ln = Expression::from(n);
9 | let nn = u64::from(ln.clone());
10 | println!("{} -> {} -> {}", n, ln, nn);
11 |
12 | let n = 1;
13 | let ln = Expression::from(n);
14 | let nn = u64::from(ln.clone());
15 | println!("{} -> {} -> {}", n, ln, nn);
16 |
17 | let n = 5;
18 | let ln = Expression::from(n);
19 | let nn = u64::from(ln.clone());
20 | println!("{} -> {} -> {}", n, ln, nn);
21 |
22 | let t = true;
23 | let lt = Expression::from(t);
24 | let tt = bool::from(lt.clone());
25 | println!("{} -> {} -> {}", t, lt, tt);
26 |
27 | let f = false;
28 | let lf = Expression::from(f);
29 | let ff = bool::from(lf.clone());
30 | println!("{} -> {} -> {}", f, lf, ff);
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2019 Nathan Lilienthal
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/examples/env.rs:
--------------------------------------------------------------------------------
1 | #![feature(non_ascii_idents, box_syntax)]
2 |
3 | #[macro_use]
4 | extern crate lalrpop_lambda;
5 |
6 | use std::collections::HashMap;
7 | use lalrpop_lambda::Strategy;
8 |
9 | macro_rules! resolve {
10 | ($expr:expr, $env:expr) => {
11 | println!("{} -r> {} -> {}",
12 | $expr,
13 | $expr.resolve($env),
14 | $expr.resolve($env).normalize(&Strategy::Applicative(false)));
15 | }
16 | }
17 |
18 | fn main() {
19 | let mut env = HashMap::new();
20 | env.insert(variable!(i), abs!{x.x});
21 | env.insert(variable!(n), 1.into());
22 | env.insert(variable!(x), var!(x));
23 | for (v, e) in &env {
24 | println!("{} := {}", v, e);
25 | }
26 | resolve!(var!(n), &env);
27 | resolve!(var!(x), &env);
28 | resolve!(var!(q), &env);
29 | resolve!(abs!{a.a}, &env);
30 | resolve!(abs!{a.n}, &env);
31 | resolve!(app!(a,n), &env);
32 | resolve!(app!(n,a), &env);
33 | resolve!(app!(n,n), &env);
34 | resolve!(app!(i,n), &env);
35 | }
36 |
--------------------------------------------------------------------------------
/src/parse.lalrpop:
--------------------------------------------------------------------------------
1 | use crate::{Expression, Variable};
2 |
3 | grammar;
4 |
5 | pub Variable: Variable = {
6 | Id => Variable(<>, None),
7 | ":" => Variable(id, Some(ty)),
8 | };
9 |
10 | pub Expression: Expression = {
11 | Abstraction => <>,
12 | Application => <>,
13 | }
14 |
15 | Abstraction: Expression = {
16 | => {
17 | let body = match term {
18 | Some((_, o @ Some(_))) => o,
19 | _ => None,
20 | };
21 | Expression::build_abs(ls.len(), ids, body)
22 | },
23 | }
24 |
25 | Application: Expression = {
26 | // NOTE: Base case of terminals is here to allow the `Application`
27 | // production to be left associative.
28 | Terminal => <>,
29 | => app!({e1},{e2}),
30 | }
31 |
32 | Terminal: Expression = {
33 | Variable => Expression::Var(<>),
34 | "(" ")" => e,
35 | }
36 |
37 | Lambda = {
38 | "λ",
39 | "\\",
40 | }
41 |
42 | Id: String = r"[a-zA-Z0-9-_]+" => {
43 | <>.to_string()
44 | };
45 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: rust
2 | sudo: false
3 | rust:
4 | - stable
5 | - beta
6 | - nightly
7 |
8 | matrix:
9 | allow_failures:
10 | - rust: stable
11 | - rust: beta
12 |
13 | script:
14 | - cargo test
15 | - cargo doc --no-deps
16 |
17 | after_success:
18 | # TODO: PR/branch docs.
19 | - test $TRAVIS_PULL_REQUEST == "false" &&
20 | test $TRAVIS_BRANCH == "master" &&
21 | test $TRAVIS_ALLOW_FAILURE == "false" &&
22 | bash deploy.sh
23 |
24 | env:
25 | global:
26 | secure: Qg/smWvkCJGLDb42Mh61qzoLiXqbxfGcIp98JGTml8M194bCBxzMJFVomYE2h8Hz4Oc+opW6phWR2yS9OTy04Uf6c/Y+DDBrSj2F+J0wn6+1u0MktzGjLHvz9Nv+7FFp5gNcUAbUOkc2VptbiBype4hL/VUnbhAnu/cDxUvugOfYpdJSCn8cAAqCT1v7K8NOFLDJDzH3vFcNM+VNFVFyLQP/1p3rJExECYtE8/75QPqGDWeHhA6g/OZ/h3203xrhaopocVVA1aATp8K7719Fy7Aiqf/hArU+WFJZ/kBKm4Eng4m/8T5ZsFbJX2qngFvryKvloELKSWuT1QFPFK81lfOHcBb+gQV8BMihpOs7UErOXFZPjyYPyXjgPcAZ9QTvsEnD1E2PED/S5F5s4ZmpTcwdI9w0A5ZDYaqbcMJ0dfOIyppQrWun2i62qdcMaP/gxMn3csF1aw7Xu6gAQvhiuyWWEDYcmv0mgn33cUTeT+bDAVMSFfATQ4CHkom5oj00V04Ep3OhJDs5VEi0+3/uz2UodxTM+XgSlbzMK3n/sLzb6jyqChGboVjhHGyLjbPZE2ZflkLO3+nMg1Ub5UT4deHK8GOpDjiyPNUL5pwFwFWZiR4nbf94ISucGaNE59MU3oTSiJuqKWDJ/Xnhh9/yvAzDubuDZvBPQ008in9fscQ=
27 |
--------------------------------------------------------------------------------
/examples/macros.rs:
--------------------------------------------------------------------------------
1 | #![feature(non_ascii_idents, box_syntax)]
2 |
3 | #[macro_use]
4 | extern crate lalrpop_lambda;
5 |
6 | use lalrpop_lambda::Strategy;
7 |
8 | fn main() {
9 | // Both the short `λ!` macro, as well as the ASCII `abs!` macro.
10 | println!("{} = {}", λ!{x.x}, abs!{x.x});
11 |
12 | // Mix in rust bindings with lambda calculus macros using `{binding}`.
13 | let ω = abs!{x.app!(x,x)};
14 | println!("ω: {}", ω);
15 | // Doesn't do what you might want.
16 | println!("app!(ω,x): {}", app!(ω,x));
17 | // But this does ;)
18 | println!("app!({{&ω}},x): {} -> {}",
19 | app!({&ω},x),
20 | app!({&ω},x).normalize(&Strategy::Applicative(false)));
21 |
22 | // An empty church numeral.
23 | let zero = λ!{f.λ!{x.x}};
24 | println!("0: {}", &zero);
25 |
26 | // A single church numeral.
27 | let one = λ!{f.λ!{x.γ!(f, x)}};
28 | println!("1: {}", &one);
29 |
30 | // Identity application.
31 | let id = λ!{x.x};
32 | println!("(id one): {} -> {}",
33 | app!({&id}, {&one}),
34 | app!({&id}, {&one}).normalize(&Strategy::Applicative(false)));
35 |
36 | let two = abs!{f.abs!{x.app!(var!(f),
37 | app!(app!(abs!{f.abs!{x.app!(var!(f),
38 | var!(x))}},
39 | var!(f)),var!(x)))}};
40 | println!("two: {} -> {}",
41 | two,
42 | two.normalize(&Strategy::Applicative(false)));
43 |
44 | // Mmmmm, curry.
45 | println!("{}", abs!{x y.app!(x,y)});
46 | println!("{}", abs!{.abs!{.abs!{.var!("")}}});
47 |
48 | // Try out a type.
49 | println!("{}", abs!{x:t.x});
50 | }
51 |
--------------------------------------------------------------------------------
/examples/parse.rs:
--------------------------------------------------------------------------------
1 | #![feature(non_ascii_idents)]
2 | extern crate lalrpop_lambda;
3 |
4 | use lalrpop_lambda::{Expression, Strategy};
5 | use lalrpop_lambda::parse::ExpressionParser;
6 |
7 | macro_rules! parse {
8 | ($expr:expr $(, $func:expr)?) => {{
9 | let e = ExpressionParser::new().parse($expr).unwrap();
10 | print!("{} parse-> {}", $expr, e);
11 | $(
12 | let e = $func(&e, &Strategy::Applicative(false)); // very funky.
13 | print!(" -> {}", e);
14 | )?
15 | println!("");
16 | e
17 | }}
18 | }
19 |
20 | fn main() {
21 | parse!("x");
22 | parse!(r"\x.x");
23 | parse!(r"\x.y");
24 | parse!("x x");
25 | parse!("x y");
26 |
27 | // A type!
28 | parse!(r"\x:t.x x");
29 |
30 | println!();
31 | parse!(r"\\\x y.x y");
32 | parse!(r"\x y.x y");
33 | parse!(r"\\\");
34 | println!();
35 |
36 | println!();
37 | parse!(r"(\x.x) x", Expression::normalize);
38 | parse!(r"(\x.x) y", Expression::normalize);
39 |
40 | // Single β-reduction identity function.
41 | println!();
42 | parse!(r"\x.x a", Expression::normalize);
43 | parse!(r"(\x.x) a", Expression::normalize);
44 |
45 | // Partial application.
46 | println!();
47 | let norm = parse!(r"(\x.\y.x y) a", Expression::normalize);
48 | parse!(&format!("({}) b", norm), Expression::normalize);
49 | // Multiple (curried) β-reductions on an identity function.
50 | parse!(r"(\x.\y.x y) a b", Expression::normalize);
51 |
52 | println!();
53 | parse!(r"((\x.(\x.x x) a) b)", Expression::normalize);
54 |
55 | // Ω
56 | println!();
57 | parse!(r"\x.(x x) (\x.(x x))");
58 | parse!(r"(\x.(x x)) (\x.(x x))");
59 | // XXX: Blows the stack in our strategy.
60 | parse!(r"(\x.(x x)) (\x.(x x))", Expression::normalize);
61 | }
62 |
--------------------------------------------------------------------------------
/src/encode/function.rs:
--------------------------------------------------------------------------------
1 | use crate::{Expression, Abstraction};
2 |
3 | /// Function call support for an `Expression`.
4 | ///
5 | /// ```
6 | /// # #![feature(box_syntax)]
7 | /// # #[macro_use]
8 | /// # extern crate lalrpop_lambda;
9 | /// # fn main() {
10 | /// assert_eq!(0u64, λ!{x.x}(0).into());
11 | /// assert_eq!(γ!(γ!(a,b),0), γ!(a,b)(0));
12 | /// # }
13 | /// ```
14 | impl FnOnce<(T,)> for Expression
15 | where T: Into +
16 | From
17 | {
18 | // TODO: Return Option here too.
19 | type Output = Expression;
20 |
21 | extern "rust-call" fn call_once(self, t: (T,)) -> Expression {
22 | γ!({self},t.0.into())
23 | }
24 | }
25 |
26 | impl From for fn(u64) -> u64 {
27 | fn from(e: Expression) -> Self {
28 | match e {
29 | Expression::Abs(Abstraction(ref lid, box ref e1)) => {
30 | match e1 {
31 | Expression::Var(ref rid) if lid == rid => {
32 | |x| x
33 | },
34 | Expression::Var(_) => {
35 | |_| 0
36 | },
37 | _ => unreachable!(),
38 | }
39 | },
40 | _ => |_| panic!("not a function"),
41 | }
42 | }
43 | }
44 |
45 | impl From u64> for Expression {
46 | fn from(_f: fn(u64) -> u64) -> Self {
47 | // TODO: Since we can't call `f` now, we should bind it to an `env` and
48 | // add a reference to f here.
49 | //
50 | // un-η
51 | abs!{x.app!(f,x)}
52 | }
53 | }
54 |
55 |
56 | #[cfg(test)]
57 | mod tests {
58 | use pretty_assertions::assert_eq;
59 |
60 | #[test]
61 | fn var() {
62 | let one = abs!{f.abs!{x.app!(f,x)}};
63 | assert_eq!(app!(x,{one}), var!(x)(1));
64 | }
65 |
66 | #[test]
67 | fn abs() {
68 | assert_eq!(5u64, abs!{x.x}(5).into());
69 | }
70 |
71 | #[test]
72 | fn app() {
73 | let zero = abs!{f.abs!{x.x}};
74 | assert_eq!(app!(app!(a,b),{zero}), app!(a,b)(0));
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # λ-calculus Parser (using LALRPOP)
2 |
3 | [](https://travis-ci.org/nixpulvis/lalrpop-lambda)
4 | [](https://crates.io/crates/lalrpop-lambda)
5 | [](https://docs.rs/lalrpop-lambda)
6 |
7 | Write lambda calculus with ease, and evaluate it. There are a number of ways to
8 | use this library (each interchangeable with another):
9 |
10 | - `Expression` AST variants `Abs`, `App`, and `Var`
11 | - Macros `abs!`/`λ!`, `app!`/`γ!`, and `var!`
12 |
13 | ```rust
14 | let id = λ!{x.x};
15 | let one = λ!{f.λ!{x.γ!(f,x)}};
16 | assert_eq!(1u64, u64::from(app!({id},{one})));
17 | ```
18 |
19 | - Parsed λ-calculus strings
20 |
21 | ```rust
22 | let parser = ExpressionParser::new();
23 | parser.parse(r"\a b.a");
24 | parser.parse(r"\f x.(f (f x))");
25 | parser.parse(r"\\\x y z");
26 | ```
27 |
28 | - Native types: `u64`, `bool`, `fn` (WIP)
29 |
30 | ```rust
31 | assert_eq!(λ!{f.λ!{x.γ!(f,γ!(f,x))}}, Expression::from(2u64));
32 | assert_eq!(true, bool::from(λ!{a.λ!{b.a}}));
33 | assert_eq!(1, λ!{x.x}(1));
34 | ```
35 |
36 | 
37 |
38 | The above is generated with `wasm-pack`, see [example/site][example/site].
39 |
40 | ### Usage (Rust)
41 |
42 | ```toml
43 | [dependencies]
44 | lalrpop_lambda = "*"
45 | ```
46 |
47 | Read the [Rust documentation](https://docs.rs/lalrpop-lambda) for more
48 | information.
49 |
50 | ### Usage (WASM/JS)
51 |
52 | An `Exp` structure is provided through WASM for use in JS. This allows cross
53 | platform, client-side, web based interfaces to be built for the λ-calculus.
54 |
55 | Read the [WASM documentation][lalrpop_lambda-wasm] for more information.
56 |
57 | ### Development
58 |
59 | This assumes you have an updated and working copy of [`rustup`][rustup].
60 |
61 | ```sh
62 | cargo +nightly [build | test | bench | doc | run --example <>]
63 | ```
64 |
65 | ##### WASM
66 |
67 | First make sure you have `wasm-pack` installed. Then:
68 |
69 | ```
70 | wasm-pack build
71 | cd examples/site
72 | npm run serve
73 | ```
74 |
75 | [example/site]: https://github.com/nixpulvis/lalrpop-lambda/blob/master/examples/site/index.js
76 | [lalrpop_lambda-wasm]: https://docs.rs/lalrpop-lambda/latest/lalrpop_lambda/wasm/index.html
77 |
--------------------------------------------------------------------------------
/examples/site/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import("./node_modules/lalrpop-lambda/lalrpop_lambda.js").then(wasm => {
5 | class LambdaEditor extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = { input: '', expression: null, error: null };
9 | this.handleChange = this.handleChange.bind(this);
10 | }
11 |
12 | handleChange(event) {
13 | let input = event.target.value;
14 |
15 | try {
16 | let expression = new wasm.Exp(input);
17 | this.setState({ input, expression, error: null });
18 | } catch(e) {
19 | this.setState({ input, expression: null, error: e });
20 | }
21 | }
22 |
23 | render() {
24 | if (this.state.input === '') {
25 | var display = (
26 |
27 | Input a valid λ-expression, e.g.
28 | \x.x x
29 |
30 | );
31 | } else if (this.state.error) {
32 | var display =
33 | } else {
34 | var display =
35 | }
36 |
37 | return (
38 |
39 |
41 | {display}
42 |
43 | );
44 | }
45 | }
46 |
47 | class LambdaOutputs extends React.Component {
48 | render() {
49 | let outputs = [
50 | { label: 'parse', func: 'toString' },
51 | { label: 'app ->', func: 'applicative' },
52 | { label: 'cbv ->', func: 'call_by_value' },
53 | { label: 'norm ->', func: 'normal' },
54 | { label: 'cbn ->', func: 'call_by_name' },
55 | // TODO: Hybrid by-func and applicative.
56 | { label: 'spine ->', func: 'head_spine' },
57 | // TODO: Hybrid head spine and normal.
58 | { label: "numeral =", func: 'toNumber' },
59 | { label: "bool =", func: 'toBool' },
60 | ];
61 | return (
62 |
63 |
64 | {outputs.map((o, i) => {
65 | return ();
69 | })}
70 |
71 |
72 | )
73 | }
74 | }
75 |
76 | class LambdaOutput extends React.Component {
77 | render() {
78 | if (this.props.func) {
79 | try {
80 | var result = (
81 | {this.props.exp[this.props.func]().toString()}
82 | );
83 | } catch(e) {
84 | var result = {e.toString()};
85 | }
86 | } else {
87 | var result = '';
88 | }
89 | return (
90 |
91 | | {this.props.label} |
92 | {result} |
93 |
94 | );
95 | }
96 | }
97 |
98 | class LambdaParseError extends React.Component {
99 | render() {
100 | return (
101 |
102 | {this.props.message}
103 |
104 | )
105 | }
106 | }
107 |
108 | ReactDOM.render(, document.getElementById('mount'));
109 | });
110 |
--------------------------------------------------------------------------------
/src/wasm.rs:
--------------------------------------------------------------------------------
1 | //! WASM types for use in JS.
2 | //!
3 | //! In addition to the Rust [crate][TODO], the WASM package is published to NPM
4 | //! as well. If you are only interested in using this library from JS, this should
5 | //! be all you need.
6 | //!
7 | //! ### Install
8 | //!
9 | //! ```sh
10 | //! npm install lalrpop-lambda [--save]
11 | //! ```
12 | //!
13 | //! Once this module is compiled to WASM, it must be loaded. Read more about [Loading and running
14 | //! WebAssembly code](https://developer.mozilla.org/en-US/docs/WebAssembly/Loading_and_running).
15 | //!
16 | //! ```js
17 | //! const module_path = "./node_modules/lalrpop-lambda/lalrpop_lambda.js";
18 | //! import(module_path).then(lambda => { ... });
19 | //! ```
20 | //!
21 | //! See `examples/site` for more.
22 | use wasm_bindgen::prelude::*;
23 | use crate::{parse, Expression};
24 | use crate::normal::Strategy;
25 |
26 | /// A parsed λ-expression
27 | ///
28 | /// This struct is a wrapper around an [`Expression`] to both allow exporting it to JS, and to
29 | /// contain functions functions we want to export for the `Exp`, for example [`Exp::to_string`].
30 | #[wasm_bindgen]
31 | pub struct Exp(Expression);
32 |
33 | #[wasm_bindgen]
34 | impl Exp {
35 | /// Parse and construct a new `Expr`
36 | ///
37 | /// ```js
38 | /// new lambda.Exp("(\\x.x x) y");
39 | /// new lambda.Exp(2);
40 | /// new lambda.Exp(false);
41 | /// new lambda.Exp("*wtf"); // Throws exception.
42 | /// ```
43 | #[wasm_bindgen(constructor)]
44 | pub fn new(v: JsValue) -> Result {
45 | if let Some(s) = v.as_string() {
46 | let parser = parse::ExpressionParser::new();
47 | match parser.parse(&s) {
48 | Ok(e) => Ok(Exp(e)),
49 | Err(e) => Err(JsValue::from_str(&format!("{}", e))),
50 | }
51 | } else if let Some(n) = v.as_f64() {
52 | Ok(Exp(Expression::from(n as u64)))
53 | } else if let Some(b) = v.as_bool() {
54 | Ok(Exp(Expression::from(b)))
55 | } else {
56 | Err(JsValue::from_str("invalid constructor type"))
57 | }
58 | }
59 |
60 |
61 | pub fn applicative(&self, η: bool) -> Self {
62 | Exp(self.0.normalize(&Strategy::Applicative(η)))
63 | }
64 |
65 | pub fn call_by_value(&self) -> Self {
66 | Exp(self.0.normalize(&Strategy::CallByValue))
67 | }
68 |
69 | pub fn normal(&self, η: bool) -> Self {
70 | Exp(self.0.normalize(&Strategy::Normal(η)))
71 | }
72 |
73 | pub fn call_by_name(&self) -> Self {
74 | Exp(self.0.normalize(&Strategy::CallByName))
75 | }
76 |
77 | pub fn head_spine(&self, η: bool) -> Self {
78 | Exp(self.0.normalize(&Strategy::HeadSpine(η)))
79 | }
80 |
81 |
82 | /// See [`std::fmt::Display`]
83 | ///
84 | /// ```js
85 | /// let expr = new lambda.Exp("\\x.x x");
86 | /// console.log(`${expr}`);
87 | /// ```
88 | #[wasm_bindgen(method, js_name = toString)]
89 | pub fn to_string(&self) -> String {
90 | format!("{}", self.0)
91 | }
92 |
93 | /// See `From for u64`
94 | ///
95 | /// ```js
96 | /// let two = new lambda.Exp("\\f.\\x.(f (f x))");
97 | /// console.log(`${two.toNumber()}`);
98 | /// ```
99 | #[wasm_bindgen(method, js_name = toNumber)]
100 | pub fn to_number(&self) -> usize {
101 | u64::from(self.0.clone()) as usize
102 | }
103 |
104 | /// See `From for bool`
105 | ///
106 | ///
107 | /// ```js
108 | /// let t = new lambda.Exp("\\a.\\b.a");
109 | /// console.log(`${t.toBool()}`);
110 | /// ```
111 | #[wasm_bindgen(method, js_name = toBool)]
112 | pub fn to_bool(&self) -> bool {
113 | self.0.clone().into()
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/encode/numerals.rs:
--------------------------------------------------------------------------------
1 | use std::ops::{Add, Mul};
2 | use crate::{Expression, Abstraction, Application, Variable};
3 | use crate::normal::Strategy;
4 |
5 | /// Church encoded natural numbers
6 | ///
7 | /// ```
8 | /// # #![feature(box_syntax)]
9 | /// # #[macro_use]
10 | /// # extern crate lalrpop_lambda;
11 | /// use lalrpop_lambda::Expression;
12 | ///
13 | /// # fn main() {
14 | /// assert_eq!(λ!{f.λ!{x.x}}, Expression::from(0));
15 | /// assert_eq!(λ!{f.λ!{x.γ!(f,x)}}, Expression::from(1));
16 | /// assert_eq!(λ!{f.λ!{x.γ!(f,γ!(f,γ!(f,x)))}}, Expression::from(3));
17 | /// # }
18 | /// ```
19 | impl From for Expression {
20 | fn from(n: u64) -> Self {
21 | let succ = λ!{n.λ!{f.λ!{x.γ!(f, γ!(γ!(n, f), x))}}};
22 | let mut e = λ!{f.λ!{x.x}};
23 | for _ in 0..n {
24 | e = app!({&succ}, {&e}).normalize(&Strategy::Applicative(false));
25 | }
26 | e
27 | }
28 | }
29 |
30 | /// Convert λ term back to native Rust type
31 | ///
32 | /// ```
33 | /// # #![feature(box_syntax)]
34 | /// # #[macro_use]
35 | /// # extern crate lalrpop_lambda;
36 | /// # fn main() {
37 | /// assert_eq!(0, u64::from(λ!{f.λ!{x.x}}));
38 | /// assert_eq!(1, u64::from(λ!{f.λ!{x.γ!(f,x)}}));
39 | /// assert_eq!(3, u64::from(λ!{f.λ!{x.γ!(f,γ!(f,γ!(f,x)))}}));
40 | /// # }
41 | /// ```
42 | impl From for u64 {
43 | fn from(e: Expression) -> u64 {
44 | // TODO: It would be ideal to use the Fn conversion and a way to "bind" `f` to u64::add.
45 | //
46 | // XXX: In fact more than ideal, this really should only be able to return an `Option`
47 | // since there are lambda terms which can evaluate to something which is not a chruch
48 | // encoded function.
49 | match e.normalize(&Strategy::Applicative(true)) {
50 | Expression::Var(id) => {
51 | if id == variable!(f) { 1 } else { 0 }
52 | },
53 | Expression::Abs(Abstraction(Variable(_id, _ty), box body)) => {
54 | u64::from(body)
55 | },
56 | Expression::App(Application(box e1, box e2)) => {
57 | u64::from(e1) + u64::from(e2)
58 | },
59 | }
60 | }
61 | }
62 |
63 | /// ```
64 | /// # #![feature(box_syntax)]
65 | /// # #[macro_use]
66 | /// # extern crate lalrpop_lambda;
67 | /// # fn main() {
68 | /// let one = λ!{f.λ!{x.γ!(f,x)}};
69 | /// let two = one.clone() + one.clone();
70 | /// assert_eq!(2, u64::from(two.clone()));
71 | /// assert_eq!(4, u64::from(two.clone() + two.clone()));
72 | /// # }
73 | /// ```
74 | impl Add for Expression {
75 | type Output = Self;
76 |
77 | fn add(self, other: Self) -> Self {
78 | let add = λ!{m.λ!{n.λ!{f.λ!{x.γ!(γ!(m,f),γ!(γ!(n,f),x))}}}};
79 | γ!(γ!({add},{self}),{other}).normalize(&Strategy::Applicative(false))
80 | }
81 | }
82 |
83 | /// ```
84 | /// # #![feature(box_syntax)]
85 | /// # #[macro_use]
86 | /// # extern crate lalrpop_lambda;
87 | /// # fn main() {
88 | /// let one = λ!{f.λ!{x.γ!(f,x)}};
89 | /// let two = one.clone() + one.clone();
90 | /// assert_eq!(1, u64::from(one.clone() * one.clone()));
91 | /// assert_eq!(4, u64::from(two.clone() * two.clone()));
92 | /// # }
93 | /// ```
94 | impl Mul for Expression {
95 | type Output = Self;
96 |
97 | fn mul(self, other: Self) -> Self {
98 | let mul = λ!{m.λ!{n.λ!{f.λ!{x.γ!(γ!(m,γ!(n,f)),x)}}}};
99 | γ!(γ!({mul},{self}),{other}).normalize(&Strategy::Applicative(false))
100 | }
101 | }
102 |
103 |
104 | #[cfg(test)]
105 | mod tests {
106 | use pretty_assertions::assert_eq;
107 | use crate::parse::ExpressionParser;
108 | use super::*;
109 |
110 | // // TODO: Move these to tests as we finalize.
111 | // dbg!(u64::from(var!(x)));
112 | // dbg!(u64::from(var!(f)));
113 | // dbg!(u64::from(app!(f,app!(f,x))));
114 | // dbg!(u64::from(abs!{f.app!(f,app!(f,x))}));
115 | // dbg!(u64::from(abs!{f.abs!{x.app!(f,app!(f,x))}}));
116 |
117 | #[test]
118 | fn u64() {
119 | assert_eq!(0u64, Expression::from(0).into());
120 | assert_eq!(5u64, Expression::from(5).into());
121 | }
122 |
123 | #[test]
124 | fn zero() {
125 | // TODO: Should this be correct? What to do about smaller terms?
126 | assert_eq!(0, u64::from(λ!{x.x}));
127 | }
128 |
129 |
130 | #[test]
131 | fn one() {
132 | let ω = ExpressionParser::new().parse("λx.x x").unwrap();
133 |
134 | // TODO: Should this be correct? What to do about smaller terms?
135 | assert_eq!(1, u64::from(ω(Expression::from(1))));
136 | }
137 |
138 | #[test]
139 | fn add() {
140 | assert_eq!(Expression::from(5), Expression::from(2) +
141 | Expression::from(3));
142 | }
143 |
144 | #[test]
145 | fn multiply() {
146 | assert_eq!(Expression::from(6), Expression::from(2) * Expression::from(3));
147 | }
148 |
149 | // app!(n, (\f.\x.(f (f x)))) -> 2^n
150 | }
151 |
--------------------------------------------------------------------------------
/src/macros.rs:
--------------------------------------------------------------------------------
1 | /// A raw `Variable`
2 | ///
3 | /// ```
4 | /// # #[macro_use]
5 | /// # extern crate lalrpop_lambda;
6 | /// # fn main() {
7 | /// let x = variable!(x);
8 | /// # }
9 | /// ```
10 | #[macro_export]
11 | macro_rules! variable {
12 | ($b:ident) => {{
13 | $crate::Variable(stringify!($b).into(), None)
14 | }};
15 | ($b:expr) => {{
16 | $crate::Variable($b.into(), None)
17 | }};
18 | ($b:ident, $ty:ident) => {{
19 | $crate::Variable(stringify!($b).into(), Some(stringify!($ty).into()))
20 | }};
21 | ($b:expr, $ty:ident) => {{
22 | $crate::Variable($b.into(), Some(stringify!($ty).into()))
23 | }};
24 | }
25 |
26 | /// A variable (`Var`) expression
27 | #[macro_export]
28 | macro_rules! var {
29 | ($b:ident) => {{
30 | $crate::Expression::Var(variable!($b))
31 | }};
32 | ($b:expr) => {{
33 | $crate::Expression::Var(variable!($b))
34 | }};
35 | }
36 |
37 | /// An abstraction (`Abs`) expression
38 | #[macro_export]
39 | macro_rules! abs {
40 | {. $body:ident} => {{
41 | $crate::Expression::build_abs(1, vec![], Some(var!($body)))
42 | }};
43 | {. $body:expr} => {{
44 | $crate::Expression::build_abs(1, vec![], Some($body.into()))
45 | }};
46 | {$($arg:ident : $ty:ident)* . $body:ident} => {{
47 | let mut ids: Vec<$crate::Variable> = Vec::new();
48 | $(ids.push(variable!($arg, $ty));)*
49 | $crate::Expression::build_abs(1, ids, Some(var!($body)))
50 | }};
51 | {$($arg:ident)* . $body:ident} => {{
52 | let mut ids: Vec<$crate::Variable> = Vec::new();
53 | $(ids.push(variable!($arg));)*
54 | $crate::Expression::build_abs(1, ids, Some(var!($body)))
55 | }};
56 | {$($arg:ident : $ty:ident)* . $body:expr} => {{
57 | let mut ids: Vec<$crate::Variable> = Vec::new();
58 | $(ids.push(variable!($arg, $ty));)*
59 | $crate::Expression::build_abs(1, ids, Some($body.into()))
60 | }};
61 | {$($arg:ident)* . $body:expr} => {{
62 | let mut ids: Vec<$crate::Variable> = Vec::new();
63 | $(ids.push(variable!($arg));)*
64 | $crate::Expression::build_abs(1, ids, Some($body.into()))
65 | }};
66 | }
67 |
68 | /// An application (`App`) expression
69 | #[macro_export]
70 | macro_rules! app {
71 | ($func:ident, $arg:ident) => {{
72 | $crate::Expression::App($crate::Application(
73 | Box::new(var!($func)),
74 | Box::new(var!($arg)),
75 | ))
76 | }};
77 | ($func:ident, $arg:expr) => {{
78 | $crate::Expression::App($crate::Application(
79 | Box::new(var!($func)),
80 | Box::new($arg.clone().into()),
81 | ))
82 | }};
83 | ($func:expr, $arg:ident) => {{
84 | $crate::Expression::App($crate::Application(
85 | Box::new($func.clone().into()),
86 | Box::new(var!($arg)),
87 | ))
88 | }};
89 | ($func:expr, $arg:expr) => {{
90 | $crate::Expression::App($crate::Application(
91 | Box::new($func.clone().into()),
92 | Box::new($arg.clone().into()),
93 | ))
94 | }};
95 | }
96 |
97 | /// The all-powerful λ
98 | ///
99 | /// ```
100 | /// # #![feature(box_syntax)]
101 | /// # #[macro_use]
102 | /// # extern crate lalrpop_lambda;
103 | /// # fn main() {
104 | /// let id = λ!{x.x};
105 | /// # }
106 | /// ```
107 | ///
108 | /// Just a shortcut for `abs!`.
109 | #[macro_export]
110 | macro_rules! λ {
111 | {. $body:ident} => {
112 | abs!($body)
113 | };
114 | {. $body:expr} => {
115 | abs!($body)
116 | };
117 | {$($arg:ident)* : $ty:ident . $body:ident} => {
118 | abs!($($arg)* . $body)
119 | };
120 | {$($arg:ident)* . $body:ident} => {
121 | abs!($($arg)* . $body)
122 | };
123 | {$($arg:ident)* : $ty:ident . $body:expr} => {{
124 | abs!($($arg)* . $body)
125 | }};
126 | {$($arg:ident)* . $body:expr} => {{
127 | abs!($($arg)* . $body)
128 | }};
129 | }
130 |
131 | /// Theory is nothing without application
132 | ///
133 | /// This is a more terse form of `app!`. The main difference between these macros is that this
134 | /// macro wraps it's parts in `var!` expressions as needed. Whereas with `app!` we can use the
135 | /// Rust bindings to compose a new expression. Together they allow us to write:
136 | ///
137 | /// ```
138 | /// # #![feature(box_syntax)]
139 | /// # #[macro_use]
140 | /// # extern crate lalrpop_lambda;
141 | /// # fn main() {
142 | /// let one = λ!{f.λ!{x.γ!(f, x)}};
143 | /// let succ = λ!{n.λ!{f.λ!{x.γ!(f, γ!(n, γ!(f, x)))}}};
144 | /// app!(succ, one);
145 | /// # }
146 | /// ```
147 | #[macro_export]
148 | macro_rules! γ {
149 | ($func:ident, $arg:ident) => {
150 | app!(var!($func), var!($arg))
151 | };
152 | ($func:ident, $arg:expr) => {
153 | app!(var!($func), $arg)
154 | };
155 | ($func:expr, $arg:ident) => {
156 | app!($func, var!($arg))
157 | };
158 | ($func:expr, $arg:expr) => {
159 | app!($func, $arg)
160 | };
161 | }
162 |
163 | /// A `HashSet` macro like `map!`
164 | macro_rules! set {
165 | (@single $($x:tt)*) => (());
166 | (@count $($rest:expr),*) => (<[()]>::len(&[$(set!(@single $rest)),*]));
167 |
168 | ($($key:expr,)+) => {
169 | set!($($key),+)
170 | };
171 |
172 | ($($key:expr),*) => {
173 | {
174 | let _cap = set!(@count $($key),*);
175 | let mut _set = ::std::collections::HashSet::with_capacity(_cap);
176 | $(
177 | let _ = _set.insert($key);
178 | )*
179 | _set
180 | }
181 | };
182 | }
183 |
184 | // A `HashMap` macro like `vec!`
185 | #[cfg(test)]
186 | macro_rules! map {
187 | ($($key:expr => $value:expr,)+) => {
188 | map!($($key => $value),+)
189 | };
190 |
191 | ($($key:expr => $value:expr),*) => {
192 | {
193 | let mut _map = ::std::collections::HashMap::new();
194 | $(
195 | let _ = _map.insert($key, $value);
196 | )*
197 | _map
198 | }
199 | };
200 | }
201 |
--------------------------------------------------------------------------------
/src/encode/boolean.rs:
--------------------------------------------------------------------------------
1 | use std::ops::{Not, BitAnd, BitOr, BitXor};
2 | use crate::{Expression, Abstraction};
3 | use crate::normal::Strategy;
4 |
5 | /// Church encoded booleans
6 | ///
7 | /// ```
8 | /// # #![feature(box_syntax)]
9 | /// # #[macro_use]
10 | /// # extern crate lalrpop_lambda;
11 | /// use lalrpop_lambda::Expression;
12 | ///
13 | /// # fn main() {
14 | /// assert_eq!(λ!{a.λ!{b.a}}, Expression::from(true));
15 | /// assert_eq!(λ!{a.λ!{b.b}}, Expression::from(false));
16 | /// # }
17 | /// ```
18 | impl From for Expression {
19 | fn from(p: bool) -> Self {
20 | if p { λ!{a.λ!{b.a}} } else { λ!{a.λ!{b.b}} }
21 | }
22 | }
23 |
24 | /// Convert λ term back to native Rust type
25 | ///
26 | /// ```
27 | /// # #![feature(box_syntax)]
28 | /// # #[macro_use]
29 | /// # extern crate lalrpop_lambda;
30 | /// # fn main() {
31 | /// assert_eq!(true , bool::from(λ!{a.λ!{b.a}}));
32 | /// assert_eq!(false, bool::from(λ!{a.λ!{b.γ!(b,b)}}));
33 | /// # }
34 | /// ```
35 | impl From for bool {
36 | fn from(e: Expression) -> bool {
37 | let s = Strategy::Applicative(true);
38 | if let Expression::Abs(Abstraction(a, box e1)) = e.normalize(&s) {
39 | if let Expression::Abs(Abstraction(_, box e2)) = e1 {
40 | if let Expression::Var(p) = e2 {
41 | return p == a
42 | }
43 | }
44 | }
45 |
46 | // Dirty hack, this should be an Option!
47 | false
48 | }
49 | }
50 |
51 | /// ```
52 | /// # #![feature(box_syntax)]
53 | /// # #[macro_use]
54 | /// # extern crate lalrpop_lambda;
55 | /// # fn main() {
56 | /// let t = λ!{a.λ!{b.a}};
57 | ///
58 | /// assert_eq!(false, bool::from(!t.clone()));
59 | /// assert_eq!(true, bool::from(!!t.clone()));
60 | /// # }
61 | /// ```
62 | ///
63 | /// # Evaluation Strategy
64 | ///
65 | /// Note that there are two version of not, depending on the evaluation
66 | /// strategy that is chosen. We _currently_ only evaluate using application
67 | /// order, so we choose the first option.
68 | ///
69 | /// - Applicative evaluation order: λp.λa.λb.p b a
70 | /// - Normal evaluation order: λp.p (λa.λb.b) (λa.λb.a)
71 | impl Not for Expression {
72 | type Output = Self;
73 |
74 | fn not(self) -> Self {
75 | let not_app = λ!{p.λ!{a.λ!{b.γ!(γ!(p,b),a)}}};
76 | γ!({not_app},{self}).normalize(&Strategy::Applicative(true))
77 | }
78 | }
79 |
80 | /// ```
81 | /// # #![feature(box_syntax)]
82 | /// # #[macro_use]
83 | /// # extern crate lalrpop_lambda;
84 | /// # fn main() {
85 | /// let t = λ!{a.λ!{b.a}};
86 | /// let f = λ!{a.λ!{b.b}};
87 | ///
88 | /// assert_eq!(true, bool::from(t.clone() | t.clone()));
89 | /// assert_eq!(true, bool::from(t.clone() | f.clone()));
90 | /// assert_eq!(true, bool::from(f.clone() | t.clone()));
91 | /// assert_eq!(false, bool::from(f.clone() | f.clone()));
92 | /// # }
93 | /// ```
94 | impl BitOr for Expression {
95 | type Output = Self;
96 |
97 | fn bitor(self, other: Self) -> Self {
98 | let or = λ!{p.λ!{q.γ!(γ!(p,p),q)}};
99 | γ!(γ!({or},{self}),{other}).normalize(&Strategy::Applicative(false))
100 | }
101 | }
102 |
103 | /// ```
104 | /// # #![feature(box_syntax)]
105 | /// # #[macro_use]
106 | /// # extern crate lalrpop_lambda;
107 | /// # fn main() {
108 | /// let t = λ!{a.λ!{b.a}};
109 | /// let f = λ!{a.λ!{b.b}};
110 | ///
111 | /// assert_eq!(true, bool::from(t.clone() & t.clone()));
112 | /// assert_eq!(false, bool::from(t.clone() & f.clone()));
113 | /// assert_eq!(false, bool::from(f.clone() & t.clone()));
114 | /// assert_eq!(false, bool::from(f.clone() & f.clone()));
115 | /// # }
116 | /// ```
117 | impl BitAnd for Expression {
118 | type Output = Self;
119 |
120 | fn bitand(self, other: Self) -> Self {
121 | let and = λ!{p.λ!{q.γ!(γ!(p,q),p)}};
122 | γ!(γ!({and},{self}),{other}).normalize(&Strategy::Applicative(false))
123 | }
124 | }
125 |
126 | /// ```
127 | /// # #![feature(box_syntax)]
128 | /// # #[macro_use]
129 | /// # extern crate lalrpop_lambda;
130 | /// # fn main() {
131 | /// let t = λ!{a.λ!{b.a}};
132 | /// let f = λ!{a.λ!{b.b}};
133 | ///
134 | /// assert_eq!(false, bool::from(t.clone() ^ t.clone()));
135 | /// assert_eq!(true, bool::from(t.clone() ^ f.clone()));
136 | /// assert_eq!(true, bool::from(f.clone() ^ t.clone()));
137 | /// assert_eq!(false, bool::from(f.clone() ^ f.clone()));
138 | /// # }
139 | /// ```
140 | impl BitXor for Expression {
141 | type Output = Self;
142 |
143 | // TODO: This is proving we need α-renaming.
144 | fn bitxor(self, other: Self) -> Self {
145 | let not_app = λ!{p.λ!{a.λ!{b.γ!(γ!(p,b),a)}}};
146 | let xor = λ!{p.λ!{q.γ!(γ!(p,γ!({not_app},q)),q)}};
147 | γ!(γ!({xor},{self}),{other}).normalize(&Strategy::Applicative(false))
148 | }
149 | }
150 |
151 |
152 |
153 | #[cfg(test)]
154 | mod tests {
155 | use pretty_assertions::assert_eq;
156 | use super::*;
157 |
158 | #[test]
159 | fn true_() {
160 | assert_eq!(true, Expression::from(true).into());
161 | }
162 |
163 | #[test]
164 | fn false_() {
165 | assert_eq!(false, Expression::from(false).into());
166 | }
167 |
168 | #[test]
169 | fn not() {
170 | assert_eq!(false, (!Expression::from(true)).into());
171 | }
172 |
173 | #[test]
174 | fn or() {
175 | assert_eq!(Expression::from(true), Expression::from(true) |
176 | Expression::from(true));
177 | assert_eq!(Expression::from(true), Expression::from(false) |
178 | Expression::from(true));
179 | assert_eq!(Expression::from(true), Expression::from(true) |
180 | Expression::from(false));
181 | assert_eq!(Expression::from(false), Expression::from(false) |
182 | Expression::from(false));
183 | }
184 |
185 | #[test]
186 | fn and() {
187 | assert_eq!(Expression::from(true), Expression::from(true) &
188 | Expression::from(true));
189 | assert_eq!(Expression::from(false), Expression::from(false) &
190 | Expression::from(true));
191 | assert_eq!(Expression::from(false), Expression::from(true) &
192 | Expression::from(false));
193 | assert_eq!(Expression::from(false), Expression::from(false) &
194 | Expression::from(false));
195 | }
196 |
197 | #[test]
198 | fn xor() {
199 | assert_eq!(Expression::from(false), Expression::from(true) ^
200 | Expression::from(true));
201 | assert_eq!(Expression::from(true), Expression::from(false) ^
202 | Expression::from(true));
203 | assert_eq!(Expression::from(true), Expression::from(true) ^
204 | Expression::from(false));
205 | assert_eq!(Expression::from(false), Expression::from(false) ^
206 | Expression::from(false));
207 | }
208 | }
209 |
--------------------------------------------------------------------------------
/src/lib.rs:
--------------------------------------------------------------------------------
1 | //! This project started as just the parse.lalrpop and AST, but grew into a bit
2 | //! more.
3 | //!
4 | //! Evaluation of λ-expressions is _currently_ done in a single big-step
5 | //! semantics [`Expression::normalize`] function. The reduction strategy is
6 | //! so far only configurable by η.
7 | //!
8 | //! See the `impl From` items under [`Expression`]. These define conversions
9 | //! between Rust and λ-expressions. These are all defined in `mod encode`.
10 | //!
11 | //! ```
12 | //! #![feature(box_syntax)]
13 | //!
14 | //! #[macro_use]
15 | //! extern crate lalrpop_lambda;
16 | //!
17 | //! use lalrpop_lambda::Strategy;
18 | //!
19 | //! fn main() {
20 | //! use lalrpop_lambda::Expression;
21 | //! use lalrpop_lambda::parse::ExpressionParser;
22 | //!
23 | //! // Define an expression parser, for shortest lambda term strings.
24 | //! let parser = ExpressionParser::new();
25 | //!
26 | //! // The successor Church numeral function.
27 | //! let add1 = parser.parse("λn.λf.λx.f (n f x)").unwrap();
28 | //!
29 | //! // The first two church numerals.
30 | //! let zero = Expression::from(0u64);
31 | //! let one = app!({add1},{zero})
32 | //! .normalize(&Strategy::Applicative(false));
33 | //! assert_eq!(Expression::from(1u64), one);
34 | //!
35 | //! // Use a parsed identity function with other `Experssion`s.
36 | //! let id = parser.parse("λx.x").unwrap();
37 | //! let id_one = id(Expression::from(1u64))
38 | //! .normalize(&Strategy::Applicative(false));
39 | //! assert_eq!(one, id_one);
40 | //! }
41 | //! ```
42 | #![feature(non_ascii_idents, box_patterns, fn_traits, unboxed_closures)]
43 |
44 | #[macro_use]
45 | extern crate lalrpop_util;
46 |
47 | #[cfg(feature = "wasm")]
48 | extern crate wasm_bindgen;
49 |
50 | #[cfg(test)]
51 | extern crate pretty_assertions;
52 |
53 | use std::collections::{HashMap, HashSet};
54 | use std::fmt;
55 |
56 | #[cfg(feature = "wasm")]
57 | pub mod wasm;
58 |
59 | // TODO: Polish and test.
60 | mod normal;
61 | pub use self::normal::Strategy;
62 |
63 | // The wonderful and easy to use `λ` and `abs!` macros.
64 | //
65 | // As well as an implementation of `set!` and `map!` taken from:
66 | // [bluss/maplit](https://github.com/bluss/maplit).
67 | #[macro_use]
68 | mod macros;
69 |
70 | // Church encoded λ-calculus data types, and conversions to Rust data types
71 | mod encode;
72 |
73 | /// A mutually recursive definition for all lambda expressions
74 | ///
75 | /// ```
76 | /// let parser = lalrpop_lambda::parse::ExpressionParser::new();
77 | ///
78 | /// assert!(parser.parse("λx.(x x)").is_ok());
79 | /// ```
80 | #[derive(Clone, PartialEq, Eq)]
81 | pub enum Expression {
82 | Var(Variable),
83 | Abs(Abstraction),
84 | App(Application),
85 | }
86 |
87 | /// A potentially free variable
88 | ///
89 | /// ```
90 | /// let parser = lalrpop_lambda::parse::ExpressionParser::new();
91 | ///
92 | /// assert!(parser.parse("x").is_ok());
93 | /// ```
94 | #[derive(Clone, Hash, PartialEq, Eq)]
95 | pub struct Variable(pub String, pub Option);
96 |
97 | /// An abstraction over a bound variable
98 | ///
99 | /// ```
100 | /// let parser = lalrpop_lambda::parse::ExpressionParser::new();
101 | ///
102 | /// assert!(parser.parse("λx.x").is_ok());
103 | /// ```
104 | #[derive(Clone, PartialEq, Eq)]
105 | pub struct Abstraction(pub Variable, pub Box);
106 |
107 | /// An application of two expressions
108 | ///
109 | /// ```
110 | /// let parser = lalrpop_lambda::parse::ExpressionParser::new();
111 | ///
112 | /// assert!(parser.parse("a b").is_ok());
113 | /// ```
114 | #[derive(Clone, PartialEq, Eq)]
115 | pub struct Application(pub Box, pub Box);
116 |
117 | impl Expression {
118 | /// α-conversion
119 | pub fn rename(&self, old: &Variable, new: &Variable) -> Self {
120 | dbg!(old, new);
121 | unimplemented!()
122 | }
123 |
124 | pub fn variables(&self) -> HashSet {
125 | match self {
126 | Expression::Var(v) => set! { v.clone() },
127 | Expression::Abs(Abstraction(id, body)) => body
128 | .variables()
129 | .union(&set! { id.clone() })
130 | .cloned()
131 | .collect(),
132 | Expression::App(Application(e1, e2)) => {
133 | e1.variables().union(&e2.variables()).cloned().collect()
134 | }
135 | }
136 | }
137 |
138 | /// FV(M) is the set of variables in M, not closed by a λ term.
139 | ///
140 | /// ```
141 | /// use std::collections::HashSet;
142 | /// use lalrpop_lambda::Variable;
143 | ///
144 | /// let parser = lalrpop_lambda::parse::ExpressionParser::new();
145 | ///
146 | /// let mut free = HashSet::new();
147 | /// free.insert(Variable("y".into(), None));
148 | ///
149 | /// let expression = parser.parse("λx.(x y)").unwrap();
150 | ///
151 | /// assert_eq!(free, expression.free_variables());
152 | /// ```
153 | pub fn free_variables(&self) -> HashSet {
154 | match self {
155 | // FV(x) = { x }, where x is a variable.
156 | Expression::Var(id) => set! { id.clone() },
157 | // FV(λx.M) = FV(M) \ { x }.
158 | Expression::Abs(Abstraction(id, body)) => body
159 | .free_variables()
160 | .difference(&set! { id.clone() })
161 | .cloned()
162 | .collect(),
163 | // FV(M N) = FV(M) ∪ FV(N).
164 | Expression::App(Application(e1, e2)) => e1
165 | .free_variables()
166 | .union(&e2.free_variables())
167 | .cloned()
168 | .collect(),
169 | }
170 | }
171 |
172 | /// ```
173 | /// # #![feature(box_syntax)]
174 | /// # #[macro_use]
175 | /// # extern crate lalrpop_lambda;
176 | /// use std::collections::HashMap;
177 | ///
178 | /// # fn main() {
179 | /// let mut env = HashMap::new();
180 | /// env.insert(variable!(id), abs!{x.x});
181 | /// env.insert(variable!(ad), abs!{x.y});
182 | /// env.insert(variable!(x), 1.into());
183 | ///
184 | /// assert_eq!(var!(q), var!(q).resolve(&env));
185 | /// assert_eq!(1u64, var!(x).resolve(&env).into());
186 | ///
187 | /// // Works with functions too!
188 | /// let id: fn(u64) -> u64 = var!(id).resolve(&env).into();
189 | /// assert_eq!(1, id(1));
190 | /// let ad: fn(u64) -> u64 = var!(ad).resolve(&env).into();
191 | /// assert_eq!(u64::from(var!(y)), ad(0));
192 | /// assert_eq!(u64::from(var!(y)), ad(1));
193 | /// # }
194 | /// ```
195 | pub fn resolve(&self, env: &HashMap) -> Expression {
196 | match self {
197 | Expression::Var(id) => {
198 | if let Some(e) = env.get(id) {
199 | e.clone()
200 | } else {
201 | self.clone()
202 | }
203 | }
204 | Expression::Abs(Abstraction(id, box body)) => {
205 | // TODO: Check FV
206 | Expression::Abs(Abstraction(id.clone(), Box::new(body.resolve(env))))
207 | }
208 | Expression::App(Application(box e1, box e2)) => {
209 | app!({ e1.resolve(env) }, { e2.resolve(env) })
210 | }
211 | }
212 | }
213 | }
214 |
215 | impl Expression {
216 | pub fn build_abs(lambs: usize, ids: Vec, body: Option) -> Self {
217 | // TODO: Make the body an Option too.
218 | let mut abs = body.unwrap_or(var!(""));
219 |
220 | let id_count = ids.len();
221 | // Curry multi args.
222 | for i in ids.into_iter().rev() {
223 | abs = Expression::Abs(Abstraction(i, Box::new(abs)));
224 | }
225 |
226 | // Wrap in as many extra lambdas as requested.
227 | for l in 0..lambs {
228 | // Skip the first lambda if given any ids, since the id will have
229 | // already generated above.
230 | if l == 0 && id_count > 0 {
231 | continue;
232 | }
233 | abs = Expression::Abs(Abstraction(variable!(""), Box::new(abs)));
234 | }
235 |
236 | abs
237 | }
238 | }
239 |
240 | impl fmt::Debug for Expression {
241 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
242 | match self {
243 | Expression::Var(id) => {
244 | write!(f, "{:?}", id)
245 | }
246 | Expression::Abs(Abstraction(id, body)) => {
247 | write!(f, "(λ{:?}.{:?})", id, body)
248 | }
249 | Expression::App(Application(box e1, box e2)) => {
250 | write!(f, "({:?} {:?})", e1, e2)
251 | }
252 | }
253 | }
254 | }
255 |
256 | impl fmt::Debug for Variable {
257 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
258 | if let Some(ty) = &self.1 {
259 | write!(f, "{}:{}", self.0, ty)
260 | } else {
261 | write!(f, "{}", self.0)
262 | }
263 | }
264 | }
265 |
266 | impl fmt::Display for Expression {
267 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268 | write!(f, "{:?}", self)
269 | }
270 | }
271 |
272 | impl fmt::Display for Variable {
273 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
274 | write!(f, "{:?}", self)
275 | }
276 | }
277 |
278 | lalrpop_mod! {
279 | /// Parse λ-expressions
280 | pub parse
281 | }
282 |
283 | #[cfg(test)]
284 | mod tests {
285 | use super::*;
286 | use crate::parse::ExpressionParser;
287 | use pretty_assertions::assert_eq;
288 |
289 | #[test]
290 | fn variable() {
291 | assert!(ExpressionParser::new().parse(r"x").is_ok());
292 | }
293 |
294 | #[test]
295 | fn abstraction() {
296 | assert!(ExpressionParser::new().parse(r"\x.x").is_ok());
297 | assert!(ExpressionParser::new().parse(r"\x. x").is_ok());
298 | assert!(ExpressionParser::new().parse(r"\x.(x)").is_ok());
299 | assert!(ExpressionParser::new().parse(r"\x. (x)").is_ok());
300 | }
301 |
302 | #[test]
303 | fn application() {
304 | assert!(ExpressionParser::new().parse(r"x x").is_ok());
305 | assert!(ExpressionParser::new().parse(r"(x y)").is_ok());
306 | assert!(ExpressionParser::new().parse(r"(\x.x y)").is_ok());
307 | }
308 |
309 | #[test]
310 | #[ignore]
311 | fn rename() {}
312 |
313 | #[test]
314 | #[ignore]
315 | fn variables() {}
316 |
317 | #[test]
318 | fn free_variables() {
319 | let parser = ExpressionParser::new();
320 |
321 | assert_eq!(
322 | set! { variable!(x) },
323 | parser.parse(r"x").unwrap().free_variables()
324 | );
325 | assert_eq!(set! {}, parser.parse(r"λx.x").unwrap().free_variables());
326 | assert_eq!(
327 | set! { variable!(f), variable!(x) },
328 | parser.parse(r"f x").unwrap().free_variables()
329 | );
330 | assert_eq!(
331 | set! { variable!(x), variable!(y) },
332 | parser
333 | .parse(r"(λx.(x y)) (λy.(x y))")
334 | .unwrap()
335 | .free_variables()
336 | );
337 | }
338 |
339 | #[test]
340 | fn resolve() {
341 | let env = map! {
342 | variable!(n) => 1.into(),
343 | };
344 |
345 | assert_eq!(var!(q), var!(q).resolve(&env));
346 | assert_eq!(1u64, var!(n).resolve(&env).into());
347 |
348 | // TODO: Add more, starting with examples/env.rs.
349 | }
350 | }
351 |
--------------------------------------------------------------------------------
/src/normal.rs:
--------------------------------------------------------------------------------
1 | use crate::{Abstraction, Application, Expression, Variable};
2 |
3 | /// A reduction strategy for an [`Expression`]
4 | pub enum Strategy {
5 | // Innermost reductions
6 |
7 | // *ao* -> normal
8 | Applicative(bool),
9 | // *bv*: not inside abstractions -> weak normal
10 | CallByValue,
11 | // ha: ao + bv -> normal
12 | HybridApplicative,
13 |
14 | // Outermost reductions
15 |
16 | // *bn*: not inside abstractions -> weak head normal
17 | CallByName,
18 | // no: bn -> normal
19 | Normal(bool),
20 | // *he*: abstractions reduced only in head position -> head normal
21 | HeadSpine(bool),
22 | // hn: no + he -> normal
23 | HybridNormal,
24 | }
25 |
26 | impl Expression {
27 | /// β-reduction small-step semantics (→)
28 | ///
29 | /// Represents local reducibility in natural deduction.
30 | ///
31 | /// - η: λx.(e1 x) -> e1 whenever x does not appear free in e1
32 | ///
33 | /// Represents local completeness in natural deduction.
34 | pub fn apply(&self, η: bool) -> Self {
35 | dbg!(η);
36 | unimplemented!()
37 | }
38 |
39 | /// Big-step natural semantics (⇓)
40 | ///
41 | /// Represents global reducibility in natural deduction.
42 | ///
43 | /// TODO: Reduction strategy.
44 | ///
45 | /// - η: (see `Expression::apply`)
46 | ///
47 | /// ```
48 | /// use lalrpop_lambda::Strategy;
49 | /// use lalrpop_lambda::parse::ExpressionParser;
50 | ///
51 | /// let parser = ExpressionParser::new();
52 | /// let expression = parser.parse("((λx.(λy.x y) b) a)").unwrap();
53 | /// let normal = parser.parse("a b").unwrap();
54 | ///
55 | /// assert_eq!(normal, expression.normalize(&Strategy::Applicative(true)));
56 | /// assert_eq!(normal, expression.normalize(&Strategy::HeadSpine(false)));
57 | /// ```
58 | pub fn normalize(&self, strategy: &Strategy) -> Self {
59 | match *strategy {
60 | Strategy::CallByName => self.bn(),
61 | Strategy::Normal(η) => self.no(η),
62 | Strategy::CallByValue => self.bv(),
63 | Strategy::Applicative(η) => self.ao(η),
64 | Strategy::HeadSpine(η) => self.hs(η),
65 | _ => unimplemented!(),
66 | }
67 | }
68 |
69 | fn bn(&self) -> Self {
70 | match self {
71 | Expression::App(Application(box e1, box e2)) => match e1.bn() {
72 | Expression::Abs(Abstraction(id, body)) => body.substitute(&e2, &id).bn(),
73 | e @ _ => Expression::App(Application(Box::new(e), Box::new(e2.clone()))),
74 | },
75 | _ => self.clone(),
76 | }
77 | }
78 |
79 | fn no(&self, η: bool) -> Self {
80 | match self {
81 | Expression::Var(_) => self.clone(),
82 | Expression::Abs(Abstraction(id, box body)) => {
83 | // η-reduction
84 | if let Expression::App(Application(box e1, box Expression::Var(x))) = body {
85 | if η && id == x && !e1.free_variables().contains(&id) {
86 | return e1.no(η);
87 | }
88 | }
89 |
90 | Expression::Abs(Abstraction(id.clone(), Box::new(body.no(η))))
91 | }
92 | Expression::App(Application(box e1, box e2)) => match e1.bn() {
93 | Expression::Abs(Abstraction(id, body)) => body.substitute(&e2, &id).no(η),
94 | e @ _ => Expression::App(Application(Box::new(e.no(η)), Box::new(e2.no(η)))),
95 | },
96 | }
97 | }
98 |
99 | fn bv(&self) -> Self {
100 | match self {
101 | Expression::App(Application(box e1, box e2)) => match e1.bv() {
102 | Expression::Abs(Abstraction(id, body)) => body.substitute(&e2.bv(), &id),
103 | e @ _ => Expression::App(Application(Box::new(e), Box::new(e2.bv()))),
104 | },
105 | _ => self.clone(),
106 | }
107 | }
108 |
109 | fn ao(&self, η: bool) -> Self {
110 | match self {
111 | Expression::Var(_) => self.clone(),
112 | Expression::Abs(Abstraction(id, box body)) => {
113 | // η-reduction
114 | if let Expression::App(Application(box e1, box Expression::Var(x))) = body {
115 | if η && id == x && !e1.free_variables().contains(&id) {
116 | return e1.ao(η);
117 | }
118 | }
119 |
120 | Expression::Abs(Abstraction(id.clone(), Box::new(body.ao(η))))
121 | }
122 | Expression::App(Application(box e1, box e2)) => match e1.ao(η) {
123 | Expression::Abs(Abstraction(id, body)) => body.substitute(&e2.ao(η), &id).ao(η),
124 | e @ _ => Expression::App(Application(Box::new(e), Box::new(e2.ao(η)))),
125 | },
126 | }
127 | }
128 |
129 | fn hs(&self, η: bool) -> Self {
130 | match self {
131 | Expression::Abs(Abstraction(id, box body)) => {
132 | // η-reduction
133 | if let Expression::App(Application(box e1, box Expression::Var(x))) = body {
134 | if η && id == x && !e1.free_variables().contains(&id) {
135 | return e1.hs(η);
136 | }
137 | }
138 |
139 | Expression::Abs(Abstraction(id.clone(), Box::new(body.hs(η))))
140 | }
141 | Expression::App(Application(box e1, box e2)) => match e1.bn() {
142 | Expression::Abs(Abstraction(id, body)) => body.substitute(&e2, &id),
143 | e @ _ => Expression::App(Application(Box::new(e), Box::new(e2.clone()))),
144 | },
145 | _ => self.clone(),
146 | }
147 | }
148 |
149 | /// self[x := v]
150 | fn substitute(&self, v: &Self, x: &Variable) -> Self {
151 | match self {
152 | Expression::Abs(Abstraction(id, box body)) => {
153 | if id == x || !v.free_variables().contains(id) {
154 | Expression::Abs(Abstraction(id.clone(), Box::new(body.substitute(v, x))))
155 | } else {
156 | let fresh = Variable(format!("{}'", id), None);
157 | let body = body.replace(&id, &fresh);
158 | Expression::Abs(Abstraction(fresh, Box::new(body.substitute(v, x))))
159 | }
160 | }
161 | Expression::Var(id) => (if id == x { v } else { self }).clone(),
162 | Expression::App(Application(e1, e2)) => Expression::App(Application(
163 | Box::new(e1.substitute(v, x)),
164 | Box::new(e2.substitute(v, x)),
165 | )),
166 | }
167 | }
168 |
169 | fn replace(&self, old: &Variable, new: &Variable) -> Self {
170 | match self {
171 | Expression::Var(v) => Expression::Var(v.replace(old, new)),
172 | Expression::Abs(Abstraction(id, body)) => Expression::Abs(Abstraction(
173 | id.replace(old, new),
174 | Box::new(body.replace(old, new)),
175 | )),
176 | Expression::App(Application(e1, e2)) => Expression::App(Application(
177 | Box::new(e1.replace(old, new)),
178 | Box::new(e2.replace(old, new)),
179 | )),
180 | }
181 | }
182 | }
183 |
184 | impl Variable {
185 | fn replace(&self, old: &Variable, new: &Variable) -> Self {
186 | if self.0 == old.0 {
187 | Variable(new.0.clone(), new.1.clone())
188 | } else {
189 | self.clone()
190 | }
191 | }
192 | }
193 |
194 | #[cfg(test)]
195 | mod tests {
196 | use super::*;
197 | use crate::{abs, app, var, variable};
198 | use pretty_assertions::assert_eq;
199 |
200 | #[test]
201 | #[ignore]
202 | fn apply() {}
203 |
204 | #[test]
205 | fn normalize() {
206 | let strategy = Strategy::Applicative(false);
207 |
208 | assert_eq!(var!(a), app!(abs! {x.x}, a).normalize(&strategy));
209 |
210 | assert_eq!(
211 | app!(a, a),
212 | app!(abs! {x.app!(abs!{x.app!(x, x)}, a)}, b).normalize(&strategy)
213 | );
214 | assert_eq!(
215 | app!(a, b),
216 | app!(abs! {y.app!(a, y)}, b).normalize(&strategy)
217 | );
218 | assert_eq!(
219 | app!(b, a),
220 | app!(app!(abs! {x.abs!{y.app!(x, y)}}, b), a).normalize(&strategy)
221 | );
222 | assert_eq!(
223 | app!(b, b),
224 | app!(app!(abs! {x.abs!{y.app!(x, y)}}, b), b).normalize(&strategy)
225 | );
226 |
227 | assert_eq!(
228 | abs! {a.a},
229 | app!(abs! {x.x}, abs! {a.a}).normalize(&strategy)
230 | );
231 | println!("{}", app!(abs! {f.abs!{x.app!(f,a)}}, abs! {x.x}));
232 | assert_eq!(
233 | abs! {x.a},
234 | app!(abs! {f.abs!{x.app!(f,a)}}, abs! {x.x}).normalize(&strategy)
235 | );
236 | }
237 |
238 | #[test]
239 | fn normalize_capture_avoid() {
240 | let strategy = Strategy::Applicative(false);
241 |
242 | let expected = Expression::Abs(Abstraction(
243 | variable!("y"),
244 | Box::new(Expression::Abs(Abstraction(
245 | variable!("y'"),
246 | Box::new(Expression::Var(variable!("y"))),
247 | ))),
248 | ));
249 | let actual = abs! {y.app!(abs!{x.abs!{y.x}}, y)};
250 | assert_eq!(expected, actual.normalize(&strategy));
251 |
252 | let expected = abs! {f.abs!{x.app!(var!(f),
253 | Expression::Abs(Abstraction(variable!("x'"),
254 | Box::new(app!(app!(var!(f),
255 | var!(x)),
256 | var!("x'"))))))}};
257 | let actual = app!(
258 | abs! {n.abs!{f.abs!{x.app!(f, app!(n, app!(f, x)))}}},
259 | abs! {f.abs!{x.app!(f, x)}}
260 | );
261 | assert_eq!(expected, actual.normalize(&strategy));
262 |
263 | let expected = Expression::Abs(Abstraction(variable!("x'"), Box::new(var!(x))));
264 | let actual = app!(abs! {f.abs!{x.app!(f,a)}}, abs! {a.x}).normalize(&strategy);
265 | assert_eq!(expected, actual);
266 |
267 | let expected = abs! {f.abs!{x.app!(f,{
268 | let x2 = Expression::Abs(Abstraction(variable!("x''"),
269 | Box::new(var!("x''"))));
270 | let fx = app!(app!(f,x),{x2});
271 | Expression::Abs(Abstraction(variable!("x'"),
272 | Box::new(fx)))
273 | })}};
274 | let actual = app!(
275 | abs! {n.abs!{f.abs!{x.app!(f,app!(n,app!(f,x)))}}},
276 | app!(
277 | abs! {n.abs!{f.abs!{x.app!(f,app!(n,app!(f,x)))}}},
278 | abs! {f.abs!{x.x}}
279 | )
280 | );
281 | assert_eq!(expected, actual.normalize(&strategy));
282 | }
283 |
284 | #[test]
285 | fn normalize_η() {
286 | let strategy = Strategy::Applicative(true);
287 |
288 | assert_eq!(var!(f), abs! {x.app!(f,x)}.normalize(&strategy));
289 | assert_eq!(abs! {x.app!(x,x)}, abs! {x.app!(x, x)}.normalize(&strategy));
290 | assert_eq!(abs! {f.f}, abs! {f.abs!{g.abs!{x.app!(app!(f,g),x)}}});
291 | }
292 |
293 | #[test]
294 | #[ignore]
295 | #[allow(non_snake_case)]
296 | fn normalize_Ω() {
297 | let strategy = Strategy::Applicative(false);
298 |
299 | let Ω = app!(abs! {x.app!(x,x)}, abs! {x.app!(x,x)});
300 | assert_eq!(abs! {x.x}, Ω.normalize(&strategy));
301 | }
302 |
303 | // TODO: Strategy testing.
304 |
305 | #[test]
306 | fn replace() {
307 | assert_eq!(var!(b), var!(a).replace(&variable!(a), &variable!(b)));
308 | assert_eq!(app!(b, b), app!(a, a).replace(&variable!(a), &variable!(b)));
309 | assert_eq!(abs! {b.b}, abs! {a.a}.replace(&variable!(a), &variable!(b)));
310 | }
311 | }
312 |
--------------------------------------------------------------------------------
/benches/baselines/v0.3.0_bench.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "base",
3 | "benchmarks": {
4 | "native addition/0": {
5 | "baseline": "base",
6 | "fullname": "base/native addition/0",
7 | "criterion_benchmark_v1": {
8 | "group_id": "native addition",
9 | "function_id": null,
10 | "value_str": "0",
11 | "throughput": null,
12 | "full_id": "native addition/0",
13 | "directory_name": "native addition/0"
14 | },
15 | "criterion_estimates_v1": {
16 | "Mean": {
17 | "confidence_interval": {
18 | "confidence_level": 0.95,
19 | "lower_bound": 0.2968468484936433,
20 | "upper_bound": 0.29981451390539515
21 | },
22 | "point_estimate": 0.2980689101273462,
23 | "standard_error": 0.0007732078076600166
24 | },
25 | "Median": {
26 | "confidence_interval": {
27 | "confidence_level": 0.95,
28 | "lower_bound": 0.2963090448367719,
29 | "upper_bound": 0.29644436136993063
30 | },
31 | "point_estimate": 0.29636802229825265,
32 | "standard_error": 0.000035282650295655695
33 | },
34 | "MedianAbsDev": {
35 | "confidence_interval": {
36 | "confidence_level": 0.95,
37 | "lower_bound": 0.0002254411781712316,
38 | "upper_bound": 0.0004287219866189192
39 | },
40 | "point_estimate": 0.00030633345954119817,
41 | "standard_error": 0.00005164797710510594
42 | },
43 | "Slope": {
44 | "confidence_interval": {
45 | "confidence_level": 0.95,
46 | "lower_bound": 0.29671960655889934,
47 | "upper_bound": 0.30091325223318677
48 | },
49 | "point_estimate": 0.2983809343621838,
50 | "standard_error": 0.001112998300797706
51 | },
52 | "StdDev": {
53 | "confidence_interval": {
54 | "confidence_level": 0.95,
55 | "lower_bound": 0.0019952290708290304,
56 | "upper_bound": 0.012467394399385635
57 | },
58 | "point_estimate": 0.007780645055749648,
59 | "standard_error": 0.0029524566947364372
60 | }
61 | }
62 | },
63 | "native addition/1": {
64 | "baseline": "base",
65 | "fullname": "base/native addition/1",
66 | "criterion_benchmark_v1": {
67 | "group_id": "native addition",
68 | "function_id": null,
69 | "value_str": "1",
70 | "throughput": null,
71 | "full_id": "native addition/1",
72 | "directory_name": "native addition/1"
73 | },
74 | "criterion_estimates_v1": {
75 | "Mean": {
76 | "confidence_interval": {
77 | "confidence_level": 0.95,
78 | "lower_bound": 0.2974932569243279,
79 | "upper_bound": 0.30142455551001746
80 | },
81 | "point_estimate": 0.29916448791189754,
82 | "standard_error": 0.001018035683551917
83 | },
84 | "Median": {
85 | "confidence_interval": {
86 | "confidence_level": 0.95,
87 | "lower_bound": 0.2966614004043141,
88 | "upper_bound": 0.29684766843879223
89 | },
90 | "point_estimate": 0.29674107319979465,
91 | "standard_error": 0.00005100175563118712
92 | },
93 | "MedianAbsDev": {
94 | "confidence_interval": {
95 | "confidence_level": 0.95,
96 | "lower_bound": 0.0002549709505649339,
97 | "upper_bound": 0.0005400208952110087
98 | },
99 | "point_estimate": 0.0004181377497412315,
100 | "standard_error": 0.00007269021666376222
101 | },
102 | "Slope": {
103 | "confidence_interval": {
104 | "confidence_level": 0.95,
105 | "lower_bound": 0.2971608543346816,
106 | "upper_bound": 0.3002425134055753
107 | },
108 | "point_estimate": 0.2984892274903682,
109 | "standard_error": 0.0007897881148983396
110 | },
111 | "StdDev": {
112 | "confidence_interval": {
113 | "confidence_level": 0.95,
114 | "lower_bound": 0.003405162674502418,
115 | "upper_bound": 0.015792138091545085
116 | },
117 | "point_estimate": 0.01021602855732574,
118 | "standard_error": 0.0032816176989411577
119 | }
120 | }
121 | },
122 | "native addition/16": {
123 | "baseline": "base",
124 | "fullname": "base/native addition/16",
125 | "criterion_benchmark_v1": {
126 | "group_id": "native addition",
127 | "function_id": null,
128 | "value_str": "16",
129 | "throughput": null,
130 | "full_id": "native addition/16",
131 | "directory_name": "native addition/16"
132 | },
133 | "criterion_estimates_v1": {
134 | "Mean": {
135 | "confidence_interval": {
136 | "confidence_level": 0.95,
137 | "lower_bound": 0.29703259415180594,
138 | "upper_bound": 0.30458481999513154
139 | },
140 | "point_estimate": 0.2999152911576112,
141 | "standard_error": 0.0020255055362622867
142 | },
143 | "Median": {
144 | "confidence_interval": {
145 | "confidence_level": 0.95,
146 | "lower_bound": 0.296028293280678,
147 | "upper_bound": 0.2962186846897828
148 | },
149 | "point_estimate": 0.29609128878637136,
150 | "standard_error": 0.00004743259148512791
151 | },
152 | "MedianAbsDev": {
153 | "confidence_interval": {
154 | "confidence_level": 0.95,
155 | "lower_bound": 0.00008149309004046841,
156 | "upper_bound": 0.00034947330618364224
157 | },
158 | "point_estimate": 0.0001685614645881633,
159 | "standard_error": 0.0000674481797812517
160 | },
161 | "Slope": {
162 | "confidence_interval": {
163 | "confidence_level": 0.95,
164 | "lower_bound": 0.296694330189109,
165 | "upper_bound": 0.29972462396528426
166 | },
167 | "point_estimate": 0.2980324283787414,
168 | "standard_error": 0.0007772907743877836
169 | },
170 | "StdDev": {
171 | "confidence_interval": {
172 | "confidence_level": 0.95,
173 | "lower_bound": 0.0035639092472373513,
174 | "upper_bound": 0.03375769020935149
175 | },
176 | "point_estimate": 0.020319324150107627,
177 | "standard_error": 0.009467540875262671
178 | }
179 | }
180 | },
181 | "native addition/2": {
182 | "baseline": "base",
183 | "fullname": "base/native addition/2",
184 | "criterion_benchmark_v1": {
185 | "group_id": "native addition",
186 | "function_id": null,
187 | "value_str": "2",
188 | "throughput": null,
189 | "full_id": "native addition/2",
190 | "directory_name": "native addition/2"
191 | },
192 | "criterion_estimates_v1": {
193 | "Mean": {
194 | "confidence_interval": {
195 | "confidence_level": 0.95,
196 | "lower_bound": 0.2970807937744729,
197 | "upper_bound": 0.3003533505568965
198 | },
199 | "point_estimate": 0.29847613972340964,
200 | "standard_error": 0.0008471106951294426
201 | },
202 | "Median": {
203 | "confidence_interval": {
204 | "confidence_level": 0.95,
205 | "lower_bound": 0.2962759008983252,
206 | "upper_bound": 0.29686478522322357
207 | },
208 | "point_estimate": 0.29654257081374513,
209 | "standard_error": 0.0001430952117779159
210 | },
211 | "MedianAbsDev": {
212 | "confidence_interval": {
213 | "confidence_level": 0.95,
214 | "lower_bound": 0.00042556487685459384,
215 | "upper_bound": 0.0010140397355954752
216 | },
217 | "point_estimate": 0.0007030435548050374,
218 | "standard_error": 0.00014045004917796367
219 | },
220 | "Slope": {
221 | "confidence_interval": {
222 | "confidence_level": 0.95,
223 | "lower_bound": 0.2972728090254777,
224 | "upper_bound": 0.3030484171817896
225 | },
226 | "point_estimate": 0.2994483113779417,
227 | "standard_error": 0.0015623364896958836
228 | },
229 | "StdDev": {
230 | "confidence_interval": {
231 | "confidence_level": 0.95,
232 | "lower_bound": 0.0022022166404387527,
233 | "upper_bound": 0.012921950064696168
234 | },
235 | "point_estimate": 0.008518972608538606,
236 | "standard_error": 0.0028147965992940107
237 | }
238 | }
239 | },
240 | "native addition/32": {
241 | "baseline": "base",
242 | "fullname": "base/native addition/32",
243 | "criterion_benchmark_v1": {
244 | "group_id": "native addition",
245 | "function_id": null,
246 | "value_str": "32",
247 | "throughput": null,
248 | "full_id": "native addition/32",
249 | "directory_name": "native addition/32"
250 | },
251 | "criterion_estimates_v1": {
252 | "Mean": {
253 | "confidence_interval": {
254 | "confidence_level": 0.95,
255 | "lower_bound": 0.297275827552392,
256 | "upper_bound": 0.30013184095846446
257 | },
258 | "point_estimate": 0.29851096988470344,
259 | "standard_error": 0.0007397907661081399
260 | },
261 | "Median": {
262 | "confidence_interval": {
263 | "confidence_level": 0.95,
264 | "lower_bound": 0.2966867798893299,
265 | "upper_bound": 0.2969044243893952
266 | },
267 | "point_estimate": 0.2967735926061519,
268 | "standard_error": 0.0000570089318612994
269 | },
270 | "MedianAbsDev": {
271 | "confidence_interval": {
272 | "confidence_level": 0.95,
273 | "lower_bound": 0.0003309350474998074,
274 | "upper_bound": 0.0006248792135043663
275 | },
276 | "point_estimate": 0.0004845653264040483,
277 | "standard_error": 0.0000780768625908119
278 | },
279 | "Slope": {
280 | "confidence_interval": {
281 | "confidence_level": 0.95,
282 | "lower_bound": 0.2971032978333613,
283 | "upper_bound": 0.3025042677653186
284 | },
285 | "point_estimate": 0.29932444397541724,
286 | "standard_error": 0.0014132132256441975
287 | },
288 | "StdDev": {
289 | "confidence_interval": {
290 | "confidence_level": 0.95,
291 | "lower_bound": 0.0027480440668540716,
292 | "upper_bound": 0.011290301535211246
293 | },
294 | "point_estimate": 0.007447559573931257,
295 | "standard_error": 0.002232602955317096
296 | }
297 | }
298 | },
299 | "native addition/4": {
300 | "baseline": "base",
301 | "fullname": "base/native addition/4",
302 | "criterion_benchmark_v1": {
303 | "group_id": "native addition",
304 | "function_id": null,
305 | "value_str": "4",
306 | "throughput": null,
307 | "full_id": "native addition/4",
308 | "directory_name": "native addition/4"
309 | },
310 | "criterion_estimates_v1": {
311 | "Mean": {
312 | "confidence_interval": {
313 | "confidence_level": 0.95,
314 | "lower_bound": 0.2966483633133743,
315 | "upper_bound": 0.2999014682361953
316 | },
317 | "point_estimate": 0.2980454326978392,
318 | "standard_error": 0.000841302596453012
319 | },
320 | "Median": {
321 | "confidence_interval": {
322 | "confidence_level": 0.95,
323 | "lower_bound": 0.2960522229086636,
324 | "upper_bound": 0.2961609506703249
325 | },
326 | "point_estimate": 0.29609173697738067,
327 | "standard_error": 0.00002747845366577081
328 | },
329 | "MedianAbsDev": {
330 | "confidence_interval": {
331 | "confidence_level": 0.95,
332 | "lower_bound": 0.00010453914475976706,
333 | "upper_bound": 0.0002269633664783
334 | },
335 | "point_estimate": 0.00016010171203138603,
336 | "standard_error": 0.00003019504692412464
337 | },
338 | "Slope": {
339 | "confidence_interval": {
340 | "confidence_level": 0.95,
341 | "lower_bound": 0.29652830364262145,
342 | "upper_bound": 0.30120607442341485
343 | },
344 | "point_estimate": 0.2983130531577798,
345 | "standard_error": 0.001252348934888083
346 | },
347 | "StdDev": {
348 | "confidence_interval": {
349 | "confidence_level": 0.95,
350 | "lower_bound": 0.0021139999809323,
351 | "upper_bound": 0.012823699698046956
352 | },
353 | "point_estimate": 0.008445058695073207,
354 | "standard_error": 0.0027015276518215373
355 | }
356 | }
357 | },
358 | "native addition/8": {
359 | "baseline": "base",
360 | "fullname": "base/native addition/8",
361 | "criterion_benchmark_v1": {
362 | "group_id": "native addition",
363 | "function_id": null,
364 | "value_str": "8",
365 | "throughput": null,
366 | "full_id": "native addition/8",
367 | "directory_name": "native addition/8"
368 | },
369 | "criterion_estimates_v1": {
370 | "Mean": {
371 | "confidence_interval": {
372 | "confidence_level": 0.95,
373 | "lower_bound": 0.2966275574721007,
374 | "upper_bound": 0.3004758779076329
375 | },
376 | "point_estimate": 0.2981698109443507,
377 | "standard_error": 0.001013961769455673
378 | },
379 | "Median": {
380 | "confidence_interval": {
381 | "confidence_level": 0.95,
382 | "lower_bound": 0.2960783413290481,
383 | "upper_bound": 0.29615919202533053
384 | },
385 | "point_estimate": 0.296108471868778,
386 | "standard_error": 0.00002065821411138976
387 | },
388 | "MedianAbsDev": {
389 | "confidence_interval": {
390 | "confidence_level": 0.95,
391 | "lower_bound": 0.00010137151395098546,
392 | "upper_bound": 0.0001996008745075391
393 | },
394 | "point_estimate": 0.0001438057706566066,
395 | "standard_error": 0.000026051713001064855
396 | },
397 | "Slope": {
398 | "confidence_interval": {
399 | "confidence_level": 0.95,
400 | "lower_bound": 0.2966422481588065,
401 | "upper_bound": 0.30105135041024694
402 | },
403 | "point_estimate": 0.2985043341611148,
404 | "standard_error": 0.001145339020403624
405 | },
406 | "StdDev": {
407 | "confidence_interval": {
408 | "confidence_level": 0.95,
409 | "lower_bound": 0.002346781134368851,
410 | "upper_bound": 0.016538811345455227
411 | },
412 | "point_estimate": 0.010162159068917148,
413 | "standard_error": 0.00418112059410067
414 | }
415 | }
416 | },
417 | "λ-expression addition/0": {
418 | "baseline": "base",
419 | "fullname": "base/λ-expression addition/0",
420 | "criterion_benchmark_v1": {
421 | "group_id": "λ-expression addition",
422 | "function_id": null,
423 | "value_str": "0",
424 | "throughput": null,
425 | "full_id": "λ-expression addition/0",
426 | "directory_name": "λ-expression addition/0"
427 | },
428 | "criterion_estimates_v1": {
429 | "Mean": {
430 | "confidence_interval": {
431 | "confidence_level": 0.95,
432 | "lower_bound": 13449.443388550942,
433 | "upper_bound": 13555.744922434284
434 | },
435 | "point_estimate": 13496.275874948264,
436 | "standard_error": 27.35214778416823
437 | },
438 | "Median": {
439 | "confidence_interval": {
440 | "confidence_level": 0.95,
441 | "lower_bound": 13406.31446414182,
442 | "upper_bound": 13430.824033272664
443 | },
444 | "point_estimate": 13421.207743408457,
445 | "standard_error": 5.913463768724566
446 | },
447 | "MedianAbsDev": {
448 | "confidence_interval": {
449 | "confidence_level": 0.95,
450 | "lower_bound": 23.306377088076676,
451 | "upper_bound": 45.40485672779425
452 | },
453 | "point_estimate": 36.32231699279966,
454 | "standard_error": 5.775624284504741
455 | },
456 | "Slope": {
457 | "confidence_interval": {
458 | "confidence_level": 0.95,
459 | "lower_bound": 13438.572144861288,
460 | "upper_bound": 13628.663197279877
461 | },
462 | "point_estimate": 13515.054902862605,
463 | "standard_error": 50.28906597420155
464 | },
465 | "StdDev": {
466 | "confidence_interval": {
467 | "confidence_level": 0.95,
468 | "lower_bound": 129.4971209105263,
469 | "upper_bound": 408.47714957406214
470 | },
471 | "point_estimate": 274.74619908142836,
472 | "standard_error": 75.60252417182761
473 | }
474 | }
475 | },
476 | "λ-expression addition/1": {
477 | "baseline": "base",
478 | "fullname": "base/λ-expression addition/1",
479 | "criterion_benchmark_v1": {
480 | "group_id": "λ-expression addition",
481 | "function_id": null,
482 | "value_str": "1",
483 | "throughput": null,
484 | "full_id": "λ-expression addition/1",
485 | "directory_name": "λ-expression addition/1"
486 | },
487 | "criterion_estimates_v1": {
488 | "Mean": {
489 | "confidence_interval": {
490 | "confidence_level": 0.95,
491 | "lower_bound": 22032.35135384203,
492 | "upper_bound": 22311.331190225337
493 | },
494 | "point_estimate": 22154.54140340484,
495 | "standard_error": 71.68197757581329
496 | },
497 | "Median": {
498 | "confidence_interval": {
499 | "confidence_level": 0.95,
500 | "lower_bound": 21963.818055555555,
501 | "upper_bound": 21971.856307258633
502 | },
503 | "point_estimate": 21967.231196581197,
504 | "standard_error": 1.9589172227392468
505 | },
506 | "MedianAbsDev": {
507 | "confidence_interval": {
508 | "confidence_level": 0.95,
509 | "lower_bound": 11.18555914508616,
510 | "upper_bound": 19.52331038509972
511 | },
512 | "point_estimate": 16.061021706890156,
513 | "standard_error": 2.088810251537709
514 | },
515 | "Slope": {
516 | "confidence_interval": {
517 | "confidence_level": 0.95,
518 | "lower_bound": 21989.711499063185,
519 | "upper_bound": 22272.396654948556
520 | },
521 | "point_estimate": 22104.353070620495,
522 | "standard_error": 74.1513907698145
523 | },
524 | "StdDev": {
525 | "confidence_interval": {
526 | "confidence_level": 0.95,
527 | "lower_bound": 290.66482415234725,
528 | "upper_bound": 1048.4154706111842
529 | },
530 | "point_estimate": 719.2075070528622,
531 | "standard_error": 192.42737433454823
532 | }
533 | }
534 | },
535 | "λ-expression addition/16": {
536 | "baseline": "base",
537 | "fullname": "base/λ-expression addition/16",
538 | "criterion_benchmark_v1": {
539 | "group_id": "λ-expression addition",
540 | "function_id": null,
541 | "value_str": "16",
542 | "throughput": null,
543 | "full_id": "λ-expression addition/16",
544 | "directory_name": "λ-expression addition/16"
545 | },
546 | "criterion_estimates_v1": {
547 | "Mean": {
548 | "confidence_interval": {
549 | "confidence_level": 0.95,
550 | "lower_bound": 412688.4729891293,
551 | "upper_bound": 417838.82914217864
552 | },
553 | "point_estimate": 415026.3712592694,
554 | "standard_error": 1321.450686255857
555 | },
556 | "Median": {
557 | "confidence_interval": {
558 | "confidence_level": 0.95,
559 | "lower_bound": 410607.7466094033,
560 | "upper_bound": 410832.15012368583
561 | },
562 | "point_estimate": 410650.9106060606,
563 | "standard_error": 59.9685133007851
564 | },
565 | "MedianAbsDev": {
566 | "confidence_interval": {
567 | "confidence_level": 0.95,
568 | "lower_bound": 223.9008251745031,
569 | "upper_bound": 496.77364758318936
570 | },
571 | "point_estimate": 311.86784201566525,
572 | "standard_error": 66.72033379729751
573 | },
574 | "Slope": {
575 | "confidence_interval": {
576 | "confidence_level": 0.95,
577 | "lower_bound": 411674.5508292543,
578 | "upper_bound": 415239.8957054938
579 | },
580 | "point_estimate": 413285.14755923353,
581 | "standard_error": 914.4441412365476
582 | },
583 | "StdDev": {
584 | "confidence_interval": {
585 | "confidence_level": 0.95,
586 | "lower_bound": 7488.577039016398,
587 | "upper_bound": 17910.407834841233
588 | },
589 | "point_estimate": 13283.1709721034,
590 | "standard_error": 2652.6960868847145
591 | }
592 | }
593 | },
594 | "λ-expression addition/2": {
595 | "baseline": "base",
596 | "fullname": "base/λ-expression addition/2",
597 | "criterion_benchmark_v1": {
598 | "group_id": "λ-expression addition",
599 | "function_id": null,
600 | "value_str": "2",
601 | "throughput": null,
602 | "full_id": "λ-expression addition/2",
603 | "directory_name": "λ-expression addition/2"
604 | },
605 | "criterion_estimates_v1": {
606 | "Mean": {
607 | "confidence_interval": {
608 | "confidence_level": 0.95,
609 | "lower_bound": 32861.60347195717,
610 | "upper_bound": 33390.167925269394
611 | },
612 | "point_estimate": 33093.77925681181,
613 | "standard_error": 136.11088228956922
614 | },
615 | "Median": {
616 | "confidence_interval": {
617 | "confidence_level": 0.95,
618 | "lower_bound": 32684.714403600898,
619 | "upper_bound": 32736.470430107525
620 | },
621 | "point_estimate": 32719.647099192793,
622 | "standard_error": 13.91090300183185
623 | },
624 | "MedianAbsDev": {
625 | "confidence_interval": {
626 | "confidence_level": 0.95,
627 | "lower_bound": 78.35166225414126,
628 | "upper_bound": 144.98949330267604
629 | },
630 | "point_estimate": 112.85152322176866,
631 | "standard_error": 16.868616388083712
632 | },
633 | "Slope": {
634 | "confidence_interval": {
635 | "confidence_level": 0.95,
636 | "lower_bound": 32773.84658960515,
637 | "upper_bound": 33241.935849819274
638 | },
639 | "point_estimate": 32972.814606081694,
640 | "standard_error": 121.561459400322
641 | },
642 | "StdDev": {
643 | "confidence_interval": {
644 | "confidence_level": 0.95,
645 | "lower_bound": 541.0552766722783,
646 | "upper_bound": 1990.8429086743072
647 | },
648 | "point_estimate": 1369.0084500725852,
649 | "standard_error": 373.46146252476063
650 | }
651 | }
652 | },
653 | "λ-expression addition/32": {
654 | "baseline": "base",
655 | "fullname": "base/λ-expression addition/32",
656 | "criterion_benchmark_v1": {
657 | "group_id": "λ-expression addition",
658 | "function_id": null,
659 | "value_str": "32",
660 | "throughput": null,
661 | "full_id": "λ-expression addition/32",
662 | "directory_name": "λ-expression addition/32"
663 | },
664 | "criterion_estimates_v1": {
665 | "Mean": {
666 | "confidence_interval": {
667 | "confidence_level": 0.95,
668 | "lower_bound": 1408541.2890109746,
669 | "upper_bound": 1422880.1625501968
670 | },
671 | "point_estimate": 1415160.637315932,
672 | "standard_error": 3673.979222997814
673 | },
674 | "Median": {
675 | "confidence_interval": {
676 | "confidence_level": 0.95,
677 | "lower_bound": 1402206.066666667,
678 | "upper_bound": 1403709.4047619049
679 | },
680 | "point_estimate": 1402794.5511904764,
681 | "standard_error": 356.30215858853774
682 | },
683 | "MedianAbsDev": {
684 | "confidence_interval": {
685 | "confidence_level": 0.95,
686 | "lower_bound": 2636.1554144026177,
687 | "upper_bound": 5321.216823364671
688 | },
689 | "point_estimate": 4100.105962760796,
690 | "standard_error": 701.8382113562593
691 | },
692 | "Slope": {
693 | "confidence_interval": {
694 | "confidence_level": 0.95,
695 | "lower_bound": 1406443.225470772,
696 | "upper_bound": 1420864.0650071786
697 | },
698 | "point_estimate": 1412637.77345648,
699 | "standard_error": 3760.796398785651
700 | },
701 | "StdDev": {
702 | "confidence_interval": {
703 | "confidence_level": 0.95,
704 | "lower_bound": 23902.71680683939,
705 | "upper_bound": 47322.099934590835
706 | },
707 | "point_estimate": 36936.647888004954,
708 | "standard_error": 5997.233896050246
709 | }
710 | }
711 | },
712 | "λ-expression addition/4": {
713 | "baseline": "base",
714 | "fullname": "base/λ-expression addition/4",
715 | "criterion_benchmark_v1": {
716 | "group_id": "λ-expression addition",
717 | "function_id": null,
718 | "value_str": "4",
719 | "throughput": null,
720 | "full_id": "λ-expression addition/4",
721 | "directory_name": "λ-expression addition/4"
722 | },
723 | "criterion_estimates_v1": {
724 | "Mean": {
725 | "confidence_interval": {
726 | "confidence_level": 0.95,
727 | "lower_bound": 61153.60752645869,
728 | "upper_bound": 62527.283763870786
729 | },
730 | "point_estimate": 61773.95857713562,
731 | "standard_error": 352.3513592188564
732 | },
733 | "Median": {
734 | "confidence_interval": {
735 | "confidence_level": 0.95,
736 | "lower_bound": 60601.502521008406,
737 | "upper_bound": 60642.39956958393
738 | },
739 | "point_estimate": 60625.619453044375,
740 | "standard_error": 10.667326522819192
741 | },
742 | "MedianAbsDev": {
743 | "confidence_interval": {
744 | "confidence_level": 0.95,
745 | "lower_bound": 65.37024793447279,
746 | "upper_bound": 152.5597123901359
747 | },
748 | "point_estimate": 96.93416983974528,
749 | "standard_error": 20.848799467836837
750 | },
751 | "Slope": {
752 | "confidence_interval": {
753 | "confidence_level": 0.95,
754 | "lower_bound": 60871.17685548583,
755 | "upper_bound": 61981.24194778028
756 | },
757 | "point_estimate": 61333.74746129574,
758 | "standard_error": 287.4252267957783
759 | },
760 | "StdDev": {
761 | "confidence_interval": {
762 | "confidence_level": 0.95,
763 | "lower_bound": 1776.121808989942,
764 | "upper_bound": 4904.638476474027
765 | },
766 | "point_estimate": 3542.5899519992336,
767 | "standard_error": 791.2978950575418
768 | }
769 | }
770 | },
771 | "λ-expression addition/8": {
772 | "baseline": "base",
773 | "fullname": "base/λ-expression addition/8",
774 | "criterion_benchmark_v1": {
775 | "group_id": "λ-expression addition",
776 | "function_id": null,
777 | "value_str": "8",
778 | "throughput": null,
779 | "full_id": "λ-expression addition/8",
780 | "directory_name": "λ-expression addition/8"
781 | },
782 | "criterion_estimates_v1": {
783 | "Mean": {
784 | "confidence_interval": {
785 | "confidence_level": 0.95,
786 | "lower_bound": 142336.4996254305,
787 | "upper_bound": 144030.23561268055
788 | },
789 | "point_estimate": 143106.76805599275,
790 | "standard_error": 433.72120854000894
791 | },
792 | "Median": {
793 | "confidence_interval": {
794 | "confidence_level": 0.95,
795 | "lower_bound": 141762.5974851788,
796 | "upper_bound": 141851.92261904763
797 | },
798 | "point_estimate": 141794.19977324264,
799 | "standard_error": 25.28157656489059
800 | },
801 | "MedianAbsDev": {
802 | "confidence_interval": {
803 | "confidence_level": 0.95,
804 | "lower_bound": 106.4318448146757,
805 | "upper_bound": 200.434860462588
806 | },
807 | "point_estimate": 134.9374721235973,
808 | "standard_error": 25.03407228543716
809 | },
810 | "Slope": {
811 | "confidence_interval": {
812 | "confidence_level": 0.95,
813 | "lower_bound": 142008.04124203886,
814 | "upper_bound": 143368.54007868798
815 | },
816 | "point_estimate": 142612.91705714707,
817 | "standard_error": 348.563886654758
818 | },
819 | "StdDev": {
820 | "confidence_interval": {
821 | "confidence_level": 0.95,
822 | "lower_bound": 2391.8979703058926,
823 | "upper_bound": 5863.020890119689
824 | },
825 | "point_estimate": 4352.079543536833,
826 | "standard_error": 882.4143314382903
827 | }
828 | }
829 | }
830 | }
831 | }
832 |
--------------------------------------------------------------------------------
/benches/baselines/v0.4.0_bench.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "base",
3 | "benchmarks": {
4 | "native addition/0": {
5 | "baseline": "base",
6 | "fullname": "base/native addition/0",
7 | "criterion_benchmark_v1": {
8 | "group_id": "native addition",
9 | "function_id": null,
10 | "value_str": "0",
11 | "throughput": null,
12 | "full_id": "native addition/0",
13 | "directory_name": "native addition/0"
14 | },
15 | "criterion_estimates_v1": {
16 | "Mean": {
17 | "confidence_interval": {
18 | "confidence_level": 0.95,
19 | "lower_bound": 0.2962261445851212,
20 | "upper_bound": 0.29653215509710795
21 | },
22 | "point_estimate": 0.29636478189397847,
23 | "standard_error": 0.00007865866709119933
24 | },
25 | "Median": {
26 | "confidence_interval": {
27 | "confidence_level": 0.95,
28 | "lower_bound": 0.2960503017844731,
29 | "upper_bound": 0.2961245586618917
30 | },
31 | "point_estimate": 0.29607952114064223,
32 | "standard_error": 0.000018668330637618655
33 | },
34 | "MedianAbsDev": {
35 | "confidence_interval": {
36 | "confidence_level": 0.95,
37 | "lower_bound": 0.00008916117713999628,
38 | "upper_bound": 0.0002045092256151861
39 | },
40 | "point_estimate": 0.00014926329338063905,
41 | "standard_error": 0.00002832948934390167
42 | },
43 | "Slope": {
44 | "confidence_interval": {
45 | "confidence_level": 0.95,
46 | "lower_bound": 0.29614667997165234,
47 | "upper_bound": 0.29636869737397653
48 | },
49 | "point_estimate": 0.296248475006578,
50 | "standard_error": 0.000056924796605270056
51 | },
52 | "StdDev": {
53 | "confidence_interval": {
54 | "confidence_level": 0.95,
55 | "lower_bound": 0.0004223297609175888,
56 | "upper_bound": 0.0011308534895149067
57 | },
58 | "point_estimate": 0.0007911800592864537,
59 | "standard_error": 0.0001860270660541352
60 | }
61 | }
62 | },
63 | "native addition/1": {
64 | "baseline": "base",
65 | "fullname": "base/native addition/1",
66 | "criterion_benchmark_v1": {
67 | "group_id": "native addition",
68 | "function_id": null,
69 | "value_str": "1",
70 | "throughput": null,
71 | "full_id": "native addition/1",
72 | "directory_name": "native addition/1"
73 | },
74 | "criterion_estimates_v1": {
75 | "Mean": {
76 | "confidence_interval": {
77 | "confidence_level": 0.95,
78 | "lower_bound": 0.29627331026653847,
79 | "upper_bound": 0.2964986772074734
80 | },
81 | "point_estimate": 0.2963760485183063,
82 | "standard_error": 0.00005759500578483468
83 | },
84 | "Median": {
85 | "confidence_interval": {
86 | "confidence_level": 0.95,
87 | "lower_bound": 0.2961609880588777,
88 | "upper_bound": 0.2962780290960543
89 | },
90 | "point_estimate": 0.29620606173552433,
91 | "standard_error": 0.000028908297931034357
92 | },
93 | "MedianAbsDev": {
94 | "confidence_interval": {
95 | "confidence_level": 0.95,
96 | "lower_bound": 0.0001587899592866076,
97 | "upper_bound": 0.0002751525996343937
98 | },
99 | "point_estimate": 0.00022147895747918532,
100 | "standard_error": 0.0000289998173065974
101 | },
102 | "Slope": {
103 | "confidence_interval": {
104 | "confidence_level": 0.95,
105 | "lower_bound": 0.2961798393025073,
106 | "upper_bound": 0.29637287752906466
107 | },
108 | "point_estimate": 0.2962566477589002,
109 | "standard_error": 0.00005151575363440915
110 | },
111 | "StdDev": {
112 | "confidence_interval": {
113 | "confidence_level": 0.95,
114 | "lower_bound": 0.00033919370526819487,
115 | "upper_bound": 0.0007755852992926167
116 | },
117 | "point_estimate": 0.0005784933336136245,
118 | "standard_error": 0.00011134762718855966
119 | }
120 | }
121 | },
122 | "native addition/16": {
123 | "baseline": "base",
124 | "fullname": "base/native addition/16",
125 | "criterion_benchmark_v1": {
126 | "group_id": "native addition",
127 | "function_id": null,
128 | "value_str": "16",
129 | "throughput": null,
130 | "full_id": "native addition/16",
131 | "directory_name": "native addition/16"
132 | },
133 | "criterion_estimates_v1": {
134 | "Mean": {
135 | "confidence_interval": {
136 | "confidence_level": 0.95,
137 | "lower_bound": 0.2960536429357375,
138 | "upper_bound": 0.29622352849949346
139 | },
140 | "point_estimate": 0.2961265649820995,
141 | "standard_error": 0.000043880269602291657
142 | },
143 | "Median": {
144 | "confidence_interval": {
145 | "confidence_level": 0.95,
146 | "lower_bound": 0.29599517861953606,
147 | "upper_bound": 0.2960266097947223
148 | },
149 | "point_estimate": 0.29601049529877266,
150 | "standard_error": 7.399785854711407e-6
151 | },
152 | "MedianAbsDev": {
153 | "confidence_interval": {
154 | "confidence_level": 0.95,
155 | "lower_bound": 0.00003636132105251257,
156 | "upper_bound": 0.00007584584439626633
157 | },
158 | "point_estimate": 0.0000567255572585545,
159 | "standard_error": 9.322061189428703e-6
160 | },
161 | "Slope": {
162 | "confidence_interval": {
163 | "confidence_level": 0.95,
164 | "lower_bound": 0.2960183082963514,
165 | "upper_bound": 0.29606684096263175
166 | },
167 | "point_estimate": 0.2960398295959106,
168 | "standard_error": 0.000012431601861181598
169 | },
170 | "StdDev": {
171 | "confidence_interval": {
172 | "confidence_level": 0.95,
173 | "lower_bound": 0.0001325676375848892,
174 | "upper_bound": 0.0006699063515499536
175 | },
176 | "point_estimate": 0.0004417266367948229,
177 | "standard_error": 0.0001425521251068037
178 | }
179 | }
180 | },
181 | "native addition/2": {
182 | "baseline": "base",
183 | "fullname": "base/native addition/2",
184 | "criterion_benchmark_v1": {
185 | "group_id": "native addition",
186 | "function_id": null,
187 | "value_str": "2",
188 | "throughput": null,
189 | "full_id": "native addition/2",
190 | "directory_name": "native addition/2"
191 | },
192 | "criterion_estimates_v1": {
193 | "Mean": {
194 | "confidence_interval": {
195 | "confidence_level": 0.95,
196 | "lower_bound": 0.2960056899602688,
197 | "upper_bound": 0.29615937351938776
198 | },
199 | "point_estimate": 0.29607038710442973,
200 | "standard_error": 0.00003978028984870305
201 | },
202 | "Median": {
203 | "confidence_interval": {
204 | "confidence_level": 0.95,
205 | "lower_bound": 0.2959770479848523,
206 | "upper_bound": 0.29599708897286087
207 | },
208 | "point_estimate": 0.2959834181904062,
209 | "standard_error": 5.404067759959278e-6
210 | },
211 | "MedianAbsDev": {
212 | "confidence_interval": {
213 | "confidence_level": 0.95,
214 | "lower_bound": 0.00001602640619185146,
215 | "upper_bound": 0.00003519206192554544
216 | },
217 | "point_estimate": 0.00002380413083293452,
218 | "standard_error": 5.0033512880482366e-6
219 | },
220 | "Slope": {
221 | "confidence_interval": {
222 | "confidence_level": 0.95,
223 | "lower_bound": 0.2959930829752187,
224 | "upper_bound": 0.2961362188874299
225 | },
226 | "point_estimate": 0.2960412475796755,
227 | "standard_error": 0.00004135801510289805
228 | },
229 | "StdDev": {
230 | "confidence_interval": {
231 | "confidence_level": 0.95,
232 | "lower_bound": 0.00007717391841127824,
233 | "upper_bound": 0.0006287173435694216
234 | },
235 | "point_estimate": 0.0003990570268437357,
236 | "standard_error": 0.00013770722225541992
237 | }
238 | }
239 | },
240 | "native addition/32": {
241 | "baseline": "base",
242 | "fullname": "base/native addition/32",
243 | "criterion_benchmark_v1": {
244 | "group_id": "native addition",
245 | "function_id": null,
246 | "value_str": "32",
247 | "throughput": null,
248 | "full_id": "native addition/32",
249 | "directory_name": "native addition/32"
250 | },
251 | "criterion_estimates_v1": {
252 | "Mean": {
253 | "confidence_interval": {
254 | "confidence_level": 0.95,
255 | "lower_bound": 0.29618448061213687,
256 | "upper_bound": 0.2964230044515484
257 | },
258 | "point_estimate": 0.29629455601892374,
259 | "standard_error": 0.00006124393208134967
260 | },
261 | "Median": {
262 | "confidence_interval": {
263 | "confidence_level": 0.95,
264 | "lower_bound": 0.29599456142374225,
265 | "upper_bound": 0.29614577473849846
266 | },
267 | "point_estimate": 0.29605693916635445,
268 | "standard_error": 0.000046427829848173056
269 | },
270 | "MedianAbsDev": {
271 | "confidence_interval": {
272 | "confidence_level": 0.95,
273 | "lower_bound": 0.00004906282509039522,
274 | "upper_bound": 0.00025717996186190253
275 | },
276 | "point_estimate": 0.00013299289203624567,
277 | "standard_error": 0.00006093109422114702
278 | },
279 | "Slope": {
280 | "confidence_interval": {
281 | "confidence_level": 0.95,
282 | "lower_bound": 0.2962037200360951,
283 | "upper_bound": 0.29643933078396006
284 | },
285 | "point_estimate": 0.29630900026690493,
286 | "standard_error": 0.00006037415509783181
287 | },
288 | "StdDev": {
289 | "confidence_interval": {
290 | "confidence_level": 0.95,
291 | "lower_bound": 0.0003698625945367107,
292 | "upper_bound": 0.0008113650602247859
293 | },
294 | "point_estimate": 0.0006182543992120164,
295 | "standard_error": 0.00011163482850210684
296 | }
297 | }
298 | },
299 | "native addition/4": {
300 | "baseline": "base",
301 | "fullname": "base/native addition/4",
302 | "criterion_benchmark_v1": {
303 | "group_id": "native addition",
304 | "function_id": null,
305 | "value_str": "4",
306 | "throughput": null,
307 | "full_id": "native addition/4",
308 | "directory_name": "native addition/4"
309 | },
310 | "criterion_estimates_v1": {
311 | "Mean": {
312 | "confidence_interval": {
313 | "confidence_level": 0.95,
314 | "lower_bound": 0.2960451211693197,
315 | "upper_bound": 0.29626002672223734
316 | },
317 | "point_estimate": 0.2961347256366851,
318 | "standard_error": 0.00005572386836973852
319 | },
320 | "Median": {
321 | "confidence_interval": {
322 | "confidence_level": 0.95,
323 | "lower_bound": 0.29598563628333846,
324 | "upper_bound": 0.2960118948137096
325 | },
326 | "point_estimate": 0.29600373548350434,
327 | "standard_error": 6.862717450036348e-6
328 | },
329 | "MedianAbsDev": {
330 | "confidence_interval": {
331 | "confidence_level": 0.95,
332 | "lower_bound": 0.0000248097324687493,
333 | "upper_bound": 0.00005423478057657614
334 | },
335 | "point_estimate": 0.00004072574983054465,
336 | "standard_error": 7.512230819926435e-6
337 | },
338 | "Slope": {
339 | "confidence_interval": {
340 | "confidence_level": 0.95,
341 | "lower_bound": 0.296004275789509,
342 | "upper_bound": 0.296031335809251
343 | },
344 | "point_estimate": 0.2960163818084652,
345 | "standard_error": 6.964266043618953e-6
346 | },
347 | "StdDev": {
348 | "confidence_interval": {
349 | "confidence_level": 0.95,
350 | "lower_bound": 0.00018197343103318735,
351 | "upper_bound": 0.0008887700725879128
352 | },
353 | "point_estimate": 0.0005607801715188632,
354 | "standard_error": 0.0002032380609615226
355 | }
356 | }
357 | },
358 | "native addition/8": {
359 | "baseline": "base",
360 | "fullname": "base/native addition/8",
361 | "criterion_benchmark_v1": {
362 | "group_id": "native addition",
363 | "function_id": null,
364 | "value_str": "8",
365 | "throughput": null,
366 | "full_id": "native addition/8",
367 | "directory_name": "native addition/8"
368 | },
369 | "criterion_estimates_v1": {
370 | "Mean": {
371 | "confidence_interval": {
372 | "confidence_level": 0.95,
373 | "lower_bound": 0.2961159533259919,
374 | "upper_bound": 0.2987679308589585
375 | },
376 | "point_estimate": 0.29703172004586953,
377 | "standard_error": 0.0008150971705870495
378 | },
379 | "Median": {
380 | "confidence_interval": {
381 | "confidence_level": 0.95,
382 | "lower_bound": 0.29601896341259065,
383 | "upper_bound": 0.2961169270483068
384 | },
385 | "point_estimate": 0.2960484471966944,
386 | "standard_error": 0.000021242000280743857
387 | },
388 | "MedianAbsDev": {
389 | "confidence_interval": {
390 | "confidence_level": 0.95,
391 | "lower_bound": 0.00005232324600957407,
392 | "upper_bound": 0.00018001033295191003
393 | },
394 | "point_estimate": 0.00009788365236839503,
395 | "standard_error": 0.000028470713397887974
396 | },
397 | "Slope": {
398 | "confidence_interval": {
399 | "confidence_level": 0.95,
400 | "lower_bound": 0.2960677591424654,
401 | "upper_bound": 0.29613524305211847
402 | },
403 | "point_estimate": 0.2961001560160475,
404 | "standard_error": 0.00001724256010030734
405 | },
406 | "StdDev": {
407 | "confidence_interval": {
408 | "confidence_level": 0.95,
409 | "lower_bound": 0.00016211318000902285,
410 | "upper_bound": 0.013928964500328187
411 | },
412 | "point_estimate": 0.008146692687470243,
413 | "standard_error": 0.0047813187791358415
414 | }
415 | }
416 | },
417 | "λ-expression addition/0": {
418 | "baseline": "base",
419 | "fullname": "base/λ-expression addition/0",
420 | "criterion_benchmark_v1": {
421 | "group_id": "λ-expression addition",
422 | "function_id": null,
423 | "value_str": "0",
424 | "throughput": null,
425 | "full_id": "λ-expression addition/0",
426 | "directory_name": "λ-expression addition/0"
427 | },
428 | "criterion_estimates_v1": {
429 | "Mean": {
430 | "confidence_interval": {
431 | "confidence_level": 0.95,
432 | "lower_bound": 13419.172099456906,
433 | "upper_bound": 13499.90383784224
434 | },
435 | "point_estimate": 13447.216489721848,
436 | "standard_error": 24.98729998469355
437 | },
438 | "Median": {
439 | "confidence_interval": {
440 | "confidence_level": 0.95,
441 | "lower_bound": 13415.42315845257,
442 | "upper_bound": 13420.241423288331
443 | },
444 | "point_estimate": 13417.39860448684,
445 | "standard_error": 1.2294798413557133
446 | },
447 | "MedianAbsDev": {
448 | "confidence_interval": {
449 | "confidence_level": 0.95,
450 | "lower_bound": 6.4572094529306865,
451 | "upper_bound": 11.083679094361472
452 | },
453 | "point_estimate": 8.13761432594782,
454 | "standard_error": 1.2183816711550477
455 | },
456 | "Slope": {
457 | "confidence_interval": {
458 | "confidence_level": 0.95,
459 | "lower_bound": 13418.846200881804,
460 | "upper_bound": 13423.50189323957
461 | },
462 | "point_estimate": 13421.048188266588,
463 | "standard_error": 1.1891048042726475
464 | },
465 | "StdDev": {
466 | "confidence_interval": {
467 | "confidence_level": 0.95,
468 | "lower_bound": 11.36268530908325,
469 | "upper_bound": 430.9183890775378
470 | },
471 | "point_estimate": 251.8170260574141,
472 | "standard_error": 148.6917231770006
473 | }
474 | }
475 | },
476 | "λ-expression addition/1": {
477 | "baseline": "base",
478 | "fullname": "base/λ-expression addition/1",
479 | "criterion_benchmark_v1": {
480 | "group_id": "λ-expression addition",
481 | "function_id": null,
482 | "value_str": "1",
483 | "throughput": null,
484 | "full_id": "λ-expression addition/1",
485 | "directory_name": "λ-expression addition/1"
486 | },
487 | "criterion_estimates_v1": {
488 | "Mean": {
489 | "confidence_interval": {
490 | "confidence_level": 0.95,
491 | "lower_bound": 21991.15684672161,
492 | "upper_bound": 22008.084031169015
493 | },
494 | "point_estimate": 21998.86783294481,
495 | "standard_error": 4.3344685043864795
496 | },
497 | "Median": {
498 | "confidence_interval": {
499 | "confidence_level": 0.95,
500 | "lower_bound": 21987.70343212343,
501 | "upper_bound": 21992.296666666665
502 | },
503 | "point_estimate": 21990.24298515105,
504 | "standard_error": 1.3418982547728602
505 | },
506 | "MedianAbsDev": {
507 | "confidence_interval": {
508 | "confidence_level": 0.95,
509 | "lower_bound": 8.382232731939983,
510 | "upper_bound": 15.195441685781692
511 | },
512 | "point_estimate": 11.508128466357126,
513 | "standard_error": 1.7244935663051226
514 | },
515 | "Slope": {
516 | "confidence_interval": {
517 | "confidence_level": 0.95,
518 | "lower_bound": 21987.98126558551,
519 | "upper_bound": 22004.777581509803
520 | },
521 | "point_estimate": 21994.63521619625,
522 | "standard_error": 4.469491312163764
523 | },
524 | "StdDev": {
525 | "confidence_interval": {
526 | "confidence_level": 0.95,
527 | "lower_bound": 24.200588390753936,
528 | "upper_bound": 58.31545595234082
529 | },
530 | "point_estimate": 43.50809061229699,
531 | "standard_error": 8.664066442796566
532 | }
533 | }
534 | },
535 | "λ-expression addition/16": {
536 | "baseline": "base",
537 | "fullname": "base/λ-expression addition/16",
538 | "criterion_benchmark_v1": {
539 | "group_id": "λ-expression addition",
540 | "function_id": null,
541 | "value_str": "16",
542 | "throughput": null,
543 | "full_id": "λ-expression addition/16",
544 | "directory_name": "λ-expression addition/16"
545 | },
546 | "criterion_estimates_v1": {
547 | "Mean": {
548 | "confidence_interval": {
549 | "confidence_level": 0.95,
550 | "lower_bound": 412258.0351927795,
551 | "upper_bound": 412588.00220630935
552 | },
553 | "point_estimate": 412404.48395206063,
554 | "standard_error": 84.67447085271617
555 | },
556 | "Median": {
557 | "confidence_interval": {
558 | "confidence_level": 0.95,
559 | "lower_bound": 412090.3333333333,
560 | "upper_bound": 412187.9292929293
561 | },
562 | "point_estimate": 412140.4737762238,
563 | "standard_error": 21.76085010752117
564 | },
565 | "MedianAbsDev": {
566 | "confidence_interval": {
567 | "confidence_level": 0.95,
568 | "lower_bound": 140.98177931525882,
569 | "upper_bound": 279.9270483391157
570 | },
571 | "point_estimate": 202.4865132335761,
572 | "standard_error": 35.714656527223745
573 | },
574 | "Slope": {
575 | "confidence_interval": {
576 | "confidence_level": 0.95,
577 | "lower_bound": 412205.37695592566,
578 | "upper_bound": 412424.0480659112
579 | },
580 | "point_estimate": 412310.2869336486,
581 | "standard_error": 55.951388420699494
582 | },
583 | "StdDev": {
584 | "confidence_interval": {
585 | "confidence_level": 0.95,
586 | "lower_bound": 421.4421778953146,
587 | "upper_bound": 1242.0586717983865
588 | },
589 | "point_estimate": 849.8084849334746,
590 | "standard_error": 216.22975704628817
591 | }
592 | }
593 | },
594 | "λ-expression addition/2": {
595 | "baseline": "base",
596 | "fullname": "base/λ-expression addition/2",
597 | "criterion_benchmark_v1": {
598 | "group_id": "λ-expression addition",
599 | "function_id": null,
600 | "value_str": "2",
601 | "throughput": null,
602 | "full_id": "λ-expression addition/2",
603 | "directory_name": "λ-expression addition/2"
604 | },
605 | "criterion_estimates_v1": {
606 | "Mean": {
607 | "confidence_interval": {
608 | "confidence_level": 0.95,
609 | "lower_bound": 32717.963147283663,
610 | "upper_bound": 32795.52698823746
611 | },
612 | "point_estimate": 32747.529310932536,
613 | "standard_error": 20.97441987762656
614 | },
615 | "Median": {
616 | "confidence_interval": {
617 | "confidence_level": 0.95,
618 | "lower_bound": 32702.639398012383,
619 | "upper_bound": 32726.522008846696
620 | },
621 | "point_estimate": 32713.849115504683,
622 | "standard_error": 6.082145507111555
623 | },
624 | "MedianAbsDev": {
625 | "confidence_interval": {
626 | "confidence_level": 0.95,
627 | "lower_bound": 32.09296637165146,
628 | "upper_bound": 50.90547079169847
629 | },
630 | "point_estimate": 43.2887443957153,
631 | "standard_error": 4.956831395218115
632 | },
633 | "Slope": {
634 | "confidence_interval": {
635 | "confidence_level": 0.95,
636 | "lower_bound": 32703.379207555332,
637 | "upper_bound": 32721.59458187356
638 | },
639 | "point_estimate": 32712.172760216803,
640 | "standard_error": 4.640527197246629
641 | },
642 | "StdDev": {
643 | "confidence_interval": {
644 | "confidence_level": 0.95,
645 | "lower_bound": 44.91795637307894,
646 | "upper_bound": 352.47530171523044
647 | },
648 | "point_estimate": 211.48491083513997,
649 | "standard_error": 100.593744450631
650 | }
651 | }
652 | },
653 | "λ-expression addition/32": {
654 | "baseline": "base",
655 | "fullname": "base/λ-expression addition/32",
656 | "criterion_benchmark_v1": {
657 | "group_id": "λ-expression addition",
658 | "function_id": null,
659 | "value_str": "32",
660 | "throughput": null,
661 | "full_id": "λ-expression addition/32",
662 | "directory_name": "λ-expression addition/32"
663 | },
664 | "criterion_estimates_v1": {
665 | "Mean": {
666 | "confidence_interval": {
667 | "confidence_level": 0.95,
668 | "lower_bound": 1406673.120846631,
669 | "upper_bound": 1408092.0614177466
670 | },
671 | "point_estimate": 1407346.9691002823,
672 | "standard_error": 361.4881345452805
673 | },
674 | "Median": {
675 | "confidence_interval": {
676 | "confidence_level": 0.95,
677 | "lower_bound": 1406782.398993808,
678 | "upper_bound": 1407518.5368421052
679 | },
680 | "point_estimate": 1407154.2936507938,
681 | "standard_error": 185.8691110446379
682 | },
683 | "MedianAbsDev": {
684 | "confidence_interval": {
685 | "confidence_level": 0.95,
686 | "lower_bound": 1224.6672336505724,
687 | "upper_bound": 1868.281734193091
688 | },
689 | "point_estimate": 1496.868414451009,
690 | "standard_error": 163.99396920185893
691 | },
692 | "Slope": {
693 | "confidence_interval": {
694 | "confidence_level": 0.95,
695 | "lower_bound": 1405997.6566173215,
696 | "upper_bound": 1407439.725864377
697 | },
698 | "point_estimate": 1406728.1597990247,
699 | "standard_error": 366.92704799742
700 | },
701 | "StdDev": {
702 | "confidence_interval": {
703 | "confidence_level": 0.95,
704 | "lower_bound": 2284.152562451756,
705 | "upper_bound": 4860.142358172205
706 | },
707 | "point_estimate": 3642.6046131719786,
708 | "standard_error": 659.8483607230639
709 | }
710 | }
711 | },
712 | "λ-expression addition/4": {
713 | "baseline": "base",
714 | "fullname": "base/λ-expression addition/4",
715 | "criterion_benchmark_v1": {
716 | "group_id": "λ-expression addition",
717 | "function_id": null,
718 | "value_str": "4",
719 | "throughput": null,
720 | "full_id": "λ-expression addition/4",
721 | "directory_name": "λ-expression addition/4"
722 | },
723 | "criterion_estimates_v1": {
724 | "Mean": {
725 | "confidence_interval": {
726 | "confidence_level": 0.95,
727 | "lower_bound": 60489.84308240336,
728 | "upper_bound": 60549.5041205548
729 | },
730 | "point_estimate": 60516.02490424841,
731 | "standard_error": 15.426846709313851
732 | },
733 | "Median": {
734 | "confidence_interval": {
735 | "confidence_level": 0.95,
736 | "lower_bound": 60463.41176470588,
737 | "upper_bound": 60491.790603741494
738 | },
739 | "point_estimate": 60474.173700591346,
740 | "standard_error": 7.795767012372237
741 | },
742 | "MedianAbsDev": {
743 | "confidence_interval": {
744 | "confidence_level": 0.95,
745 | "lower_bound": 36.92267641104938,
746 | "upper_bound": 70.68602395514246
747 | },
748 | "point_estimate": 51.190236411449625,
749 | "standard_error": 8.443761500299653
750 | },
751 | "Slope": {
752 | "confidence_interval": {
753 | "confidence_level": 0.95,
754 | "lower_bound": 60503.30641090349,
755 | "upper_bound": 60533.25477066823
756 | },
757 | "point_estimate": 60518.31268143847,
758 | "standard_error": 7.613959689786166
759 | },
760 | "StdDev": {
761 | "confidence_interval": {
762 | "confidence_level": 0.95,
763 | "lower_bound": 60.92546224709873,
764 | "upper_bound": 232.4735539959209
765 | },
766 | "point_estimate": 155.34286088095925,
767 | "standard_error": 45.70192464249218
768 | }
769 | }
770 | },
771 | "λ-expression addition/8": {
772 | "baseline": "base",
773 | "fullname": "base/λ-expression addition/8",
774 | "criterion_benchmark_v1": {
775 | "group_id": "λ-expression addition",
776 | "function_id": null,
777 | "value_str": "8",
778 | "throughput": null,
779 | "full_id": "λ-expression addition/8",
780 | "directory_name": "λ-expression addition/8"
781 | },
782 | "criterion_estimates_v1": {
783 | "Mean": {
784 | "confidence_interval": {
785 | "confidence_level": 0.95,
786 | "lower_bound": 141825.09984838014,
787 | "upper_bound": 141951.53805074206
788 | },
789 | "point_estimate": 141880.63280450238,
790 | "standard_error": 32.57101957064142
791 | },
792 | "Median": {
793 | "confidence_interval": {
794 | "confidence_level": 0.95,
795 | "lower_bound": 141793.3192481203,
796 | "upper_bound": 141822.87394957984
797 | },
798 | "point_estimate": 141801.0717189315,
799 | "standard_error": 9.013766113564763
800 | },
801 | "MedianAbsDev": {
802 | "confidence_interval": {
803 | "confidence_level": 0.95,
804 | "lower_bound": 34.79895189055458,
805 | "upper_bound": 57.93287118699164
806 | },
807 | "point_estimate": 45.22943033140649,
808 | "standard_error": 5.991652159965814
809 | },
810 | "Slope": {
811 | "confidence_interval": {
812 | "confidence_level": 0.95,
813 | "lower_bound": 141795.4526169362,
814 | "upper_bound": 141824.79582209594
815 | },
816 | "point_estimate": 141809.04570921912,
817 | "standard_error": 7.4709802381494
818 | },
819 | "StdDev": {
820 | "confidence_interval": {
821 | "confidence_level": 0.95,
822 | "lower_bound": 115.44644380644294,
823 | "upper_bound": 476.3764202362789
824 | },
825 | "point_estimate": 326.94680597276704,
826 | "standard_error": 89.09743151821272
827 | }
828 | }
829 | }
830 | }
831 | }
832 |
--------------------------------------------------------------------------------