-
Notifications
You must be signed in to change notification settings - Fork 41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Laziness #40
Comments
Interesting. Basically Nice idea! I have no strong opinion about adding this to the spec yet though. Very curious what others think. |
When I think of lazy evaluation in Javascript currying/partial application or function composition comes to my mind. However, I have difficulties to imagine how lazy evaluation with thunks is useful in the context of iterative functions. Here is a plain and simple example: const sequence = (n, acc) => () => n >= 0 ? sequence(n - 1, acc.concat(n)) : acc;
sequence(5, [])(); // ?
sequence(5, [])()()()()()()(); // [5,4,3,2,1,0] With |
It allows e.g. iteration to be stopped after a fixed point has been reached. Here is a self-contained example. Note that I'm writing the code here in a naïve, inefficient, way to make it clearer. As we are programming in an eager language, we need some explicit machinery to express laziness. Here is a kind of minimal vocabulary for laziness: // lazy :: (() -> a) -> Lazy a
const lazy = th => () => {
if (typeof th === "function")
th = {value: th()}
return th.value
}
// force :: Lazy a -> a
const force = delayed => delayed()
Here is a lazy monoid for computing disjunctions: const LazyOr = {
delay(th) {
return lazy(() => force(th()))
},
empty() {
return lazy(() => false)
},
concat(lhs, rhs) {
if (force(lhs))
return lhs
else
return rhs
}
} The implementation of type LazyOr = Lazy Bool and the type of delay :: (() -> LazyOr) -> LazyOr This explains the A monoid can be lifted to an applicative: function ConstOf(Monoid) {
const Const = {
map(_, x) {return x},
ap: Monoid.concat,
of(_) {return Monoid.empty()}
}
if (Monoid.delay)
Const.delay = Monoid.delay
return Const
} Here is the lazy traversal from the partial.lenses issue without Ramda: const traverse = (A, x2yA, xs) => A.delay(() =>
xs.length === 0
? A.of([])
: A.ap(A.map(x => xs => [x].concat(xs), x2yA(xs[0])),
traverse(A, x2yA, xs.slice(1)))) We can now use force(traverse(ConstOf(LazyOr),
x => (console.log(x), lazy(() => x > 3)),
[3, 1, 4, 1, 5, 9]))
// 3
// 1
// 4
// true |
@polytypic thanks for this in-depth reply. The sketch is impressing! I think e.g. purescript forgoes general lazy evaluation because with Javascript as compile target it gets pretty expensive. And directly encoded in Javascript the resulting code is somehow hard to read or at least looks unfamiliar. The crucial question is, what benefits entail with laziness that you can't achieve by other means. For instance, I use a special version of const foldlk = f => acc => xs => {
const next = (acc, i) => xs.length === i
? acc
: f(acc, xs[i], i) (acc => next(acc, i + 1));
return next(acc, 0);
};
const any = f => foldlk(
(acc, x) => k => f(x)
? true
: k(acc)
) (false);
const xs = [3, 1, 4, 1, 5, 9];
const gt = y => x => (console.log(x), x > y);
any(gt(3)) (xs); // 3, 1, 4, true |
Laziness can be useful with algebraic types. I recently implemented an experimental approach to laziness in my partial.lenses library. The idea is briefly discussed in issue 56.
The experimental approach used in partial.lenses is based on having an optional
delay
operation.Concretely, in the case of Monoids, the optional
delay
has a signature like:And in the case of Applicatives, the
delay
has a signature like:In some cases, it is possible to derive the
delay
operation from other operations. In the case of Monads:The support for laziness in partial.lenses is considered experimental partly due to not having the concept in the Static Land Specification. Perhaps Static Land could be enhanced with support for laziness?
Addition: The F# Computation Expression Zoo paper contains some relevant discussion on considerations for impure effects and delayed computations in a strict language in conjunction with algebraic types (mostly Monads).
The text was updated successfully, but these errors were encountered: