forked from Orchid/orchid
Massive improvements across the board. One day I'll adopt incremental commits.
76 lines
2.3 KiB
Plaintext
76 lines
2.3 KiB
Plaintext
import super::procedural::*
|
|
import super::bool::*
|
|
import super::fn::(return, identity)
|
|
import super::known::*
|
|
|
|
--[
|
|
Bare fixpoint combinator. Due to its many pitfalls, usercode is
|
|
recommended to use one of the wrappers such as [recursive] or
|
|
[loop_over] instead.
|
|
]--
|
|
export const Y := \f.(\x.f (x x))(\x.f (x x))
|
|
|
|
--[
|
|
A syntax construct that encapsulates the Y combinator and encourages
|
|
single tail recursion. It's possible to use this for multiple or
|
|
non-tail recursion by using cps statements, but it's more ergonomic
|
|
than [Y] and more flexible than [std::list::fold].
|
|
|
|
To break out of the loop, use [std::fn::return] in a cps statement
|
|
]--
|
|
export macro loop_over (..$binds) {
|
|
...$body
|
|
} =0x5p129=> Y (\r.
|
|
def_binds parse_binds (..$binds) do{
|
|
...$body;
|
|
r apply_binds parse_binds (..$binds)
|
|
}
|
|
) init_binds parse_binds (..$binds)
|
|
|
|
-- parse_binds builds a conslist
|
|
macro parse_binds (...$item, ...$tail:1) =0x2p250=> (
|
|
parse_bind (...$item)
|
|
parse_binds (...$tail)
|
|
)
|
|
macro parse_binds (...$item) =0x1p250=> (
|
|
parse_bind (...$item)
|
|
()
|
|
)
|
|
|
|
-- while loop
|
|
export macro statement (
|
|
while ..$condition (..$binds) {
|
|
...$body
|
|
}
|
|
) $next =0x5p129=> loop_over (..$binds) {
|
|
cps if (..$condition) then identity else return $next;
|
|
...$body;
|
|
}
|
|
|
|
-- parse_bind converts items to pairs
|
|
macro parse_bind ($name) =0x1p250=> ($name bind_no_value)
|
|
macro parse_bind ($name = ...$value) =0x1p250=> ($name (...$value))
|
|
|
|
-- def_binds creates name bindings for everything
|
|
macro def_binds ( ($name $value) $tail ) ...$body =0x1p250=> (
|
|
\$name. def_binds $tail ...$body
|
|
)
|
|
macro def_binds () ...$body =0x1p250=> ...$body
|
|
|
|
-- init_binds passes the value for initializers
|
|
macro init_binds ( ($name bind_no_value) $tail ) =0x2p250=> $name init_binds $tail
|
|
macro init_binds ( ($name $value) $tail ) =0x1p250=> $value init_binds $tail
|
|
-- avoid empty templates by assuming that there is a previous token
|
|
macro $fn init_binds () =0x1p250=> $fn
|
|
|
|
-- apply_binds passes the name for initializers
|
|
macro apply_binds ( ($name $value) $tail ) =0x1p250=> $name apply_binds $tail
|
|
macro $fn apply_binds () =0x1p250=> $fn
|
|
|
|
--[
|
|
Alias for the Y-combinator to avoid some universal pitfalls
|
|
]--
|
|
export macro recursive $name (..$binds) ...$body =0x5p129=> Y (\$name.
|
|
def_binds parse_binds (..$binds) ...$body
|
|
) init_binds parse_binds (..$binds)
|