summaryrefslogtreecommitdiff
path: root/dhall/src/normalize.rs
diff options
context:
space:
mode:
Diffstat (limited to 'dhall/src/normalize.rs')
-rw-r--r--dhall/src/normalize.rs1909
1 files changed, 0 insertions, 1909 deletions
diff --git a/dhall/src/normalize.rs b/dhall/src/normalize.rs
deleted file mode 100644
index 1d306bc..0000000
--- a/dhall/src/normalize.rs
+++ /dev/null
@@ -1,1909 +0,0 @@
-#![allow(non_snake_case)]
-use std::collections::BTreeMap;
-use std::rc::Rc;
-
-use dhall_proc_macros as dhall;
-use dhall_syntax::context::Context;
-use dhall_syntax::{
- rc, BinOp, Builtin, Const, ExprF, Integer, InterpolatedTextContents, Label,
- Natural, Span, SubExpr, V, X,
-};
-
-use crate::expr::{Normalized, Type, Typed};
-
-type InputSubExpr = SubExpr<Span, Normalized>;
-type OutputSubExpr = SubExpr<X, X>;
-
-impl Typed {
- /// Reduce an expression to its normal form, performing beta reduction
- ///
- /// `normalize` does not type-check the expression. You may want to type-check
- /// expressions before normalizing them since normalization can convert an
- /// ill-typed expression into a well-typed expression.
- ///
- /// However, `normalize` will not fail if the expression is ill-typed and will
- /// leave ill-typed sub-expressions unevaluated.
- ///
- pub fn normalize(self) -> Normalized {
- match &self {
- Typed::Sort => {}
- Typed::Value(thunk, _) => {
- thunk.normalize_nf();
- }
- }
- Normalized(self)
- }
-}
-
-/// Stores a pair of variables: a normal one and if relevant one
-/// that corresponds to the alpha-normalized version of the first one.
-#[derive(Debug, Clone, Eq)]
-pub(crate) struct AlphaVar {
- normal: V<Label>,
- alpha: Option<V<()>>,
-}
-
-impl AlphaVar {
- pub(crate) fn to_var(&self, alpha: bool) -> V<Label> {
- match (alpha, &self.alpha) {
- (true, Some(x)) => V("_".into(), x.1),
- _ => self.normal.clone(),
- }
- }
- pub(crate) fn from_var(normal: V<Label>) -> Self {
- AlphaVar {
- normal,
- alpha: None,
- }
- }
- pub(crate) fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- AlphaVar {
- normal: self.normal.shift(delta, &var.normal),
- alpha: match (&self.alpha, &var.alpha) {
- (Some(x), Some(v)) => Some(x.shift(delta, v)),
- _ => None,
- },
- }
- }
-}
-
-/// Equality is up to alpha-equivalence.
-impl std::cmp::PartialEq for AlphaVar {
- fn eq(&self, other: &Self) -> bool {
- match (&self.alpha, &other.alpha) {
- (Some(x), Some(y)) => x == y,
- (None, None) => self.normal == other.normal,
- _ => false,
- }
- }
-}
-
-impl From<Label> for AlphaVar {
- fn from(x: Label) -> AlphaVar {
- AlphaVar {
- normal: V(x, 0),
- alpha: Some(V((), 0)),
- }
- }
-}
-impl<'a> From<&'a Label> for AlphaVar {
- fn from(x: &'a Label) -> AlphaVar {
- x.clone().into()
- }
-}
-impl From<AlphaLabel> for AlphaVar {
- fn from(x: AlphaLabel) -> AlphaVar {
- let l: Label = x.into();
- l.into()
- }
-}
-impl<'a> From<&'a AlphaLabel> for AlphaVar {
- fn from(x: &'a AlphaLabel) -> AlphaVar {
- x.clone().into()
- }
-}
-
-// Exactly like a Label, but equality returns always true.
-// This is so that Value equality is exactly alpha-equivalence.
-#[derive(Debug, Clone, Eq)]
-pub(crate) struct AlphaLabel(Label);
-
-impl AlphaLabel {
- fn to_label_maybe_alpha(&self, alpha: bool) -> Label {
- if alpha {
- "_".into()
- } else {
- self.to_label()
- }
- }
- fn to_label(&self) -> Label {
- self.clone().into()
- }
-}
-
-impl std::cmp::PartialEq for AlphaLabel {
- fn eq(&self, _other: &Self) -> bool {
- true
- }
-}
-
-impl From<Label> for AlphaLabel {
- fn from(x: Label) -> AlphaLabel {
- AlphaLabel(x)
- }
-}
-impl From<AlphaLabel> for Label {
- fn from(x: AlphaLabel) -> Label {
- x.0
- }
-}
-
-#[derive(Debug, Clone)]
-enum EnvItem {
- Thunk(Thunk),
- Skip(AlphaVar),
-}
-
-impl EnvItem {
- fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- use EnvItem::*;
- match self {
- Thunk(e) => Thunk(e.shift(delta, var)),
- Skip(v) => Skip(v.shift(delta, var)),
- }
- }
-
- pub(crate) fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
- match self {
- EnvItem::Thunk(e) => EnvItem::Thunk(e.subst_shift(var, val)),
- EnvItem::Skip(v) if v == var => EnvItem::Thunk(val.to_thunk()),
- EnvItem::Skip(v) => EnvItem::Skip(v.shift(-1, var)),
- }
- }
-}
-
-#[derive(Debug, Clone)]
-pub(crate) struct NormalizationContext(Rc<Context<Label, EnvItem>>);
-
-impl NormalizationContext {
- pub(crate) fn new() -> Self {
- NormalizationContext(Rc::new(Context::new()))
- }
- fn skip(&self, x: &Label) -> Self {
- NormalizationContext(Rc::new(
- self.0
- .map(|_, e| e.shift(1, &x.into()))
- .insert(x.clone(), EnvItem::Skip(x.into())),
- ))
- }
- fn lookup(&self, var: &V<Label>) -> Value {
- let V(x, n) = var;
- match self.0.lookup(x, *n) {
- Some(EnvItem::Thunk(t)) => t.to_value(),
- Some(EnvItem::Skip(newvar)) => Value::Var(newvar.clone()),
- // Free variable
- None => Value::Var(AlphaVar::from_var(var.clone())),
- }
- }
- pub(crate) fn from_typecheck_ctx(
- tc_ctx: &crate::typecheck::TypecheckContext,
- ) -> Self {
- use crate::typecheck::EnvItem::*;
- let mut ctx = Context::new();
- for (k, vs) in tc_ctx.0.iter_keys() {
- for v in vs.iter() {
- let new_item = match v {
- Type(var, _) => EnvItem::Skip(var.clone()),
- Value(e) => EnvItem::Thunk(e.to_thunk()),
- };
- ctx = ctx.insert(k.clone(), new_item);
- }
- }
- NormalizationContext(Rc::new(ctx))
- }
-
- fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- NormalizationContext(Rc::new(self.0.map(|_, e| e.shift(delta, var))))
- }
-
- fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
- NormalizationContext(Rc::new(
- self.0.map(|_, e| e.subst_shift(var, val)),
- ))
- }
-}
-
-/// A semantic value.
-/// Equality is up to alpha-equivalence (renaming of bound variables).
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub(crate) enum Value {
- /// Closures
- Lam(AlphaLabel, Thunk, Thunk),
- AppliedBuiltin(Builtin, Vec<Thunk>),
- /// `λ(x: a) -> Some x`
- OptionalSomeClosure(TypeThunk),
- /// `λ(x : a) -> λ(xs : List a) -> [ x ] # xs`
- /// `λ(xs : List a) -> [ x ] # xs`
- ListConsClosure(TypeThunk, Option<Thunk>),
- /// `λ(x : Natural) -> x + 1`
- NaturalSuccClosure,
- Pi(AlphaLabel, TypeThunk, TypeThunk),
-
- Var(AlphaVar),
- Const(Const),
- BoolLit(bool),
- NaturalLit(Natural),
- IntegerLit(Integer),
- EmptyOptionalLit(TypeThunk),
- NEOptionalLit(Thunk),
- EmptyListLit(TypeThunk),
- NEListLit(Vec<Thunk>),
- RecordLit(BTreeMap<Label, Thunk>),
- RecordType(BTreeMap<Label, TypeThunk>),
- UnionType(BTreeMap<Label, Option<TypeThunk>>),
- UnionConstructor(Label, BTreeMap<Label, Option<TypeThunk>>),
- UnionLit(Label, Thunk, BTreeMap<Label, Option<TypeThunk>>),
- TextLit(Vec<InterpolatedTextContents<Thunk>>),
- /// Invariant: This must not contain a value captured by one of the variants above.
- PartialExpr(ExprF<Thunk, Label, X>),
-}
-
-impl Value {
- pub(crate) fn into_thunk(self) -> Thunk {
- Thunk::from_value(self)
- }
-
- /// Convert the value to a fully normalized syntactic expression
- pub(crate) fn normalize_to_expr(&self) -> OutputSubExpr {
- self.normalize_to_expr_maybe_alpha(false)
- }
- /// Convert the value to a fully normalized syntactic expression. Also alpha-normalize
- /// if alpha is `true`
- pub(crate) fn normalize_to_expr_maybe_alpha(
- &self,
- alpha: bool,
- ) -> OutputSubExpr {
- match self {
- Value::Lam(x, t, e) => rc(ExprF::Lam(
- x.to_label_maybe_alpha(alpha),
- t.normalize_to_expr_maybe_alpha(alpha),
- e.normalize_to_expr_maybe_alpha(alpha),
- )),
- Value::AppliedBuiltin(b, args) => {
- let mut e = rc(ExprF::Builtin(*b));
- for v in args {
- e = rc(ExprF::App(
- e,
- v.normalize_to_expr_maybe_alpha(alpha),
- ));
- }
- e
- }
- Value::OptionalSomeClosure(n) => {
- let a = n.normalize_to_expr_maybe_alpha(alpha);
- dhall::subexpr!(λ(x: a) -> Some x)
- }
- Value::ListConsClosure(a, None) => {
- // Avoid accidental capture of the new `x` variable
- let a1 = a.shift(1, &Label::from("x").into());
- let a1 = a1.normalize_to_expr_maybe_alpha(alpha);
- let a = a.normalize_to_expr_maybe_alpha(alpha);
- dhall::subexpr!(λ(x : a) -> λ(xs : List a1) -> [ x ] # xs)
- }
- Value::ListConsClosure(n, Some(v)) => {
- // Avoid accidental capture of the new `xs` variable
- let v = v.shift(1, &Label::from("xs").into());
- let v = v.normalize_to_expr_maybe_alpha(alpha);
- let a = n.normalize_to_expr_maybe_alpha(alpha);
- dhall::subexpr!(λ(xs : List a) -> [ v ] # xs)
- }
- Value::NaturalSuccClosure => {
- dhall::subexpr!(λ(x : Natural) -> x + 1)
- }
- Value::Pi(x, t, e) => rc(ExprF::Pi(
- x.to_label_maybe_alpha(alpha),
- t.normalize_to_expr_maybe_alpha(alpha),
- e.normalize_to_expr_maybe_alpha(alpha),
- )),
- Value::Var(v) => rc(ExprF::Var(v.to_var(alpha))),
- Value::Const(c) => rc(ExprF::Const(*c)),
- Value::BoolLit(b) => rc(ExprF::BoolLit(*b)),
- Value::NaturalLit(n) => rc(ExprF::NaturalLit(*n)),
- Value::IntegerLit(n) => rc(ExprF::IntegerLit(*n)),
- Value::EmptyOptionalLit(n) => rc(ExprF::App(
- rc(ExprF::Builtin(Builtin::OptionalNone)),
- n.normalize_to_expr_maybe_alpha(alpha),
- )),
- Value::NEOptionalLit(n) => {
- rc(ExprF::SomeLit(n.normalize_to_expr_maybe_alpha(alpha)))
- }
- Value::EmptyListLit(n) => {
- rc(ExprF::EmptyListLit(n.normalize_to_expr_maybe_alpha(alpha)))
- }
- Value::NEListLit(elts) => rc(ExprF::NEListLit(
- elts.into_iter()
- .map(|n| n.normalize_to_expr_maybe_alpha(alpha))
- .collect(),
- )),
- Value::RecordLit(kvs) => rc(ExprF::RecordLit(
- kvs.iter()
- .map(|(k, v)| {
- (k.clone(), v.normalize_to_expr_maybe_alpha(alpha))
- })
- .collect(),
- )),
- Value::RecordType(kts) => rc(ExprF::RecordType(
- kts.iter()
- .map(|(k, v)| {
- (k.clone(), v.normalize_to_expr_maybe_alpha(alpha))
- })
- .collect(),
- )),
- Value::UnionType(kts) => rc(ExprF::UnionType(
- kts.iter()
- .map(|(k, v)| {
- (
- k.clone(),
- v.as_ref().map(|v| {
- v.normalize_to_expr_maybe_alpha(alpha)
- }),
- )
- })
- .collect(),
- )),
- Value::UnionConstructor(l, kts) => {
- let kts = kts
- .iter()
- .map(|(k, v)| {
- (
- k.clone(),
- v.as_ref().map(|v| {
- v.normalize_to_expr_maybe_alpha(alpha)
- }),
- )
- })
- .collect();
- rc(ExprF::Field(rc(ExprF::UnionType(kts)), l.clone()))
- }
- Value::UnionLit(l, v, kts) => rc(ExprF::UnionLit(
- l.clone(),
- v.normalize_to_expr_maybe_alpha(alpha),
- kts.iter()
- .map(|(k, v)| {
- (
- k.clone(),
- v.as_ref().map(|v| {
- v.normalize_to_expr_maybe_alpha(alpha)
- }),
- )
- })
- .collect(),
- )),
- Value::TextLit(elts) => {
- use InterpolatedTextContents::{Expr, Text};
- rc(ExprF::TextLit(
- elts.iter()
- .map(|contents| match contents {
- Expr(e) => {
- Expr(e.normalize_to_expr_maybe_alpha(alpha))
- }
- Text(s) => Text(s.clone()),
- })
- .collect(),
- ))
- }
- Value::PartialExpr(e) => {
- rc(e.map_ref_simple(|v| v.normalize_to_expr_maybe_alpha(alpha)))
- }
- }
- }
-
- // Deprecated
- fn normalize(&self) -> Value {
- let mut v = self.clone();
- v.normalize_mut();
- v
- }
-
- pub(crate) fn normalize_mut(&mut self) {
- match self {
- Value::NaturalSuccClosure
- | Value::Var(_)
- | Value::Const(_)
- | Value::BoolLit(_)
- | Value::NaturalLit(_)
- | Value::IntegerLit(_) => {}
-
- Value::EmptyOptionalLit(tth)
- | Value::OptionalSomeClosure(tth)
- | Value::EmptyListLit(tth) => {
- tth.normalize_mut();
- }
-
- Value::NEOptionalLit(th) => {
- th.normalize_mut();
- }
- Value::Lam(_, t, e) => {
- t.normalize_mut();
- e.normalize_mut();
- }
- Value::Pi(_, t, e) => {
- t.normalize_mut();
- e.normalize_mut();
- }
- Value::AppliedBuiltin(_, args) => {
- for x in args.iter_mut() {
- x.normalize_mut();
- }
- }
- Value::ListConsClosure(t, v) => {
- t.normalize_mut();
- for x in v.iter_mut() {
- x.normalize_mut();
- }
- }
- Value::NEListLit(elts) => {
- for x in elts.iter_mut() {
- x.normalize_mut();
- }
- }
- Value::RecordLit(kvs) => {
- for x in kvs.values_mut() {
- x.normalize_mut();
- }
- }
- Value::RecordType(kvs) => {
- for x in kvs.values_mut() {
- x.normalize_mut();
- }
- }
- Value::UnionType(kts) | Value::UnionConstructor(_, kts) => {
- for x in kts.values_mut().flat_map(|opt| opt) {
- x.normalize_mut();
- }
- }
- Value::UnionLit(_, v, kts) => {
- v.normalize_mut();
- for x in kts.values_mut().flat_map(|opt| opt) {
- x.normalize_mut();
- }
- }
- Value::TextLit(elts) => {
- for x in elts.iter_mut() {
- use InterpolatedTextContents::{Expr, Text};
- match x {
- Expr(n) => n.normalize_mut(),
- Text(_) => {}
- }
- }
- }
- Value::PartialExpr(e) => {
- // TODO: need map_mut_simple
- e.map_ref_simple(|v| {
- v.normalize_nf();
- });
- }
- }
- }
-
- /// Apply to a value
- pub(crate) fn app(self, val: Value) -> Value {
- self.app_val(val)
- }
-
- /// Apply to a value
- pub(crate) fn app_val(self, val: Value) -> Value {
- self.app_thunk(val.into_thunk())
- }
-
- /// Apply to a thunk
- pub(crate) fn app_thunk(self, th: Thunk) -> Value {
- Thunk::from_value(self).app_thunk(th)
- }
-
- pub(crate) fn from_builtin(b: Builtin) -> Value {
- Value::AppliedBuiltin(b, vec![])
- }
-
- fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- match self {
- Value::Lam(x, t, e) => Value::Lam(
- x.clone(),
- t.shift(delta, var),
- e.shift(delta, &var.shift(1, &x.into())),
- ),
- Value::AppliedBuiltin(b, args) => Value::AppliedBuiltin(
- *b,
- args.iter().map(|v| v.shift(delta, var)).collect(),
- ),
- Value::NaturalSuccClosure => Value::NaturalSuccClosure,
- Value::OptionalSomeClosure(tth) => {
- Value::OptionalSomeClosure(tth.shift(delta, var))
- }
- Value::ListConsClosure(t, v) => Value::ListConsClosure(
- t.shift(delta, var),
- v.as_ref().map(|v| v.shift(delta, var)),
- ),
- Value::Pi(x, t, e) => Value::Pi(
- x.clone(),
- t.shift(delta, var),
- e.shift(delta, &var.shift(1, &x.into())),
- ),
- Value::Var(v) => Value::Var(v.shift(delta, var)),
- Value::Const(c) => Value::Const(*c),
- Value::BoolLit(b) => Value::BoolLit(*b),
- Value::NaturalLit(n) => Value::NaturalLit(*n),
- Value::IntegerLit(n) => Value::IntegerLit(*n),
- Value::EmptyOptionalLit(tth) => {
- Value::EmptyOptionalLit(tth.shift(delta, var))
- }
- Value::NEOptionalLit(th) => {
- Value::NEOptionalLit(th.shift(delta, var))
- }
- Value::EmptyListLit(tth) => {
- Value::EmptyListLit(tth.shift(delta, var))
- }
- Value::NEListLit(elts) => Value::NEListLit(
- elts.iter().map(|v| v.shift(delta, var)).collect(),
- ),
- Value::RecordLit(kvs) => Value::RecordLit(
- kvs.iter()
- .map(|(k, v)| (k.clone(), v.shift(delta, var)))
- .collect(),
- ),
- Value::RecordType(kvs) => Value::RecordType(
- kvs.iter()
- .map(|(k, v)| (k.clone(), v.shift(delta, var)))
- .collect(),
- ),
- Value::UnionType(kts) => Value::UnionType(
- kts.iter()
- .map(|(k, v)| {
- (k.clone(), v.as_ref().map(|v| v.shift(delta, var)))
- })
- .collect(),
- ),
- Value::UnionConstructor(x, kts) => Value::UnionConstructor(
- x.clone(),
- kts.iter()
- .map(|(k, v)| {
- (k.clone(), v.as_ref().map(|v| v.shift(delta, var)))
- })
- .collect(),
- ),
- Value::UnionLit(x, v, kts) => Value::UnionLit(
- x.clone(),
- v.shift(delta, var),
- kts.iter()
- .map(|(k, v)| {
- (k.clone(), v.as_ref().map(|v| v.shift(delta, var)))
- })
- .collect(),
- ),
- Value::TextLit(elts) => Value::TextLit(
- elts.iter()
- .map(|contents| {
- use InterpolatedTextContents::{Expr, Text};
- match contents {
- Expr(th) => Expr(th.shift(delta, var)),
- Text(s) => Text(s.clone()),
- }
- })
- .collect(),
- ),
- Value::PartialExpr(e) => {
- Value::PartialExpr(e.map_ref_with_special_handling_of_binders(
- |v| v.shift(delta, var),
- |x, v| v.shift(delta, &var.shift(1, &x.into())),
- X::clone,
- Label::clone,
- ))
- }
- }
- }
-
- pub(crate) fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
- match self {
- // Retry normalizing since substituting may allow progress
- Value::AppliedBuiltin(b, args) => apply_builtin(
- *b,
- args.iter().map(|v| v.subst_shift(var, val)).collect(),
- ),
- // Retry normalizing since substituting may allow progress
- Value::PartialExpr(e) => {
- normalize_one_layer(e.map_ref_with_special_handling_of_binders(
- |v| v.subst_shift(var, val),
- |x, v| {
- v.subst_shift(
- &var.shift(1, &x.into()),
- &val.shift(1, &x.into()),
- )
- },
- X::clone,
- Label::clone,
- ))
- }
- // Retry normalizing since substituting may allow progress
- Value::TextLit(elts) => {
- Value::TextLit(squash_textlit(elts.iter().map(|contents| {
- use InterpolatedTextContents::{Expr, Text};
- match contents {
- Expr(th) => Expr(th.subst_shift(var, val)),
- Text(s) => Text(s.clone()),
- }
- })))
- }
- Value::Lam(x, t, e) => Value::Lam(
- x.clone(),
- t.subst_shift(var, val),
- e.subst_shift(
- &var.shift(1, &x.into()),
- &val.shift(1, &x.into()),
- ),
- ),
- Value::NaturalSuccClosure => Value::NaturalSuccClosure,
- Value::OptionalSomeClosure(tth) => {
- Value::OptionalSomeClosure(tth.subst_shift(var, val))
- }
- Value::ListConsClosure(t, v) => Value::ListConsClosure(
- t.subst_shift(var, val),
- v.as_ref().map(|v| v.subst_shift(var, val)),
- ),
- Value::Pi(x, t, e) => Value::Pi(
- x.clone(),
- t.subst_shift(var, val),
- e.subst_shift(
- &var.shift(1, &x.into()),
- &val.shift(1, &x.into()),
- ),
- ),
- Value::Var(v) if v == var => val.to_value().clone(),
- Value::Var(v) => Value::Var(v.shift(-1, var)),
- Value::Const(c) => Value::Const(*c),
- Value::BoolLit(b) => Value::BoolLit(*b),
- Value::NaturalLit(n) => Value::NaturalLit(*n),
- Value::IntegerLit(n) => Value::IntegerLit(*n),
- Value::EmptyOptionalLit(tth) => {
- Value::EmptyOptionalLit(tth.subst_shift(var, val))
- }
- Value::NEOptionalLit(th) => {
- Value::NEOptionalLit(th.subst_shift(var, val))
- }
- Value::EmptyListLit(tth) => {
- Value::EmptyListLit(tth.subst_shift(var, val))
- }
- Value::NEListLit(elts) => Value::NEListLit(
- elts.iter().map(|v| v.subst_shift(var, val)).collect(),
- ),
- Value::RecordLit(kvs) => Value::RecordLit(
- kvs.iter()
- .map(|(k, v)| (k.clone(), v.subst_shift(var, val)))
- .collect(),
- ),
- Value::RecordType(kvs) => Value::RecordType(
- kvs.iter()
- .map(|(k, v)| (k.clone(), v.subst_shift(var, val)))
- .collect(),
- ),
- Value::UnionType(kts) => Value::UnionType(
- kts.iter()
- .map(|(k, v)| {
- (k.clone(), v.as_ref().map(|v| v.subst_shift(var, val)))
- })
- .collect(),
- ),
- Value::UnionConstructor(x, kts) => Value::UnionConstructor(
- x.clone(),
- kts.iter()
- .map(|(k, v)| {
- (k.clone(), v.as_ref().map(|v| v.subst_shift(var, val)))
- })
- .collect(),
- ),
- Value::UnionLit(x, v, kts) => Value::UnionLit(
- x.clone(),
- v.subst_shift(var, val),
- kts.iter()
- .map(|(k, v)| {
- (k.clone(), v.as_ref().map(|v| v.subst_shift(var, val)))
- })
- .collect(),
- ),
- }
- }
-}
-
-mod thunk {
- use super::{
- apply_any, normalize_whnf, AlphaVar, InputSubExpr,
- NormalizationContext, OutputSubExpr, Value,
- };
- use crate::expr::Typed;
- use std::cell::{Ref, RefCell};
- use std::rc::Rc;
-
- #[derive(Debug, Clone, Copy)]
- enum Marker {
- /// Weak Head Normal Form, i.e. subexpressions may not be normalized
- WHNF,
- /// Normal form, i.e. completely normalized
- NF,
- }
- use Marker::{NF, WHNF};
-
- #[derive(Debug)]
- enum ThunkInternal {
- /// Non-normalized value alongside a normalization context
- Unnormalized(NormalizationContext, InputSubExpr),
- /// Partially normalized value.
- /// Invariant: if the marker is `NF`, the value must be fully normalized
- Value(Marker, Value),
- }
-
- /// Stores a possibl unevaluated value. Uses RefCell to ensure that
- /// the value gets normalized at most once.
- #[derive(Debug, Clone)]
- pub struct Thunk(Rc<RefCell<ThunkInternal>>);
-
- impl ThunkInternal {
- fn into_thunk(self) -> Thunk {
- Thunk(Rc::new(RefCell::new(self)))
- }
-
- fn normalize_whnf(&mut self) {
- match self {
- ThunkInternal::Unnormalized(ctx, e) => {
- *self = ThunkInternal::Value(
- WHNF,
- normalize_whnf(ctx.clone(), e.clone()),
- )
- }
- // Already at least in WHNF
- ThunkInternal::Value(_, _) => {}
- }
- }
-
- fn normalize_nf(&mut self) {
- match self {
- ThunkInternal::Unnormalized(_, _) => {
- self.normalize_whnf();
- self.normalize_nf();
- }
- ThunkInternal::Value(m @ WHNF, v) => {
- v.normalize_mut();
- *m = NF;
- }
- // Already in NF
- ThunkInternal::Value(NF, _) => {}
- }
- }
-
- // Always use normalize_whnf before
- fn as_whnf(&self) -> &Value {
- match self {
- ThunkInternal::Unnormalized(_, _) => unreachable!(),
- ThunkInternal::Value(_, v) => v,
- }
- }
-
- // Always use normalize_nf before
- fn as_nf(&self) -> &Value {
- match self {
- ThunkInternal::Unnormalized(_, _) => unreachable!(),
- ThunkInternal::Value(WHNF, _) => unreachable!(),
- ThunkInternal::Value(NF, v) => v,
- }
- }
-
- fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- match self {
- ThunkInternal::Unnormalized(ctx, e) => {
- ThunkInternal::Unnormalized(
- ctx.shift(delta, var),
- e.clone(),
- )
- }
- ThunkInternal::Value(m, v) => {
- ThunkInternal::Value(*m, v.shift(delta, var))
- }
- }
- }
-
- fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
- match self {
- ThunkInternal::Unnormalized(ctx, e) => {
- ThunkInternal::Unnormalized(
- ctx.subst_shift(var, val),
- e.clone(),
- )
- }
- ThunkInternal::Value(_, v) => {
- // The resulting value may not stay in normal form after substitution
- ThunkInternal::Value(WHNF, v.subst_shift(var, val))
- }
- }
- }
- }
-
- impl Thunk {
- pub(crate) fn new(ctx: NormalizationContext, e: InputSubExpr) -> Thunk {
- ThunkInternal::Unnormalized(ctx, e).into_thunk()
- }
-
- pub(crate) fn from_value(v: Value) -> Thunk {
- ThunkInternal::Value(WHNF, v).into_thunk()
- }
-
- pub(crate) fn from_normalized_expr(e: OutputSubExpr) -> Thunk {
- Thunk::new(
- NormalizationContext::new(),
- e.embed_absurd().note_absurd(),
- )
- }
-
- // Normalizes contents to normal form; faster than `normalize_nf` if
- // no one else shares this thunk
- pub(crate) fn normalize_mut(&mut self) {
- match Rc::get_mut(&mut self.0) {
- // Mutate directly if sole owner
- Some(refcell) => RefCell::get_mut(refcell).normalize_nf(),
- // Otherwise mutate through the refcell
- None => self.0.borrow_mut().normalize_nf(),
- }
- }
-
- fn do_normalize_whnf(&self) {
- let borrow = self.0.borrow();
- match &*borrow {
- ThunkInternal::Unnormalized(_, _) => {
- drop(borrow);
- self.0.borrow_mut().normalize_whnf();
- }
- // Already at least in WHNF
- ThunkInternal::Value(_, _) => {}
- }
- }
-
- fn do_normalize_nf(&self) {
- let borrow = self.0.borrow();
- match &*borrow {
- ThunkInternal::Unnormalized(_, _)
- | ThunkInternal::Value(WHNF, _) => {
- drop(borrow);
- self.0.borrow_mut().normalize_nf();
- }
- // Already in NF
- ThunkInternal::Value(NF, _) => {}
- }
- }
-
- // WARNING: avoid normalizing any thunk while holding on to this ref
- // or you could run into BorrowMut panics
- pub(crate) fn normalize_nf(&self) -> Ref<Value> {
- self.do_normalize_nf();
- Ref::map(self.0.borrow(), ThunkInternal::as_nf)
- }
-
- // WARNING: avoid normalizing any thunk while holding on to this ref
- // or you could run into BorrowMut panics
- pub(crate) fn as_value(&self) -> Ref<Value> {
- self.do_normalize_whnf();
- Ref::map(self.0.borrow(), ThunkInternal::as_whnf)
- }
-
- pub(crate) fn to_value(&self) -> Value {
- self.as_value().clone()
- }
-
- pub(crate) fn normalize_to_expr(&self) -> OutputSubExpr {
- self.normalize_to_expr_maybe_alpha(false)
- }
-
- pub(crate) fn normalize_to_expr_maybe_alpha(
- &self,
- alpha: bool,
- ) -> OutputSubExpr {
- self.normalize_nf().normalize_to_expr_maybe_alpha(alpha)
- }
-
- pub(crate) fn app_val(&self, val: Value) -> Value {
- self.app_thunk(val.into_thunk())
- }
-
- pub(crate) fn app_thunk(&self, th: Thunk) -> Value {
- apply_any(self.clone(), th)
- }
-
- pub(crate) fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- self.0.borrow().shift(delta, var).into_thunk()
- }
-
- pub(crate) fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
- self.0.borrow().subst_shift(var, val).into_thunk()
- }
- }
-
- impl std::cmp::PartialEq for Thunk {
- fn eq(&self, other: &Self) -> bool {
- &*self.as_value() == &*other.as_value()
- }
- }
- impl std::cmp::Eq for Thunk {}
-}
-
-pub(crate) use thunk::Thunk;
-
-/// A thunk in type position.
-#[derive(Debug, Clone)]
-pub(crate) enum TypeThunk {
- Thunk(Thunk),
- Type(Type),
-}
-
-impl TypeThunk {
- fn from_value(v: Value) -> TypeThunk {
- TypeThunk::from_thunk(Thunk::from_value(v))
- }
-
- fn from_thunk(th: Thunk) -> TypeThunk {
- TypeThunk::Thunk(th)
- }
-
- pub(crate) fn from_type(t: Type) -> TypeThunk {
- TypeThunk::Type(t)
- }
-
- fn normalize_mut(&mut self) {
- match self {
- TypeThunk::Thunk(th) => th.normalize_mut(),
- TypeThunk::Type(_) => {}
- }
- }
-
- pub(crate) fn normalize_nf(&self) -> Value {
- match self {
- TypeThunk::Thunk(th) => th.normalize_nf().clone(),
- TypeThunk::Type(t) => t.to_value().normalize(),
- }
- }
-
- pub(crate) fn to_value(&self) -> Value {
- match self {
- TypeThunk::Thunk(th) => th.to_value(),
- TypeThunk::Type(t) => t.to_value(),
- }
- }
-
- pub(crate) fn normalize_to_expr_maybe_alpha(
- &self,
- alpha: bool,
- ) -> OutputSubExpr {
- self.normalize_nf().normalize_to_expr_maybe_alpha(alpha)
- }
-
- fn shift(&self, delta: isize, var: &AlphaVar) -> Self {
- match self {
- TypeThunk::Thunk(th) => TypeThunk::Thunk(th.shift(delta, var)),
- TypeThunk::Type(t) => TypeThunk::Type(t.shift(delta, var)),
- }
- }
-
- pub(crate) fn subst_shift(&self, var: &AlphaVar, val: &Typed) -> Self {
- match self {
- TypeThunk::Thunk(th) => TypeThunk::Thunk(th.subst_shift(var, val)),
- TypeThunk::Type(t) => TypeThunk::Type(t.subst_shift(var, val)),
- }
- }
-}
-
-impl std::cmp::PartialEq for TypeThunk {
- fn eq(&self, other: &Self) -> bool {
- self.to_value() == other.to_value()
- }
-}
-impl std::cmp::Eq for TypeThunk {}
-
-fn apply_builtin(b: Builtin, args: Vec<Thunk>) -> Value {
- use dhall_syntax::Builtin::*;
- use Value::*;
-
- // Return Ok((unconsumed args, returned value)), or Err(()) if value could not be produced.
- let ret = match (b, args.as_slice()) {
- (OptionalNone, [t, r..]) => {
- Ok((r, EmptyOptionalLit(TypeThunk::from_thunk(t.clone()))))
- }
- (NaturalIsZero, [n, r..]) => match &*n.as_value() {
- NaturalLit(n) => Ok((r, BoolLit(*n == 0))),
- _ => Err(()),
- },
- (NaturalEven, [n, r..]) => match &*n.as_value() {
- NaturalLit(n) => Ok((r, BoolLit(*n % 2 == 0))),
- _ => Err(()),
- },
- (NaturalOdd, [n, r..]) => match &*n.as_value() {
- NaturalLit(n) => Ok((r, BoolLit(*n % 2 != 0))),
- _ => Err(()),
- },
- (NaturalToInteger, [n, r..]) => match &*n.as_value() {
- NaturalLit(n) => Ok((r, IntegerLit(*n as isize))),
- _ => Err(()),
- },
- (NaturalShow, [n, r..]) => match &*n.as_value() {
- NaturalLit(n) => Ok((
- r,
- TextLit(vec![InterpolatedTextContents::Text(n.to_string())]),
- )),
- _ => Err(()),
- },
- (ListLength, [_, l, r..]) => match &*l.as_value() {
- EmptyListLit(_) => Ok((r, NaturalLit(0))),
- NEListLit(xs) => Ok((r, NaturalLit(xs.len()))),
- _ => Err(()),
- },
- (ListHead, [_, l, r..]) => match &*l.as_value() {
- EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()))),
- NEListLit(xs) => {
- Ok((r, NEOptionalLit(xs.iter().next().unwrap().clone())))
- }
- _ => Err(()),
- },
- (ListLast, [_, l, r..]) => match &*l.as_value() {
- EmptyListLit(n) => Ok((r, EmptyOptionalLit(n.clone()))),
- NEListLit(xs) => {
- Ok((r, NEOptionalLit(xs.iter().rev().next().unwrap().clone())))
- }
- _ => Err(()),
- },
- (ListReverse, [_, l, r..]) => match &*l.as_value() {
- EmptyListLit(n) => Ok((r, EmptyListLit(n.clone()))),
- NEListLit(xs) => {
- Ok((r, NEListLit(xs.iter().rev().cloned().collect())))
- }
- _ => Err(()),
- },
- (ListIndexed, [_, l, r..]) => match &*l.as_value() {
- EmptyListLit(t) => {
- let mut kts = BTreeMap::new();
- kts.insert(
- "index".into(),
- TypeThunk::from_value(Value::from_builtin(Natural)),
- );
- kts.insert("value".into(), t.clone());
- Ok((r, EmptyListLit(TypeThunk::from_value(RecordType(kts)))))
- }
- NEListLit(xs) => {
- let xs = xs
- .iter()
- .enumerate()
- .map(|(i, e)| {
- let i = NaturalLit(i);
- let mut kvs = BTreeMap::new();
- kvs.insert("index".into(), Thunk::from_value(i));
- kvs.insert("value".into(), e.clone());
- Thunk::from_value(RecordLit(kvs))
- })
- .collect();
- Ok((r, NEListLit(xs)))
- }
- _ => Err(()),
- },
- (ListBuild, [t, f, r..]) => match &*f.as_value() {
- // fold/build fusion
- Value::AppliedBuiltin(ListFold, args) => {
- if args.len() >= 2 {
- Ok((r, args[1].to_value()))
- } else {
- // Do we really need to handle this case ?
- unimplemented!()
- }
- }
- _ => Ok((
- r,
- f.app_val(Value::from_builtin(List).app_thunk(t.clone()))
- .app_val(ListConsClosure(
- TypeThunk::from_thunk(t.clone()),
- None,
- ))
- .app_val(EmptyListLit(TypeThunk::from_thunk(t.clone()))),
- )),
- },
- (ListFold, [_, l, _, cons, nil, r..]) => match &*l.as_value() {
- EmptyListLit(_) => Ok((r, nil.to_value())),
- NEListLit(xs) => {
- let mut v = nil.clone();
- for x in xs.iter().rev() {
- v = cons
- .clone()
- .app_thunk(x.clone())
- .app_thunk(v)
- .into_thunk();
- }
- Ok((r, v.to_value()))
- }
- _ => Err(()),
- },
- (OptionalBuild, [t, f, r..]) => match &*f.as_value() {
- // fold/build fusion
- Value::AppliedBuiltin(OptionalFold, args) => {
- if args.len() >= 2 {
- Ok((r, args[1].to_value()))
- } else {
- // Do we really need to handle this case ?
- unimplemented!()
- }
- }
- _ => Ok((
- r,
- f.app_val(Value::from_builtin(Optional).app_thunk(t.clone()))
- .app_val(OptionalSomeClosure(TypeThunk::from_thunk(
- t.clone(),
- )))
- .app_val(EmptyOptionalLit(TypeThunk::from_thunk(
- t.clone(),
- ))),
- )),
- },
- (OptionalFold, [_, v, _, just, nothing, r..]) => match &*v.as_value() {
- EmptyOptionalLit(_) => Ok((r, nothing.to_value())),
- NEOptionalLit(x) => Ok((r, just.app_thunk(x.clone()))),
- _ => Err(()),
- },
- (NaturalBuild, [f, r..]) => match &*f.as_value() {
- // fold/build fusion
- Value::AppliedBuiltin(NaturalFold, args) => {
- if args.len() >= 1 {
- Ok((r, args[0].to_value()))
- } else {
- // Do we really need to handle this case ?
- unimplemented!()
- }
- }
- _ => Ok((
- r,
- f.app_val(Value::from_builtin(Natural))
- .app_val(NaturalSuccClosure)
- .app_val(NaturalLit(0)),
- )),
- },
- (NaturalFold, [n, t, succ, zero, r..]) => match &*n.as_value() {
- NaturalLit(0) => Ok((r, zero.to_value())),
- NaturalLit(n) => {
- let fold = Value::from_builtin(NaturalFold)
- .app(NaturalLit(n - 1))
- .app_thunk(t.clone())
- .app_thunk(succ.clone())
- .app_thunk(zero.clone());
- Ok((r, succ.app_val(fold)))
- }
- _ => Err(()),
- },
- _ => Err(()),
- };
- match ret {
- Ok((unconsumed_args, mut v)) => {
- let n_consumed_args = args.len() - unconsumed_args.len();
- for x in args.into_iter().skip(n_consumed_args) {
- v = v.app_thunk(x);
- }
- v
- }
- Err(()) => AppliedBuiltin(b, args),
- }
-}
-
-fn apply_any(f: Thunk, a: Thunk) -> Value {
- let fallback = |f: Thunk, a: Thunk| Value::PartialExpr(ExprF::App(f, a));
-
- let f_borrow = f.as_value();
- match &*f_borrow {
- Value::Lam(x, _, e) => {
- let val = Typed::from_thunk_untyped(a);
- e.subst_shift(&x.into(), &val).to_value()
- }
- Value::AppliedBuiltin(b, args) => {
- use std::iter::once;
- let args = args.iter().cloned().chain(once(a.clone())).collect();
- apply_builtin(*b, args)
- }
- Value::OptionalSomeClosure(_) => Value::NEOptionalLit(a),
- Value::ListConsClosure(t, None) => {
- Value::ListConsClosure(t.clone(), Some(a))
- }
- Value::ListConsClosure(_, Some(x)) => {
- let a_borrow = a.as_value();
- match &*a_borrow {
- Value::EmptyListLit(_) => Value::NEListLit(vec![x.clone()]),
- Value::NEListLit(xs) => {
- use std::iter::once;
- let xs =
- once(x.clone()).chain(xs.iter().cloned()).collect();
- Value::NEListLit(xs)
- }
- _ => {
- drop(f_borrow);
- drop(a_borrow);
- fallback(f, a)
- }
- }
- }
- Value::NaturalSuccClosure => {
- let a_borrow = a.as_value();
- match &*a_borrow {
- Value::NaturalLit(n) => Value::NaturalLit(n + 1),
- _ => {
- drop(f_borrow);
- drop(a_borrow);
- fallback(f, a)
- }
- }
- }
- Value::UnionConstructor(l, kts) => {
- Value::UnionLit(l.clone(), a, kts.clone())
- }
- _ => {
- drop(f_borrow);
- fallback(f, a)
- }
- }
-}
-
-fn squash_textlit(
- elts: impl Iterator<Item = InterpolatedTextContents<Thunk>>,
-) -> Vec<InterpolatedTextContents<Thunk>> {
- use std::mem::replace;
- use InterpolatedTextContents::{Expr, Text};
-
- fn inner(
- elts: impl Iterator<Item = InterpolatedTextContents<Thunk>>,
- crnt_str: &mut String,
- ret: &mut Vec<InterpolatedTextContents<Thunk>>,
- ) {
- for contents in elts {
- match contents {
- Text(s) => crnt_str.push_str(&s),
- Expr(e) => {
- let e_borrow = e.as_value();
- match &*e_borrow {
- Value::TextLit(elts2) => {
- inner(elts2.iter().cloned(), crnt_str, ret)
- }
- _ => {
- drop(e_borrow);
- if !crnt_str.is_empty() {
- ret.push(Text(replace(crnt_str, String::new())))
- }
- ret.push(Expr(e.clone()))
- }
- }
- }
- }
- }
- }
-
- let mut crnt_str = String::new();
- let mut ret = Vec::new();
- inner(elts, &mut crnt_str, &mut ret);
- if !crnt_str.is_empty() {
- ret.push(Text(replace(&mut crnt_str, String::new())))
- }
- ret
-}
-
-/// Reduces the imput expression to a Value. Evaluates as little as possible.
-fn normalize_whnf(ctx: NormalizationContext, expr: InputSubExpr) -> Value {
- match expr.as_ref() {
- ExprF::Embed(e) => return e.to_value(),
- ExprF::Var(v) => return ctx.lookup(v),
- _ => {}
- }
-
- // Thunk subexpressions
- let expr: ExprF<Thunk, Label, X> =
- expr.as_ref().map_ref_with_special_handling_of_binders(
- |e| Thunk::new(ctx.clone(), e.clone()),
- |x, e| Thunk::new(ctx.skip(x), e.clone()),
- |_| unreachable!(),
- Label::clone,
- );
-
- normalize_one_layer(expr)
-}
-
-fn normalize_one_layer(expr: ExprF<Thunk, Label, X>) -> Value {
- use Value::{
- BoolLit, EmptyListLit, EmptyOptionalLit, IntegerLit, Lam, NEListLit,
- NEOptionalLit, NaturalLit, Pi, RecordLit, RecordType, TextLit,
- UnionConstructor, UnionLit, UnionType,
- };
-
- // Small helper enum to avoid repetition
- enum Ret<'a> {
- RetValue(Value),
- RetThunk(Thunk),
- RetThunkRef(&'a Thunk),
- RetExpr(ExprF<Thunk, Label, X>),
- }
- use Ret::{RetExpr, RetThunk, RetThunkRef, RetValue};
-
- let ret = match expr {
- ExprF::Embed(_) => unreachable!(),
- ExprF::Var(_) => unreachable!(),
- ExprF::Annot(x, _) => RetThunk(x),
- ExprF::Lam(x, t, e) => RetValue(Lam(x.into(), t, e)),
- ExprF::Pi(x, t, e) => RetValue(Pi(
- x.into(),
- TypeThunk::from_thunk(t),
- TypeThunk::from_thunk(e),
- )),
- ExprF::Let(x, _, v, b) => {
- let v = Typed::from_thunk_untyped(v);
- RetThunk(b.subst_shift(&x.into(), &v))
- }
- ExprF::App(v, a) => RetValue(v.app_thunk(a)),
- ExprF::Builtin(b) => RetValue(Value::from_builtin(b)),
- ExprF::Const(c) => RetValue(Value::Const(c)),
- ExprF::BoolLit(b) => RetValue(BoolLit(b)),
- ExprF::NaturalLit(n) => RetValue(NaturalLit(n)),
- ExprF::IntegerLit(n) => RetValue(IntegerLit(n)),
- ExprF::DoubleLit(_) => RetExpr(expr),
- ExprF::OldOptionalLit(None, t) => {
- RetValue(EmptyOptionalLit(TypeThunk::from_thunk(t)))
- }
- ExprF::OldOptionalLit(Some(e), _) => RetValue(NEOptionalLit(e)),
- ExprF::SomeLit(e) => RetValue(NEOptionalLit(e)),
- ExprF::EmptyListLit(t) => {
- RetValue(EmptyListLit(TypeThunk::from_thunk(t)))
- }
- ExprF::NEListLit(elts) => {
- RetValue(NEListLit(elts.into_iter().collect()))
- }
- ExprF::RecordLit(kvs) => RetValue(RecordLit(kvs.into_iter().collect())),
- ExprF::RecordType(kts) => RetValue(RecordType(
- kts.into_iter()
- .map(|(k, t)| (k, TypeThunk::from_thunk(t)))
- .collect(),
- )),
- ExprF::UnionLit(l, x, kts) => RetValue(UnionLit(
- l,
- x,
- kts.into_iter()
- .map(|(k, t)| (k, t.map(|t| TypeThunk::from_thunk(t))))
- .collect(),
- )),
- ExprF::UnionType(kts) => RetValue(UnionType(
- kts.into_iter()
- .map(|(k, t)| (k, t.map(|t| TypeThunk::from_thunk(t))))
- .collect(),
- )),
- ExprF::TextLit(elts) => {
- use InterpolatedTextContents::Expr;
- let elts: Vec<_> = squash_textlit(elts.into_iter());
- // Simplify bare interpolation
- if let [Expr(th)] = elts.as_slice() {
- RetThunk(th.clone())
- } else {
- RetValue(TextLit(elts))
- }
- }
- ExprF::BoolIf(ref b, ref e1, ref e2) => {
- let b_borrow = b.as_value();
- match &*b_borrow {
- BoolLit(true) => RetThunkRef(e1),
- BoolLit(false) => RetThunkRef(e2),
- _ => {
- let e1_borrow = e1.as_value();
- let e2_borrow = e2.as_value();
- match (&*e1_borrow, &*e2_borrow) {
- // Simplify `if b then True else False`
- (BoolLit(true), BoolLit(false)) => RetThunkRef(b),
- _ if e1 == e2 => RetThunkRef(e1),
- _ => {
- drop(b_borrow);
- drop(e1_borrow);
- drop(e2_borrow);
- RetExpr(expr)
- }
- }
- }
- }
- }
- ExprF::BinOp(o, ref x, ref y) => {
- use BinOp::{
- BoolAnd, BoolEQ, BoolNE, BoolOr, ListAppend, NaturalPlus,
- NaturalTimes, TextAppend,
- };
- let x_borrow = x.as_value();
- let y_borrow = y.as_value();
- match (o, &*x_borrow, &*y_borrow) {
- (BoolAnd, BoolLit(true), _) => RetThunkRef(y),
- (BoolAnd, _, BoolLit(true)) => RetThunkRef(x),
- (BoolAnd, BoolLit(false), _) => RetValue(BoolLit(false)),
- (BoolAnd, _, BoolLit(false)) => RetValue(BoolLit(false)),
- (BoolAnd, _, _) if x == y => RetThunkRef(x),
- (BoolOr, BoolLit(true), _) => RetValue(BoolLit(true)),
- (BoolOr, _, BoolLit(true)) => RetValue(BoolLit(true)),
- (BoolOr, BoolLit(false), _) => RetThunkRef(y),
- (BoolOr, _, BoolLit(false)) => RetThunkRef(x),
- (BoolOr, _, _) if x == y => RetThunkRef(x),
- (BoolEQ, BoolLit(true), _) => RetThunkRef(y),
- (BoolEQ, _, BoolLit(true)) => RetThunkRef(x),
- (BoolEQ, BoolLit(x), BoolLit(y)) => RetValue(BoolLit(x == y)),
- (BoolEQ, _, _) if x == y => RetValue(BoolLit(true)),
- (BoolNE, BoolLit(false), _) => RetThunkRef(y),
- (BoolNE, _, BoolLit(false)) => RetThunkRef(x),
- (BoolNE, BoolLit(x), BoolLit(y)) => RetValue(BoolLit(x != y)),
- (BoolNE, _, _) if x == y => RetValue(BoolLit(false)),
-
- (NaturalPlus, NaturalLit(0), _) => RetThunkRef(y),
- (NaturalPlus, _, NaturalLit(0)) => RetThunkRef(x),
- (NaturalPlus, NaturalLit(x), NaturalLit(y)) => {
- RetValue(NaturalLit(x + y))
- }
- (NaturalTimes, NaturalLit(0), _) => RetValue(NaturalLit(0)),
- (NaturalTimes, _, NaturalLit(0)) => RetValue(NaturalLit(0)),
- (NaturalTimes, NaturalLit(1), _) => RetThunkRef(y),
- (NaturalTimes, _, NaturalLit(1)) => RetThunkRef(x),
- (NaturalTimes, NaturalLit(x), NaturalLit(y)) => {
- RetValue(NaturalLit(x * y))
- }
-
- (ListAppend, EmptyListLit(_), _) => RetThunkRef(y),
- (ListAppend, _, EmptyListLit(_)) => RetThunkRef(x),
- (ListAppend, NEListLit(xs), NEListLit(ys)) => RetValue(
- NEListLit(xs.iter().chain(ys.iter()).cloned().collect()),
- ),
-
- (TextAppend, TextLit(x), _) if x.is_empty() => RetThunkRef(y),
- (TextAppend, _, TextLit(y)) if y.is_empty() => RetThunkRef(x),
- (TextAppend, TextLit(x), TextLit(y)) => RetValue(TextLit(
- squash_textlit(x.iter().chain(y.iter()).cloned()),
- )),
- (TextAppend, TextLit(x), _) => {
- use std::iter::once;
- let y = InterpolatedTextContents::Expr(y.clone());
- RetValue(TextLit(squash_textlit(
- x.iter().cloned().chain(once(y)),
- )))
- }
- (TextAppend, _, TextLit(y)) => {
- use std::iter::once;
- let x = InterpolatedTextContents::Expr(x.clone());
- RetValue(TextLit(squash_textlit(
- once(x).chain(y.iter().cloned()),
- )))
- }
-
- _ => {
- drop(x_borrow);
- drop(y_borrow);
- RetExpr(expr)
- }
- }
- }
-
- ExprF::Projection(_, ls) if ls.is_empty() => {
- RetValue(RecordLit(std::collections::BTreeMap::new()))
- }
- ExprF::Projection(ref v, ref ls) => {
- let v_borrow = v.as_value();
- match &*v_borrow {
- RecordLit(kvs) => RetValue(RecordLit(
- ls.iter()
- .filter_map(|l| {
- kvs.get(l).map(|x| (l.clone(), x.clone()))
- })
- .collect(),
- )),
- _ => {
- drop(v_borrow);
- RetExpr(expr)
- }
- }
- }
- ExprF::Field(ref v, ref l) => {
- let v_borrow = v.as_value();
- match &*v_borrow {
- RecordLit(kvs) => match kvs.get(l) {
- Some(r) => RetThunk(r.clone()),
- None => {
- drop(v_borrow);
- RetExpr(expr)
- }
- },
- UnionType(kts) => {
- RetValue(UnionConstructor(l.clone(), kts.clone()))
- }
- _ => {
- drop(v_borrow);
- RetExpr(expr)
- }
- }
- }
-
- ExprF::Merge(ref handlers, ref variant, _) => {
- let handlers_borrow = handlers.as_value();
- let variant_borrow = variant.as_value();
- match (&*handlers_borrow, &*variant_borrow) {
- (RecordLit(kvs), UnionConstructor(l, _)) => match kvs.get(l) {
- Some(h) => RetThunk(h.clone()),
- None => {
- drop(handlers_borrow);
- drop(variant_borrow);
- RetExpr(expr)
- }
- },
- (RecordLit(kvs), UnionLit(l, v, _)) => match kvs.get(l) {
- Some(h) => RetValue(h.app_thunk(v.clone())),
- None => {
- drop(handlers_borrow);
- drop(variant_borrow);
- RetExpr(expr)
- }
- },
- _ => {
- drop(handlers_borrow);
- drop(variant_borrow);
- RetExpr(expr)
- }
- }
- }
- };
-
- match ret {
- RetValue(v) => v,
- RetThunk(th) => th.to_value(),
- RetThunkRef(th) => th.to_value(),
- RetExpr(expr) => Value::PartialExpr(expr),
- }
-}
-
-#[cfg(test)]
-mod spec_tests {
- #![rustfmt::skip]
-
- macro_rules! norm {
- ($name:ident, $path:expr) => {
- make_spec_test!(Normalization, Success, $name, $path);
- };
- }
-
- macro_rules! alpha_norm {
- ($name:ident, $path:expr) => {
- make_spec_test!(AlphaNormalization, Success, $name, $path);
- };
- }
-
- norm!(success_haskell_tutorial_access_0, "haskell-tutorial/access/0");
- norm!(success_haskell_tutorial_access_1, "haskell-tutorial/access/1");
- // norm!(success_haskell_tutorial_combineTypes_0, "haskell-tutorial/combineTypes/0");
- // norm!(success_haskell_tutorial_combineTypes_1, "haskell-tutorial/combineTypes/1");
- // norm!(success_haskell_tutorial_prefer_0, "haskell-tutorial/prefer/0");
- norm!(success_haskell_tutorial_projection_0, "haskell-tutorial/projection/0");
-
- norm!(success_prelude_Bool_and_0, "prelude/Bool/and/0");
- norm!(success_prelude_Bool_and_1, "prelude/Bool/and/1");
- norm!(success_prelude_Bool_build_0, "prelude/Bool/build/0");
- norm!(success_prelude_Bool_build_1, "prelude/Bool/build/1");
- norm!(success_prelude_Bool_even_0, "prelude/Bool/even/0");
- norm!(success_prelude_Bool_even_1, "prelude/Bool/even/1");
- norm!(success_prelude_Bool_even_2, "prelude/Bool/even/2");
- norm!(success_prelude_Bool_even_3, "prelude/Bool/even/3");
- norm!(success_prelude_Bool_fold_0, "prelude/Bool/fold/0");
- norm!(success_prelude_Bool_fold_1, "prelude/Bool/fold/1");
- norm!(success_prelude_Bool_not_0, "prelude/Bool/not/0");
- norm!(success_prelude_Bool_not_1, "prelude/Bool/not/1");
- norm!(success_prelude_Bool_odd_0, "prelude/Bool/odd/0");
- norm!(success_prelude_Bool_odd_1, "prelude/Bool/odd/1");
- norm!(success_prelude_Bool_odd_2, "prelude/Bool/odd/2");
- norm!(success_prelude_Bool_odd_3, "prelude/Bool/odd/3");
- norm!(success_prelude_Bool_or_0, "prelude/Bool/or/0");
- norm!(success_prelude_Bool_or_1, "prelude/Bool/or/1");
- norm!(success_prelude_Bool_show_0, "prelude/Bool/show/0");
- norm!(success_prelude_Bool_show_1, "prelude/Bool/show/1");
- // norm!(success_prelude_Double_show_0, "prelude/Double/show/0");
- // norm!(success_prelude_Double_show_1, "prelude/Double/show/1");
- // norm!(success_prelude_Integer_show_0, "prelude/Integer/show/0");
- // norm!(success_prelude_Integer_show_1, "prelude/Integer/show/1");
- // norm!(success_prelude_Integer_toDouble_0, "prelude/Integer/toDouble/0");
- // norm!(success_prelude_Integer_toDouble_1, "prelude/Integer/toDouble/1");
- norm!(success_prelude_List_all_0, "prelude/List/all/0");
- norm!(success_prelude_List_all_1, "prelude/List/all/1");
- norm!(success_prelude_List_any_0, "prelude/List/any/0");
- norm!(success_prelude_List_any_1, "prelude/List/any/1");
- norm!(success_prelude_List_build_0, "prelude/List/build/0");
- norm!(success_prelude_List_build_1, "prelude/List/build/1");
- norm!(success_prelude_List_concat_0, "prelude/List/concat/0");
- norm!(success_prelude_List_concat_1, "prelude/List/concat/1");
- norm!(success_prelude_List_concatMap_0, "prelude/List/concatMap/0");
- norm!(success_prelude_List_concatMap_1, "prelude/List/concatMap/1");
- norm!(success_prelude_List_filter_0, "prelude/List/filter/0");
- norm!(success_prelude_List_filter_1, "prelude/List/filter/1");
- norm!(success_prelude_List_fold_0, "prelude/List/fold/0");
- norm!(success_prelude_List_fold_1, "prelude/List/fold/1");
- norm!(success_prelude_List_fold_2, "prelude/List/fold/2");
- norm!(success_prelude_List_generate_0, "prelude/List/generate/0");
- norm!(success_prelude_List_generate_1, "prelude/List/generate/1");
- norm!(success_prelude_List_head_0, "prelude/List/head/0");
- norm!(success_prelude_List_head_1, "prelude/List/head/1");
- norm!(success_prelude_List_indexed_0, "prelude/List/indexed/0");
- norm!(success_prelude_List_indexed_1, "prelude/List/indexed/1");
- norm!(success_prelude_List_iterate_0, "prelude/List/iterate/0");
- norm!(success_prelude_List_iterate_1, "prelude/List/iterate/1");
- norm!(success_prelude_List_last_0, "prelude/List/last/0");
- norm!(success_prelude_List_last_1, "prelude/List/last/1");
- norm!(success_prelude_List_length_0, "prelude/List/length/0");
- norm!(success_prelude_List_length_1, "prelude/List/length/1");
- norm!(success_prelude_List_map_0, "prelude/List/map/0");
- norm!(success_prelude_List_map_1, "prelude/List/map/1");
- norm!(success_prelude_List_null_0, "prelude/List/null/0");
- norm!(success_prelude_List_null_1, "prelude/List/null/1");
- norm!(success_prelude_List_replicate_0, "prelude/List/replicate/0");
- norm!(success_prelude_List_replicate_1, "prelude/List/replicate/1");
- norm!(success_prelude_List_reverse_0, "prelude/List/reverse/0");
- norm!(success_prelude_List_reverse_1, "prelude/List/reverse/1");
- norm!(success_prelude_List_shifted_0, "prelude/List/shifted/0");
- norm!(success_prelude_List_shifted_1, "prelude/List/shifted/1");
- norm!(success_prelude_List_unzip_0, "prelude/List/unzip/0");
- norm!(success_prelude_List_unzip_1, "prelude/List/unzip/1");
- norm!(success_prelude_Natural_build_0, "prelude/Natural/build/0");
- norm!(success_prelude_Natural_build_1, "prelude/Natural/build/1");
- norm!(success_prelude_Natural_enumerate_0, "prelude/Natural/enumerate/0");
- norm!(success_prelude_Natural_enumerate_1, "prelude/Natural/enumerate/1");
- norm!(success_prelude_Natural_even_0, "prelude/Natural/even/0");
- norm!(success_prelude_Natural_even_1, "prelude/Natural/even/1");
- norm!(success_prelude_Natural_fold_0, "prelude/Natural/fold/0");
- norm!(success_prelude_Natural_fold_1, "prelude/Natural/fold/1");
- norm!(success_prelude_Natural_fold_2, "prelude/Natural/fold/2");
- norm!(success_prelude_Natural_isZero_0, "prelude/Natural/isZero/0");
- norm!(success_prelude_Natural_isZero_1, "prelude/Natural/isZero/1");
- norm!(success_prelude_Natural_odd_0, "prelude/Natural/odd/0");
- norm!(success_prelude_Natural_odd_1, "prelude/Natural/odd/1");
- norm!(success_prelude_Natural_product_0, "prelude/Natural/product/0");
- norm!(success_prelude_Natural_product_1, "prelude/Natural/product/1");
- norm!(success_prelude_Natural_show_0, "prelude/Natural/show/0");
- norm!(success_prelude_Natural_show_1, "prelude/Natural/show/1");
- norm!(success_prelude_Natural_sum_0, "prelude/Natural/sum/0");
- norm!(success_prelude_Natural_sum_1, "prelude/Natural/sum/1");
- // norm!(success_prelude_Natural_toDouble_0, "prelude/Natural/toDouble/0");
- // norm!(success_prelude_Natural_toDouble_1, "prelude/Natural/toDouble/1");
- norm!(success_prelude_Natural_toInteger_0, "prelude/Natural/toInteger/0");
- norm!(success_prelude_Natural_toInteger_1, "prelude/Natural/toInteger/1");
- norm!(success_prelude_Optional_all_0, "prelude/Optional/all/0");
- norm!(success_prelude_Optional_all_1, "prelude/Optional/all/1");
- norm!(success_prelude_Optional_any_0, "prelude/Optional/any/0");
- norm!(success_prelude_Optional_any_1, "prelude/Optional/any/1");
- norm!(success_prelude_Optional_build_0, "prelude/Optional/build/0");
- norm!(success_prelude_Optional_build_1, "prelude/Optional/build/1");
- norm!(success_prelude_Optional_concat_0, "prelude/Optional/concat/0");
- norm!(success_prelude_Optional_concat_1, "prelude/Optional/concat/1");
- norm!(success_prelude_Optional_concat_2, "prelude/Optional/concat/2");
- norm!(success_prelude_Optional_filter_0, "prelude/Optional/filter/0");
- norm!(success_prelude_Optional_filter_1, "prelude/Optional/filter/1");
- norm!(success_prelude_Optional_fold_0, "prelude/Optional/fold/0");
- norm!(success_prelude_Optional_fold_1, "prelude/Optional/fold/1");
- norm!(success_prelude_Optional_head_0, "prelude/Optional/head/0");
- norm!(success_prelude_Optional_head_1, "prelude/Optional/head/1");
- norm!(success_prelude_Optional_head_2, "prelude/Optional/head/2");
- norm!(success_prelude_Optional_last_0, "prelude/Optional/last/0");
- norm!(success_prelude_Optional_last_1, "prelude/Optional/last/1");
- norm!(success_prelude_Optional_last_2, "prelude/Optional/last/2");
- norm!(success_prelude_Optional_length_0, "prelude/Optional/length/0");
- norm!(success_prelude_Optional_length_1, "prelude/Optional/length/1");
- norm!(success_prelude_Optional_map_0, "prelude/Optional/map/0");
- norm!(success_prelude_Optional_map_1, "prelude/Optional/map/1");
- norm!(success_prelude_Optional_null_0, "prelude/Optional/null/0");
- norm!(success_prelude_Optional_null_1, "prelude/Optional/null/1");
- norm!(success_prelude_Optional_toList_0, "prelude/Optional/toList/0");
- norm!(success_prelude_Optional_toList_1, "prelude/Optional/toList/1");
- norm!(success_prelude_Optional_unzip_0, "prelude/Optional/unzip/0");
- norm!(success_prelude_Optional_unzip_1, "prelude/Optional/unzip/1");
- norm!(success_prelude_Text_concat_0, "prelude/Text/concat/0");
- norm!(success_prelude_Text_concat_1, "prelude/Text/concat/1");
- norm!(success_prelude_Text_concatMap_0, "prelude/Text/concatMap/0");
- norm!(success_prelude_Text_concatMap_1, "prelude/Text/concatMap/1");
- // norm!(success_prelude_Text_concatMapSep_0, "prelude/Text/concatMapSep/0");
- // norm!(success_prelude_Text_concatMapSep_1, "prelude/Text/concatMapSep/1");
- // norm!(success_prelude_Text_concatSep_0, "prelude/Text/concatSep/0");
- // norm!(success_prelude_Text_concatSep_1, "prelude/Text/concatSep/1");
- // norm!(success_prelude_Text_show_0, "prelude/Text/show/0");
- // norm!(success_prelude_Text_show_1, "prelude/Text/show/1");
- // norm!(success_remoteSystems, "remoteSystems");
-
- // norm!(success_simple_doubleShow, "simple/doubleShow");
- norm!(success_simple_enum, "simple/enum");
- // norm!(success_simple_integerShow, "simple/integerShow");
- // norm!(success_simple_integerToDouble, "simple/integerToDouble");
- norm!(success_simple_letlet, "simple/letlet");
- norm!(success_simple_listBuild, "simple/listBuild");
- norm!(success_simple_multiLine, "simple/multiLine");
- norm!(success_simple_naturalBuild, "simple/naturalBuild");
- norm!(success_simple_naturalPlus, "simple/naturalPlus");
- norm!(success_simple_naturalShow, "simple/naturalShow");
- norm!(success_simple_naturalToInteger, "simple/naturalToInteger");
- norm!(success_simple_optionalBuild, "simple/optionalBuild");
- norm!(success_simple_optionalBuildFold, "simple/optionalBuildFold");
- norm!(success_simple_optionalFold, "simple/optionalFold");
- // norm!(success_simple_sortOperator, "simple/sortOperator");
- norm!(success_simplifications_and, "simplifications/and");
- norm!(success_simplifications_eq, "simplifications/eq");
- norm!(success_simplifications_ifThenElse, "simplifications/ifThenElse");
- norm!(success_simplifications_ne, "simplifications/ne");
- norm!(success_simplifications_or, "simplifications/or");
-
- norm!(success_unit_Bool, "unit/Bool");
- norm!(success_unit_Double, "unit/Double");
- norm!(success_unit_DoubleLiteral, "unit/DoubleLiteral");
- norm!(success_unit_DoubleShow, "unit/DoubleShow");
- // norm!(success_unit_DoubleShowValue, "unit/DoubleShowValue");
- norm!(success_unit_EmptyAlternative, "unit/EmptyAlternative");
- norm!(success_unit_FunctionApplicationCapture, "unit/FunctionApplicationCapture");
- norm!(success_unit_FunctionApplicationNoSubstitute, "unit/FunctionApplicationNoSubstitute");
- norm!(success_unit_FunctionApplicationNormalizeArguments, "unit/FunctionApplicationNormalizeArguments");
- norm!(success_unit_FunctionApplicationSubstitute, "unit/FunctionApplicationSubstitute");
- norm!(success_unit_FunctionNormalizeArguments, "unit/FunctionNormalizeArguments");
- norm!(success_unit_FunctionTypeNormalizeArguments, "unit/FunctionTypeNormalizeArguments");
- norm!(success_unit_IfAlternativesIdentical, "unit/IfAlternativesIdentical");
- norm!(success_unit_IfFalse, "unit/IfFalse");
- norm!(success_unit_IfNormalizePredicateAndBranches, "unit/IfNormalizePredicateAndBranches");
- norm!(success_unit_IfTrivial, "unit/IfTrivial");
- norm!(success_unit_IfTrue, "unit/IfTrue");
- norm!(success_unit_Integer, "unit/Integer");
- norm!(success_unit_IntegerNegative, "unit/IntegerNegative");
- norm!(success_unit_IntegerPositive, "unit/IntegerPositive");
- // norm!(success_unit_IntegerShow_12, "unit/IntegerShow-12");
- // norm!(success_unit_IntegerShow12, "unit/IntegerShow12");
- norm!(success_unit_IntegerShow, "unit/IntegerShow");
- // norm!(success_unit_IntegerToDouble_12, "unit/IntegerToDouble-12");
- // norm!(success_unit_IntegerToDouble12, "unit/IntegerToDouble12");
- norm!(success_unit_IntegerToDouble, "unit/IntegerToDouble");
- norm!(success_unit_Kind, "unit/Kind");
- norm!(success_unit_Let, "unit/Let");
- norm!(success_unit_LetWithType, "unit/LetWithType");
- norm!(success_unit_List, "unit/List");
- norm!(success_unit_ListBuild, "unit/ListBuild");
- norm!(success_unit_ListBuildFoldFusion, "unit/ListBuildFoldFusion");
- norm!(success_unit_ListBuildImplementation, "unit/ListBuildImplementation");
- norm!(success_unit_ListFold, "unit/ListFold");
- norm!(success_unit_ListFoldEmpty, "unit/ListFoldEmpty");
- norm!(success_unit_ListFoldOne, "unit/ListFoldOne");
- norm!(success_unit_ListHead, "unit/ListHead");
- norm!(success_unit_ListHeadEmpty, "unit/ListHeadEmpty");
- norm!(success_unit_ListHeadOne, "unit/ListHeadOne");
- norm!(success_unit_ListIndexed, "unit/ListIndexed");
- norm!(success_unit_ListIndexedEmpty, "unit/ListIndexedEmpty");
- norm!(success_unit_ListIndexedOne, "unit/ListIndexedOne");
- norm!(success_unit_ListLast, "unit/ListLast");
- norm!(success_unit_ListLastEmpty, "unit/ListLastEmpty");
- norm!(success_unit_ListLastOne, "unit/ListLastOne");
- norm!(success_unit_ListLength, "unit/ListLength");
- norm!(success_unit_ListLengthEmpty, "unit/ListLengthEmpty");
- norm!(success_unit_ListLengthOne, "unit/ListLengthOne");
- norm!(success_unit_ListNormalizeElements, "unit/ListNormalizeElements");
- norm!(success_unit_ListNormalizeTypeAnnotation, "unit/ListNormalizeTypeAnnotation");
- norm!(success_unit_ListReverse, "unit/ListReverse");
- norm!(success_unit_ListReverseEmpty, "unit/ListReverseEmpty");
- norm!(success_unit_ListReverseTwo, "unit/ListReverseTwo");
- norm!(success_unit_Merge, "unit/Merge");
- norm!(success_unit_MergeEmptyAlternative, "unit/MergeEmptyAlternative");
- norm!(success_unit_MergeNormalizeArguments, "unit/MergeNormalizeArguments");
- norm!(success_unit_MergeWithType, "unit/MergeWithType");
- norm!(success_unit_MergeWithTypeNormalizeArguments, "unit/MergeWithTypeNormalizeArguments");
- norm!(success_unit_Natural, "unit/Natural");
- norm!(success_unit_NaturalBuild, "unit/NaturalBuild");
- norm!(success_unit_NaturalBuildFoldFusion, "unit/NaturalBuildFoldFusion");
- norm!(success_unit_NaturalBuildImplementation, "unit/NaturalBuildImplementation");
- norm!(success_unit_NaturalEven, "unit/NaturalEven");
- norm!(success_unit_NaturalEvenOne, "unit/NaturalEvenOne");
- norm!(success_unit_NaturalEvenZero, "unit/NaturalEvenZero");
- norm!(success_unit_NaturalFold, "unit/NaturalFold");
- norm!(success_unit_NaturalFoldOne, "unit/NaturalFoldOne");
- norm!(success_unit_NaturalFoldZero, "unit/NaturalFoldZero");
- norm!(success_unit_NaturalIsZero, "unit/NaturalIsZero");
- norm!(success_unit_NaturalIsZeroOne, "unit/NaturalIsZeroOne");
- norm!(success_unit_NaturalIsZeroZero, "unit/NaturalIsZeroZero");
- norm!(success_unit_NaturalLiteral, "unit/NaturalLiteral");
- norm!(success_unit_NaturalOdd, "unit/NaturalOdd");
- norm!(success_unit_NaturalOddOne, "unit/NaturalOddOne");
- norm!(success_unit_NaturalOddZero, "unit/NaturalOddZero");
- norm!(success_unit_NaturalShow, "unit/NaturalShow");
- norm!(success_unit_NaturalShowOne, "unit/NaturalShowOne");
- norm!(success_unit_NaturalToInteger, "unit/NaturalToInteger");
- norm!(success_unit_NaturalToIntegerOne, "unit/NaturalToIntegerOne");
- norm!(success_unit_None, "unit/None");
- norm!(success_unit_NoneNatural, "unit/NoneNatural");
- norm!(success_unit_OperatorAndEquivalentArguments, "unit/OperatorAndEquivalentArguments");
- norm!(success_unit_OperatorAndLhsFalse, "unit/OperatorAndLhsFalse");
- norm!(success_unit_OperatorAndLhsTrue, "unit/OperatorAndLhsTrue");
- norm!(success_unit_OperatorAndNormalizeArguments, "unit/OperatorAndNormalizeArguments");
- norm!(success_unit_OperatorAndRhsFalse, "unit/OperatorAndRhsFalse");
- norm!(success_unit_OperatorAndRhsTrue, "unit/OperatorAndRhsTrue");
- norm!(success_unit_OperatorEqualEquivalentArguments, "unit/OperatorEqualEquivalentArguments");
- norm!(success_unit_OperatorEqualLhsTrue, "unit/OperatorEqualLhsTrue");
- norm!(success_unit_OperatorEqualNormalizeArguments, "unit/OperatorEqualNormalizeArguments");
- norm!(success_unit_OperatorEqualRhsTrue, "unit/OperatorEqualRhsTrue");
- norm!(success_unit_OperatorListConcatenateLhsEmpty, "unit/OperatorListConcatenateLhsEmpty");
- norm!(success_unit_OperatorListConcatenateListList, "unit/OperatorListConcatenateListList");
- norm!(success_unit_OperatorListConcatenateNormalizeArguments, "unit/OperatorListConcatenateNormalizeArguments");
- norm!(success_unit_OperatorListConcatenateRhsEmpty, "unit/OperatorListConcatenateRhsEmpty");
- norm!(success_unit_OperatorNotEqualEquivalentArguments, "unit/OperatorNotEqualEquivalentArguments");
- norm!(success_unit_OperatorNotEqualLhsFalse, "unit/OperatorNotEqualLhsFalse");
- norm!(success_unit_OperatorNotEqualNormalizeArguments, "unit/OperatorNotEqualNormalizeArguments");
- norm!(success_unit_OperatorNotEqualRhsFalse, "unit/OperatorNotEqualRhsFalse");
- norm!(success_unit_OperatorOrEquivalentArguments, "unit/OperatorOrEquivalentArguments");
- norm!(success_unit_OperatorOrLhsFalse, "unit/OperatorOrLhsFalse");
- norm!(success_unit_OperatorOrLhsTrue, "unit/OperatorOrLhsTrue");
- norm!(success_unit_OperatorOrNormalizeArguments, "unit/OperatorOrNormalizeArguments");
- norm!(success_unit_OperatorOrRhsFalse, "unit/OperatorOrRhsFalse");
- norm!(success_unit_OperatorOrRhsTrue, "unit/OperatorOrRhsTrue");
- norm!(success_unit_OperatorPlusLhsZero, "unit/OperatorPlusLhsZero");
- norm!(success_unit_OperatorPlusNormalizeArguments, "unit/OperatorPlusNormalizeArguments");
- norm!(success_unit_OperatorPlusOneAndOne, "unit/OperatorPlusOneAndOne");
- norm!(success_unit_OperatorPlusRhsZero, "unit/OperatorPlusRhsZero");
- norm!(success_unit_OperatorTextConcatenateLhsEmpty, "unit/OperatorTextConcatenateLhsEmpty");
- norm!(success_unit_OperatorTextConcatenateLhsNonEmpty, "unit/OperatorTextConcatenateLhsNonEmpty");
- norm!(success_unit_OperatorTextConcatenateTextText, "unit/OperatorTextConcatenateTextText");
- norm!(success_unit_OperatorTimesLhsOne, "unit/OperatorTimesLhsOne");
- norm!(success_unit_OperatorTimesLhsZero, "unit/OperatorTimesLhsZero");
- norm!(success_unit_OperatorTimesNormalizeArguments, "unit/OperatorTimesNormalizeArguments");
- norm!(success_unit_OperatorTimesRhsOne, "unit/OperatorTimesRhsOne");
- norm!(success_unit_OperatorTimesRhsZero, "unit/OperatorTimesRhsZero");
- norm!(success_unit_OperatorTimesTwoAndTwo, "unit/OperatorTimesTwoAndTwo");
- norm!(success_unit_Optional, "unit/Optional");
- norm!(success_unit_OptionalBuild, "unit/OptionalBuild");
- norm!(success_unit_OptionalBuildFoldFusion, "unit/OptionalBuildFoldFusion");
- norm!(success_unit_OptionalBuildImplementation, "unit/OptionalBuildImplementation");
- norm!(success_unit_OptionalFold, "unit/OptionalFold");
- norm!(success_unit_OptionalFoldNone, "unit/OptionalFoldNone");
- norm!(success_unit_OptionalFoldSome, "unit/OptionalFoldSome");
- norm!(success_unit_Record, "unit/Record");
- norm!(success_unit_RecordEmpty, "unit/RecordEmpty");
- norm!(success_unit_RecordProjection, "unit/RecordProjection");
- norm!(success_unit_RecordProjectionEmpty, "unit/RecordProjectionEmpty");
- norm!(success_unit_RecordProjectionNormalizeArguments, "unit/RecordProjectionNormalizeArguments");
- norm!(success_unit_RecordSelection, "unit/RecordSelection");
- norm!(success_unit_RecordSelectionNormalizeArguments, "unit/RecordSelectionNormalizeArguments");
- norm!(success_unit_RecordType, "unit/RecordType");
- norm!(success_unit_RecordTypeEmpty, "unit/RecordTypeEmpty");
- // norm!(success_unit_RecursiveRecordMergeCollision, "unit/RecursiveRecordMergeCollision");
- // norm!(success_unit_RecursiveRecordMergeLhsEmpty, "unit/RecursiveRecordMergeLhsEmpty");
- // norm!(success_unit_RecursiveRecordMergeNoCollision, "unit/RecursiveRecordMergeNoCollision");
- // norm!(success_unit_RecursiveRecordMergeNormalizeArguments, "unit/RecursiveRecordMergeNormalizeArguments");
- // norm!(success_unit_RecursiveRecordMergeRhsEmpty, "unit/RecursiveRecordMergeRhsEmpty");
- // norm!(success_unit_RecursiveRecordTypeMergeCollision, "unit/RecursiveRecordTypeMergeCollision");
- // norm!(success_unit_RecursiveRecordTypeMergeLhsEmpty, "unit/RecursiveRecordTypeMergeLhsEmpty");
- // norm!(success_unit_RecursiveRecordTypeMergeNoCollision, "unit/RecursiveRecordTypeMergeNoCollision");
- // norm!(success_unit_RecursiveRecordTypeMergeNormalizeArguments, "unit/RecursiveRecordTypeMergeNormalizeArguments");
- // norm!(success_unit_RecursiveRecordTypeMergeRhsEmpty, "unit/RecursiveRecordTypeMergeRhsEmpty");
- // norm!(success_unit_RecursiveRecordTypeMergeSorts, "unit/RecursiveRecordTypeMergeSorts");
- // norm!(success_unit_RightBiasedRecordMergeCollision, "unit/RightBiasedRecordMergeCollision");
- // norm!(success_unit_RightBiasedRecordMergeLhsEmpty, "unit/RightBiasedRecordMergeLhsEmpty");
- // norm!(success_unit_RightBiasedRecordMergeNoCollision, "unit/RightBiasedRecordMergeNoCollision");
- // norm!(success_unit_RightBiasedRecordMergeNormalizeArguments, "unit/RightBiasedRecordMergeNormalizeArguments");
- // norm!(success_unit_RightBiasedRecordMergeRhsEmpty, "unit/RightBiasedRecordMergeRhsEmpty");
- norm!(success_unit_SomeNormalizeArguments, "unit/SomeNormalizeArguments");
- norm!(success_unit_Sort, "unit/Sort");
- norm!(success_unit_Text, "unit/Text");
- norm!(success_unit_TextInterpolate, "unit/TextInterpolate");
- norm!(success_unit_TextLiteral, "unit/TextLiteral");
- norm!(success_unit_TextNormalizeInterpolations, "unit/TextNormalizeInterpolations");
- norm!(success_unit_TextShow, "unit/TextShow");
- // norm!(success_unit_TextShowAllEscapes, "unit/TextShowAllEscapes");
- norm!(success_unit_True, "unit/True");
- norm!(success_unit_Type, "unit/Type");
- norm!(success_unit_TypeAnnotation, "unit/TypeAnnotation");
- norm!(success_unit_UnionNormalizeAlternatives, "unit/UnionNormalizeAlternatives");
- norm!(success_unit_UnionNormalizeArguments, "unit/UnionNormalizeArguments");
- norm!(success_unit_UnionProjectConstructor, "unit/UnionProjectConstructor");
- norm!(success_unit_UnionSortAlternatives, "unit/UnionSortAlternatives");
- norm!(success_unit_UnionType, "unit/UnionType");
- norm!(success_unit_UnionTypeEmpty, "unit/UnionTypeEmpty");
- norm!(success_unit_UnionTypeNormalizeArguments, "unit/UnionTypeNormalizeArguments");
- norm!(success_unit_Variable, "unit/Variable");
-
- alpha_norm!(alpha_success_unit_FunctionBindingUnderscore, "unit/FunctionBindingUnderscore");
- alpha_norm!(alpha_success_unit_FunctionBindingX, "unit/FunctionBindingX");
- alpha_norm!(alpha_success_unit_FunctionNestedBindingX, "unit/FunctionNestedBindingX");
- alpha_norm!(alpha_success_unit_FunctionTypeBindingUnderscore, "unit/FunctionTypeBindingUnderscore");
- alpha_norm!(alpha_success_unit_FunctionTypeBindingX, "unit/FunctionTypeBindingX");
- alpha_norm!(alpha_success_unit_FunctionTypeNestedBindingX, "unit/FunctionTypeNestedBindingX");
-}