curry.toolchain.flat2icurry.setlift module
The set0 lift, a FlatCurry-to-FlatCurry pass over the FlatCurry file of a module (decision D28 of 2026-10-12).
set0 e is the set function of the expression e. When e holds
variables of the enclosing context (the captured variables), those
variables are arguments of the capsule, boxed at the entry as the arguments
of setk are: the set function of e is the set function of the
operation \v_1 .. v_p -> e applied to v_1 .. v_p, and the
non-determinism and the failure of a captured variable stay outside the
set, one set per outside alternative. That is the semantics of weakly
encapsulated search (Christiansen, Hanus, Reck and Seidel, PPDP 2013,
section 3.3): let x = coin in allValues x yields {0} and {1}, and
let x = failed in allValues x fails instead of yielding a set. The
implementations that scope by the time of the first evaluation (KiCS2,
PAKCS) are not the authority; the paper is.
The compiler, not the runtime, makes it so. The runtime boxes the
arguments a function value holds (set_step of
cyrt/currylib/setfunctions.cpp, set_ of the Python backend; issue
#117), so set1 (f x_1 .. x_(k-1)) x_k and setk f x_1 .. x_k reach
one entry state for any k, and this pass turns every saturated call
set0 e whose argument has captured variables x_1 .. x_k into that
call:
A new function
L x_1 .. x_k = e,Private, with the aritykand a fresh polymorphic typeforall a_0 .. a_k. a_0 -> .. -> a_k(the file is written to disk, and a reader of the file may read the type; the ICurry compiler ignores it). A type annotation at the root ofeis removed first: a root annotation over a let, a free declaration or a case meets a defect oficurry3.1.0 (seecompiler.to_iblock).The call becomes
setk L x_1 .. x_kforkup to seven, the arities the library has, andset1 (L x_1 .. x_(k-1)) x_kbeyond, which reaches the same entry state.
The captured variables are the variables e does not bind (the Curry
unboundVars), in the order of their first occurrence in e. A class
dictionary and a variable of a where .. free declaration outside e
are captured variables like any other, as they are arguments of a
lambda-lifted function. The pass runs bottom-up, so a set0 inside
e is lifted first, and it reaches every rule of the module, the lifted
lambdas of the front end (f._#lambdaN) and the bodies of lets and
cases included. set0 $ e is the call set0 e (the $ on a
partial application is reduced as the binding optimization reduces it).
The name of a lifted function is f_SET0n, where f is the local
name of the enclosing function and n counts from zero per enclosing
function; a name an original function of the module has is skipped, and
the counter still advances. The front end writes no such name
(f._#lambdaN, f.g.N, _impl#, _inst#, _super#,
_def#), and the case lifting of the translation
(caselifting, names f_CASEn, f_LETn, f_FREEn,
f_COMPLEXCASEn) runs after this pass over a program that holds the
lifted functions, whose names it skips. A lifted function has no entry
in the interface M.fint, which the pass never writes: it is private,
and the importers number the public functions of the module from that
file.
A closed set0 e (no captured variable) is unchanged: an encapsulated
expression, with no argument to box. A set0 that is not a saturated
call, a partial application such as map set0 xs or a set0 reached
through a variable, is left alone: the pass sees no argument there.
optimize_file() applies the pass to a FlatCurry file in place, as
bindingopt.optimize_file() applies the binding optimization; the
routes apply the two passes together (rewrite.rewrite_file()),
after the front end and before the translation, so the .fcy on disk
is the lifted program and both routes translate the same text. The pass
is idempotent: over a lifted program it lifts nothing and writes nothing.
- curry.toolchain.flat2icurry.setlift.captured_vars(e)[source]
The variables
edoes not bind (the CurryunboundVars), each once, in the order of their first occurrence in a left-to-right walk ofe: the arguments of a call in order, the bindings of a let before its body, the scrutinee of a case before its branches. A variable a let, a free declaration or a pattern ofebinds is left out under its binder. The walk keeps its own stack, so an expression of any depth needs no recursion.
- curry.toolchain.flat2icurry.setlift.contains_set0(e)[source]
Whether an expression holds a call or a partial application of
set0. The walk keeps its own stack.
- curry.toolchain.flat2icurry.setlift.is_lifted_name(name)[source]
Whether the local name
nameis the name of a lifted function.
- curry.toolchain.flat2icurry.setlift.lift_type(k)[source]
The type of a lifted function of arity
k: a fresh polymorphic scheme overk + 1type variables,forall a_0 .. a_k. a_0 -> .. -> a_k, written as the front end writes a scheme.
- curry.toolchain.flat2icurry.setlift.lifted_functions(prog)[source]
The qualified names of the lifted functions of a program.
- curry.toolchain.flat2icurry.setlift.optimize_file(fcyfile)[source]
Applies the set0 lift to the FlatCurry file
fcyfilein place. The file is written again, in the format of the front end, when the pass lifted a call; else it is left as it is, with its time. Returns the number of calls lifted.
- curry.toolchain.flat2icurry.setlift.optimize_set0(prog)[source]
Applies the set0 lift to a FlatCurry program. Returns the transformed program when a call was lifted, else
progitself.
- curry.toolchain.flat2icurry.setlift.set0_call(e)[source]
The saturated call
set0 e'thateis, or None. Two shapes count: the call itself, andset0 $ e'(a call of$on the partial applicationset0, which is reduced to the call). A partial application ofset0alone is no call.
- curry.toolchain.flat2icurry.setlift.strip_typed(e)[source]
The expression under any type annotations at the root.
- curry.toolchain.flat2icurry.setlift.transform_exp(state, e)[source]
Transforms an expression bottom-up: the subexpressions first, then the expression itself when it is a saturated call of
set0whose argument has captured variables. The walk runs on a stack of its own (utility.trampoline.trampoline()), so a nested application of any depth needs no recursion (issue #125).
- curry.toolchain.flat2icurry.setlift.transform_func(fd, names)[source]
Transforms a function declaration. Returns the declaration and the list of the functions lifted out of it.
namesis the set of the qualified names of the functions of the module, which the new names join. A rule without aset0, and one whose everyset0is closed or not a saturated call, is returned as it is.