[sc-684] Disable forwarding of free vars in ask terms

This commit is contained in:
Nicolas Abril 2024-05-15 12:24:43 +02:00
parent 0ce59d9721
commit 3a6c746fd6
5 changed files with 33 additions and 13 deletions

View File

@ -1,7 +1,7 @@
use super::{parser::TermParser, Book, Name, Num, Pattern, Term};
use crate::maybe_grow;
const BUILTINS: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/fun/builtins.hvm"));
const BUILTINS: &str = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/fun/builtins.bend"));
pub const LIST: &str = "List";
pub const LCONS: &str = "List/cons";

View File

@ -1,6 +1,6 @@
use crate::{
diagnostics::Diagnostics,
fun::{Ctx, Name, Pattern, Term},
fun::{Ctx, Name, Term},
maybe_grow,
};
use std::collections::HashSet;
@ -41,15 +41,9 @@ impl Term {
let fun = make_fun_name(typ);
if def_names.contains(&fun) {
let mut fvs = nxt.free_vars();
pat.binds().flatten().for_each(|bind| _ = fvs.remove(bind));
let fvs = fvs.into_keys().collect::<Vec<_>>();
let nxt = fvs
.iter()
.fold(*nxt.clone(), |nxt, nam| Term::lam(Pattern::Var(Some(nam.clone())), nxt.clone()));
let nxt = Term::lam(*pat.clone(), nxt);
let term = Term::call(Term::Ref { nam: fun.clone() }, [*val.clone(), nxt]);
*self = Term::call(term, fvs.into_iter().map(|nam| Term::Var { nam }));
// TODO: come up with a strategy for forwarding free vars to prevent infinite recursion.
let nxt = Term::lam(*pat.clone(), std::mem::take(nxt));
*self = Term::call(Term::Ref { nam: fun.clone() }, [*val.clone(), nxt]);
} else {
return Err(format!("Could not find definition {} for type {}.", fun, typ));
}

View File

@ -2,4 +2,4 @@
source: tests/golden_tests.rs
input_file: examples/bitonic_sort.bend
---
523776
16515072

View File

@ -2,4 +2,30 @@
source: tests/golden_tests.rs
input_file: tests/golden_tests/run_file/recursive_bind.bend
---
λa (a 0)
Errors:
The following functions contain recursive cycles incompatible with HVM's strict evaluation:
* Foo -> Foo
The greedy eager evaluation of HVM may cause infinite loops.
Refactor these functions to use lazy references instead of direct function calls.
A reference is strict when it's being called ('(Foo x)') or when it's used non-linearly ('let x = Foo; (x x)').
It is lazy when it's an argument ('(x Foo)') or when it's used linearly ('let x = Foo; (x 0)').
Try one of these strategies:
- Use pattern matching with 'match', 'fold', and 'bend' to automatically lift expressions to lazy references.
- Replace direct calls with combinators. For example, change:
'Foo = λa λb (b (λc (Foo a c)) a)'
to:
'Foo = λa λb (b (λc λa (Foo a c)) (λa a) a)'
which is lifted to:
'Foo = λa λb (b Foo__C1 Foo_C2 a)'
- Replace non-linear 'let' expressions with 'use' expressions. For example, change:
'Foo = λf let x = Foo; (f x x)'
to:
'Foo = λf use x = Foo; (f x x)'
which inlines to:
'Foo = λf (f Foo Foo)'
- If disabled, re-enable the default 'float-combinators' and 'linearize-matches' compiler options.
For more information, visit: https://github.com/HigherOrderCO/hvm-lang/blob/main/docs/lazy-definitions.md.
To disable this check, use the "-Arecursion-cycle" compiler option.