diff --git a/README.md b/README.md index cedf2f3..ec4ab12 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,43 @@ -# Laziness in Elm +# DEPRECATED -This package provides the basic primitives for working with laziness in Elm. +It turned out that many folks were unclear on the difference between laziness +and delayed computation: + - **Delayed Computation** is when you have a value like `answer : () -> Int` + that you can evaluate later. You only do all the computation when you say + `answer ()` at some later time. If you call `answer ()` four times, you do + the computation four times. -# Motivating Example + - **Laziness** is an optimization on top of delayed computation. It is just + like having `answer : () -> Int` but when this function is evaluated for the + first time, the results are saved. So if you call `answer ()` four times, you + do the computation *one* time. -Maybe you have 100 different graphs you want to show at various times, each -requiring a decent amount of computation. Here are a couple ways to handle -this: +In all the cases in Elm that I have heard of that use this library, folks only +really needed *delayed computation* and ended up with simpler code when they +went that way. - 1. Compute everything up front. This will introduce a delay on startup, but - it should be quite fast after that. Depending on how much memory is needed - to store each graph, you may be paying a lot there as well. +So in the end, there are two major reasons to stop supporting laziness: - 2. Compute each graph whenever you need it. This minimizes startup cost and - uses a minimal amount of memory, but when you are flipping between two - graphs you may be running the same computations again and again. + 1. It is overkill for all the scenarios I have seen in Elm. + 2. It allows the creation of cyclic data, significantly complicating GC. - 3. Compute each graph whenever you need it and save the result. Again, this - makes startup as fast as possible fast, but since we save the result, - flipping between graphs becomes much quicker. As we look at more graphs - we will need to use more and more memory though. +With laziness you can create a list like `ones = 1 :: ones` that refers to +itself. Without laziness, there is no way to create cyclic data in Elm. That +means we can use a naive reference counting approach to collect garbage if we +wanted. So although people have dreamed up data structures that use laziness +in interesting ways, I do not feel these cases are compelling enough to commit +to the collateral complications. -All of these strategies are useful in general, but the details of your -particular problem will mean that one of these ways provides the best -experience. This library makes it super easy to use strategy #3. +
+ +* * * + +What follows is some of content from the old README. + +* * * + +
# Pitfalls diff --git a/elm-package.json b/elm-package.json index 19bf77e..3543a47 100644 --- a/elm-package.json +++ b/elm-package.json @@ -1,7 +1,7 @@ { - "version": "1.1.0", + "version": "2.0.0", "summary": "Basic primitives for working with laziness", - "repository": "http://github.com/maxsnew/lazy.git", + "repository": "http://github.com/elm-lang/lazy.git", "license": "BSD3", "source-directories": [ "src" @@ -11,7 +11,7 @@ ], "native-modules": true, "dependencies": { - "elm-lang/core": "2.0.0 <= v < 4.0.0" + "elm-lang/core": "5.0.0 <= v < 6.0.0" }, - "elm-version": "0.15.0 <= v < 0.17.0" + "elm-version": "0.18.0 <= v < 0.19.0" } diff --git a/src/Lazy.elm b/src/Lazy.elm index a7e3bfb..008e512 100644 --- a/src/Lazy.elm +++ b/src/Lazy.elm @@ -1,9 +1,9 @@ -module Lazy - ( Lazy, force, lazy +module Lazy exposing + ( Lazy + , force, lazy , map, map2, map3, map4, map5 , apply, andThen ) - where {-| This library lets you delay a computation until later. @@ -20,8 +20,14 @@ module Lazy import Native.Lazy + +-- PRIMITIVES + + {-| A wrapper around a value that will be lazily evaluated. -} -type Lazy a = Lazy (() -> a) +type Lazy a = + Lazy (() -> a) + {-| Delay the evaluation of a value until later. For example, maybe we will need to generate a very long list and find its sum, but we do not want to do @@ -59,6 +65,10 @@ force (Lazy thunk) = thunk () + +-- COMPOSING LAZINESS + + {-| Lazily apply a function to a lazy value. lazySum : Lazy Int @@ -128,23 +138,27 @@ pattern match on a value, for example, when appending lazy lists: cons : a -> Lazy (List a) -> Lazy (List a) cons first rest = - Lazy.map (Node first) rest + Lazy.map (Node first) rest append : Lazy (List a) -> Lazy (List a) -> Lazy (List a) append lazyList1 lazyList2 = + let + appendHelp list1 = + case list1 of + Empty -> + lazyList2 + + Node first rest -> + cons first (append rest list2)) + in lazyList1 - `andThen` \list1 -> - case list1 of - Empty -> - lazyList2 + |> Lazy.andThen appendHelp - Node first rest -> - cons first (append rest list2)) By using `andThen` we ensure that neither `lazyList1` or `lazyList2` are forced before they are needed. So as written, the `append` function delays the pattern matching until later. -} -andThen : Lazy a -> (a -> Lazy b) -> Lazy b -andThen a callback = +andThen : (a -> Lazy b) -> Lazy a -> Lazy b +andThen callback a = lazy (\() -> force (callback (force a))) diff --git a/src/Native/Lazy.js b/src/Native/Lazy.js index 4f5502c..73fa1b0 100644 --- a/src/Native/Lazy.js +++ b/src/Native/Lazy.js @@ -1,25 +1,20 @@ -Elm.Native.Lazy = {}; -Elm.Native.Lazy.make = function(localRuntime) { +var _elm_lang$lazy$Native_Lazy = function() { - localRuntime.Native = localRuntime.Native || {}; - localRuntime.Native.Lazy = localRuntime.Native.Lazy || {}; - if (localRuntime.Native.Lazy.values) { - return localRuntime.Native.Lazy.values; - } - - function memoize(thunk) { - var value; - var isForced = false; - return function(tuple0) { - if (!isForced) { - value = thunk(tuple0); - isForced = true; - } - return value; - }; - } - - return localRuntime.Native.Lazy.values = { - memoize: memoize +function memoize(thunk) +{ + var value; + var isForced = false; + return function(tuple0) { + if (!isForced) { + value = thunk(tuple0); + isForced = true; + } + return value; }; +} + +return { + memoize: memoize }; + +}();