├── .gitignore ├── LICENSE ├── README.md ├── elm-package.json └── src ├── Lazy.elm └── Native └── Lazy.js /.gitignore: -------------------------------------------------------------------------------- 1 | elm-stuff/ 2 | *~ 3 | *.html 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Max New 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | 1. Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the 14 | distribution. 15 | 16 | 3. Neither the name of the author nor the names of other 17 | contributors may be used to endorse or promote products derived 18 | from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project Moved 2 | 3 | Please direct all issues and pull requests to [this fork](https://github.com/elm-lang/lazy). 4 | -------------------------------------------------------------------------------- /elm-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.1.0", 3 | "summary": "Basic primitives for working with laziness", 4 | "repository": "http://github.com/maxsnew/lazy.git", 5 | "license": "BSD3", 6 | "source-directories": [ 7 | "src" 8 | ], 9 | "exposed-modules": [ 10 | "Lazy" 11 | ], 12 | "native-modules": true, 13 | "dependencies": { 14 | "elm-lang/core": "2.0.0 <= v < 4.0.0" 15 | }, 16 | "elm-version": "0.15.0 <= v < 0.17.0" 17 | } 18 | -------------------------------------------------------------------------------- /src/Lazy.elm: -------------------------------------------------------------------------------- 1 | module Lazy 2 | ( Lazy, force, lazy 3 | , map, map2, map3, map4, map5 4 | , apply, andThen 5 | ) 6 | where 7 | 8 | {-| This library lets you delay a computation until later. 9 | 10 | # Basics 11 | @docs Lazy, lazy, force 12 | 13 | # Mapping 14 | @docs map, map2, map3, map4, map5 15 | 16 | # Chaining 17 | @docs apply, andThen 18 | -} 19 | 20 | import Native.Lazy 21 | 22 | 23 | {-| A wrapper around a value that will be lazily evaluated. -} 24 | type Lazy a = Lazy (() -> a) 25 | 26 | {-| Delay the evaluation of a value until later. For example, maybe we will 27 | need to generate a very long list and find its sum, but we do not want to do 28 | it unless it is absolutely necessary. 29 | 30 | lazySum : Lazy Int 31 | lazySum = 32 | lazy (\() -> sum [1..1000000]) 33 | 34 | Now we only pay for `lazySum` if we actually need it. 35 | -} 36 | lazy : (() -> a) -> Lazy a 37 | lazy thunk = 38 | Lazy (Native.Lazy.memoize thunk) 39 | 40 | 41 | {-| Force the evaluation of a lazy value. This means we only pay for the 42 | computation when we need it. Here is a rather contrived example. 43 | 44 | lazySum : Lazy Int 45 | lazySum = 46 | lazy (\() -> List.sum [1..1000000]) 47 | 48 | sums : (Int, Int, Int) 49 | sums = 50 | (force lazySum, force lazySum, force lazySum) 51 | 52 | We are forcing this computation three times. The cool thing is that the first 53 | time you `force` a value, the result is stored. This means you pay the cost on 54 | the first one, but all the rest are very cheap, basically just looking up a 55 | value in memory. 56 | -} 57 | force : Lazy a -> a 58 | force (Lazy thunk) = 59 | thunk () 60 | 61 | 62 | {-| Lazily apply a function to a lazy value. 63 | 64 | lazySum : Lazy Int 65 | lazySum = 66 | map List.sum (lazy (\() -> [1..1000000])) 67 | 68 | The resulting lazy value will create a big list and sum it up when it is 69 | finally forced. 70 | -} 71 | map : (a -> b) -> Lazy a -> Lazy b 72 | map f a = 73 | lazy (\() -> f (force a)) 74 | 75 | 76 | {-| Lazily apply a function to two lazy values. 77 | 78 | lazySum : Lazy Int 79 | lazySum = 80 | lazy (\() -> List.sum [1..1000000]) 81 | 82 | lazySumPair : Lazy (Int, Int) 83 | lazySumPair = 84 | map2 (,) lazySum lazySum 85 | 86 | -} 87 | map2 : (a -> b -> result) -> Lazy a -> Lazy b -> Lazy result 88 | map2 f a b = 89 | lazy (\() -> f (force a) (force b)) 90 | 91 | 92 | {-|-} 93 | map3 : (a -> b -> c -> result) -> Lazy a -> Lazy b -> Lazy c -> Lazy result 94 | map3 f a b c = 95 | lazy (\() -> f (force a) (force b) (force c)) 96 | 97 | 98 | {-|-} 99 | map4 : (a -> b -> c -> d -> result) -> Lazy a -> Lazy b -> Lazy c -> Lazy d -> Lazy result 100 | map4 f a b c d = 101 | lazy (\() -> f (force a) (force b) (force c) (force d)) 102 | 103 | 104 | {-|-} 105 | map5 : (a -> b -> c -> d -> e -> result) -> Lazy a -> Lazy b -> Lazy c -> Lazy d -> Lazy e -> Lazy result 106 | map5 f a b c d e = 107 | lazy (\() -> f (force a) (force b) (force c) (force d) (force e)) 108 | 109 | 110 | {-| Lazily apply a lazy function to a lazy value. This is pretty rare on its 111 | own, but it lets you map as high as you want. 112 | 113 | map3 f a b == f `map` a `apply` b `apply` c 114 | 115 | It is not the most beautiful, but it is equivalent and will let you create 116 | `map9` quite easily if you really need it. 117 | -} 118 | apply : Lazy (a -> b) -> Lazy a -> Lazy b 119 | apply f x = 120 | lazy (\() -> (force f) (force x)) 121 | 122 | 123 | {-| Lazily chain together lazy computations, for when you have a series of 124 | steps that all need to be performed lazily. This can be nice when you need to 125 | pattern match on a value, for example, when appending lazy lists: 126 | 127 | type List a = Empty | Node a (Lazy (List a)) 128 | 129 | cons : a -> Lazy (List a) -> Lazy (List a) 130 | cons first rest = 131 | Lazy.map (Node first) rest 132 | 133 | append : Lazy (List a) -> Lazy (List a) -> Lazy (List a) 134 | append lazyList1 lazyList2 = 135 | lazyList1 136 | `andThen` \list1 -> 137 | case list1 of 138 | Empty -> 139 | lazyList2 140 | 141 | Node first rest -> 142 | cons first (append rest list2)) 143 | 144 | By using `andThen` we ensure that neither `lazyList1` or `lazyList2` are forced 145 | before they are needed. So as written, the `append` function delays the pattern 146 | matching until later. 147 | -} 148 | andThen : Lazy a -> (a -> Lazy b) -> Lazy b 149 | andThen a callback = 150 | lazy (\() -> force (callback (force a))) 151 | -------------------------------------------------------------------------------- /src/Native/Lazy.js: -------------------------------------------------------------------------------- 1 | Elm.Native.Lazy = {}; 2 | Elm.Native.Lazy.make = function(localRuntime) { 3 | 4 | localRuntime.Native = localRuntime.Native || {}; 5 | localRuntime.Native.Lazy = localRuntime.Native.Lazy || {}; 6 | if (localRuntime.Native.Lazy.values) { 7 | return localRuntime.Native.Lazy.values; 8 | } 9 | 10 | function memoize(thunk) { 11 | var value; 12 | var isForced = false; 13 | return function(tuple0) { 14 | if (!isForced) { 15 | value = thunk(tuple0); 16 | isForced = true; 17 | } 18 | return value; 19 | }; 20 | } 21 | 22 | return localRuntime.Native.Lazy.values = { 23 | memoize: memoize 24 | }; 25 | }; 26 | --------------------------------------------------------------------------------