├── .gitignore ├── README.md ├── elm-package.json ├── src ├── Mom │ ├── Option.elm │ ├── Either.elm │ ├── Always.elm │ └── Identity.elm └── Mom.elm └── examples └── Mom └── Examples.elm /.gitignore: -------------------------------------------------------------------------------- 1 | elm-stuff 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elm-mom 2 | 3 | Generalizes most computational effects. 4 | 5 | Continuations are very powerful. Powerful enough for most other data types to be implemented using them. This library explores the use of continuations to represent other data types. 6 | 7 | Based on ideas presented [here][1] and [here][2]. 8 | 9 | [1]: http://blog.sigfpe.com/2008/12/mother-of-all-monads.html 10 | [2]: http://fplab.bitbucket.org/posts/2007-12-09-continuations-and-classic.html 11 | -------------------------------------------------------------------------------- /elm-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "summary": "Generalizes most computational effects.", 4 | "repository": "https://github.com/joneshf/elm-mom.git", 5 | "license": "BSD3", 6 | "source-directories": [ 7 | "src" 8 | ], 9 | "exposed-modules": [ 10 | "Mom", 11 | "Mom.Always", 12 | "Mom.Either", 13 | "Mom.Identity", 14 | "Mom.Option" 15 | ], 16 | "dependencies": { 17 | "elm-lang/core": "4.0.1 <= v < 5.0.0" 18 | }, 19 | "elm-version": "0.17.0 <= v < 0.18.0" 20 | } 21 | -------------------------------------------------------------------------------- /src/Mom/Option.elm: -------------------------------------------------------------------------------- 1 | module Mom.Option exposing (..) 2 | 3 | {-| 4 | @docs Option 5 | @docs none, run, some 6 | -} 7 | 8 | import Mom exposing (..) 9 | 10 | {-| 11 | A computation that may fail with no information about the failure. 12 | -} 13 | type alias Option a = 14 | Mom (Maybe a) a 15 | 16 | {-| 17 | Run the computation extracting the value to `Maybe a`. 18 | -} 19 | run : Option a -> Maybe a 20 | run = 21 | with Just 22 | 23 | {-| 24 | A failed computation. 25 | -} 26 | none : Option a 27 | none = 28 | Mom (\_ -> Nothing) 29 | 30 | {-| 31 | A successful computation. 32 | -} 33 | some : a -> Option a 34 | some = 35 | pure 36 | -------------------------------------------------------------------------------- /src/Mom/Either.elm: -------------------------------------------------------------------------------- 1 | module Mom.Either exposing (..) 2 | 3 | {-| 4 | @docs Either 5 | @docs left, right, run 6 | -} 7 | 8 | import Mom exposing (..) 9 | 10 | {-| 11 | A computation that may fail with additional information about the failure. 12 | -} 13 | type alias Either a b = 14 | Mom (Result a b) b 15 | 16 | {-| 17 | Run the computation extracting the value to `Result a b`. 18 | -} 19 | run : Either a b -> Result a b 20 | run = 21 | with Ok 22 | 23 | {-| 24 | A failed computation. 25 | -} 26 | left : a -> Either a b 27 | left a = 28 | Mom (\_ -> Err a) 29 | 30 | {-| 31 | A successful computation. 32 | -} 33 | right : b -> Either a b 34 | right = 35 | pure 36 | -------------------------------------------------------------------------------- /src/Mom/Always.elm: -------------------------------------------------------------------------------- 1 | module Mom.Always exposing (Always, always, run) 2 | 3 | {-| 4 | @docs Always 5 | @docs always, run 6 | -} 7 | 8 | import Mom exposing (..) 9 | 10 | {-| 11 | A computation that never changes its value. 12 | -} 13 | type alias Always a b = 14 | Mom a b 15 | 16 | {-| 17 | Remove the value the computation. 18 | -} 19 | run : Always a b -> a 20 | run (Mom k) = 21 | let 22 | spin = spin 23 | in 24 | k spin 25 | 26 | {-| 27 | A value that never changes in the computation. 28 | 29 | Due to parametricity, this documentation is worthless, 30 | as there is exactly one implementation of this function. 31 | -} 32 | always : a -> Always a b 33 | always x = 34 | Mom (\_ -> x) 35 | -------------------------------------------------------------------------------- /src/Mom/Identity.elm: -------------------------------------------------------------------------------- 1 | module Mom.Identity exposing (..) 2 | 3 | {-| 4 | @docs Identity 5 | @docs identity, run 6 | -} 7 | 8 | import Mom exposing (..) 9 | 10 | {-| 11 | A computation with no effects. 12 | -} 13 | type alias Identity a = 14 | Mom a a 15 | 16 | {-| 17 | Remove the value the computation. 18 | 19 | Due to parametricity, this documentation is worthless, 20 | as there is exactly one implementation of this function. 21 | -} 22 | run : Identity a -> a 23 | run = 24 | with (\x -> x) 25 | 26 | {-| 27 | Alias for `pure`. 28 | 29 | Due to parametricity, this documentation is worthless, 30 | as there is exactly one implementation of this function. 31 | -} 32 | identity : a -> Identity a 33 | identity = 34 | \x -> Mom (\f -> f x) 35 | -------------------------------------------------------------------------------- /examples/Mom/Examples.elm: -------------------------------------------------------------------------------- 1 | module Mom.Examples exposing (..) 2 | 3 | import Mom exposing (..) 4 | import Mom.Either as ME exposing (..) 5 | import Mom.Identity as MI exposing (..) 6 | import Mom.Option as MO exposing (..) 7 | 8 | ex1 : Mom a Int 9 | ex1 = 10 | pure 1 >>= \a -> 11 | pure 10 >>= \b -> 12 | pure (a + b) 13 | 14 | test1 : String 15 | test1 = 16 | Mom.run ex1 toString 17 | 18 | ex2 : Mom a Int 19 | ex2 = 20 | pure 1 >>= \a -> 21 | Mom (\fred -> fred 10) >>= \b -> 22 | pure (a + b) 23 | 24 | test2 : String 25 | test2 = 26 | Mom.run ex2 toString 27 | 28 | ex3 : Mom String Int 29 | ex3 = 30 | pure 1 >>= \a -> 31 | Mom (\fred -> "escape") >>= \b -> 32 | pure (a + b) 33 | 34 | test3 : String 35 | test3 = 36 | Mom.run ex3 toString 37 | 38 | ex4 : Mom appendable Int 39 | ex4 = 40 | pure 1 >>= \a -> 41 | Mom (\fred -> fred 10 ++ fred 20) >>= \b -> 42 | pure (a + b) 43 | 44 | test4 : String 45 | test4 = 46 | Mom.run ex4 toString 47 | 48 | ex6 : Mom appendable Int 49 | ex6 = 50 | pure 1 >>= \a -> 51 | Mom (\fred -> fred 10 ++ fred 20) >>= \b -> 52 | pure (a + b) 53 | 54 | test6 : List Int 55 | test6 = 56 | Mom.run ex6 (\x -> [x]) 57 | 58 | ex7 : Mom (List a) Int 59 | ex7 = 60 | pure 1 >>= \a -> 61 | Mom (\fred -> List.concat [fred 10, fred 20]) >>= \b -> 62 | pure (a + b) 63 | 64 | test7 : List Int 65 | test7 = 66 | Mom.run ex7 (\x -> [x]) 67 | 68 | ex8 : Mom (List a) Int 69 | ex8 = 70 | pure 1 >>= \a -> 71 | Mom (\fred -> List.concatMap fred [10, 20]) >>= \b -> 72 | pure (a + b) 73 | 74 | test8 : List Int 75 | test8 = 76 | Mom.run ex8 (\x -> [x]) 77 | 78 | ex9 : Mom a Int 79 | ex9 = 80 | (+) <$> pure 3 <*> pure 4 81 | 82 | test9 : List Int 83 | test9 = 84 | Mom.run ex9 (\x -> [x]) 85 | 86 | nums1 : Mom a Int 87 | nums1 = 88 | pure 1 *> pure 2 *> pure 3 89 | 90 | nums2 : Mom a Int 91 | nums2 = 92 | pure 4 *> pure 5 *> pure 6 93 | 94 | ex10 : Mom a Int 95 | ex10 = 96 | (+) <$> nums1 <*> nums2 97 | 98 | test10 : List Int 99 | test10 = 100 | Mom.run ex10 (\x -> [x]) 101 | 102 | idEx1 : Identity Int 103 | idEx1 = 104 | ex1 105 | 106 | idTest1 : Int 107 | idTest1 = 108 | MI.run idEx1 109 | 110 | optionEx1 : Option Int 111 | optionEx1 = 112 | some 3 >>= \x -> 113 | some 4 >>= \y -> 114 | pure (x + y) 115 | 116 | optionTest1 : Maybe Int 117 | optionTest1 = 118 | MO.run optionEx1 119 | 120 | optionEx2 : Option Int 121 | optionEx2 = 122 | some 3 >>= \x -> 123 | none >>= \y -> 124 | pure (x + y) 125 | 126 | optionTest2 : Maybe Int 127 | optionTest2 = 128 | MO.run optionEx2 129 | 130 | genericSeven : Mom a Int 131 | genericSeven = 132 | pure 3 >>= \x -> 133 | pure 4 >>= \y -> 134 | pure (x + y) 135 | 136 | optionSeven : Option Int 137 | optionSeven = 138 | genericSeven 139 | 140 | length : List a -> Mom b Int 141 | length xs = 142 | pure (List.length xs) 143 | 144 | double : Int -> Mom a Int 145 | double n = 146 | pure (n * 2) 147 | 148 | doubleLength : Mom a Int 149 | doubleLength = 150 | length ['1', '2', '3'] >>= double 151 | 152 | eitherEx1 : Either String Int 153 | eitherEx1 = 154 | right 3 >>= \x -> 155 | right 4 >>= \y -> 156 | pure (x + y) 157 | 158 | eitherTest1 : Result String Int 159 | eitherTest1 = 160 | ME.run eitherEx1 161 | 162 | eitherEx2 : Either String Int 163 | eitherEx2 = 164 | right 3 >>= \x -> 165 | left "wat" >>= \y -> 166 | pure (x + y) 167 | 168 | eitherTest2 : Result String Int 169 | eitherTest2 = 170 | ME.run eitherEx2 171 | -------------------------------------------------------------------------------- /src/Mom.elm: -------------------------------------------------------------------------------- 1 | module Mom exposing (..) 2 | 3 | {-| 4 | @docs Mom 5 | @docs (#>), (*>), (<#>), (<$), (<$>), (<*), (<*>), (<=<), (=<<), (>=>), (>>=) 6 | @docs ap, bind, callCC, forever, join, map, pure, run, unless, when, with 7 | -} 8 | 9 | {-| 10 | Generalizes most computational effects. 11 | 12 | Based on ideas from http://blog.sigfpe.com/2008/12/mother-of-all-monads.html and http://fplab.bitbucket.org/posts/2007-12-09-continuations-and-classic.html 13 | -} 14 | type Mom r a 15 | = Mom ((a -> r) -> r) 16 | 17 | {-| 18 | Extracts the computational effects to the elm level. 19 | 20 | Due to parametricity, this documentation is worthless, 21 | as there is exactly one implementation of this function. 22 | -} 23 | run : Mom r a -> (a -> r) -> r 24 | run (Mom k) = 25 | k 26 | 27 | {-| 28 | Flipped version of `run` 29 | 30 | Due to parametricity, this documentation is worthless, 31 | as there is exactly one implementation of this function. 32 | -} 33 | with : (a -> r) -> Mom r a -> r 34 | with = 35 | flip run 36 | 37 | {-| 38 | Transforms values of a computational effect by the given function. 39 | 40 | Due to parametricity, this documentation is worthless, 41 | as there is exactly one implementation of this function. 42 | -} 43 | map : (a -> b) -> Mom r a -> Mom r b 44 | map f (Mom k) = 45 | Mom (\h -> k (\a -> h (f a))) 46 | 47 | {-| 48 | An operator alias for `map`. 49 | 50 | Due to parametricity, this documentation is worthless, 51 | as there is exactly one implementation of this function. 52 | -} 53 | (<$>) : (a -> b) -> Mom r a -> Mom r b 54 | (<$>) = 55 | map 56 | 57 | {-| 58 | Replaces values of a computational effect by the given function. 59 | 60 | Due to parametricity, this documentation is worthless, 61 | as there is exactly one implementation of this function. 62 | -} 63 | (<$) : b -> Mom r a -> Mom r b 64 | (<$) b = 65 | map (\_ -> b) 66 | 67 | {-| 68 | Flipped version of `(<$>)`. 69 | Pun with "dollar" and "pound". 70 | 71 | Due to parametricity, this documentation is worthless, 72 | as there is exactly one implementation of this function. 73 | -} 74 | (<#>) : Mom r a -> (a -> b) -> Mom r b 75 | (<#>) = 76 | flip map 77 | 78 | {-| 79 | Flipped version of `(<$)`. 80 | Pun with "dollar" and "pound". 81 | 82 | Due to parametricity, this documentation is worthless, 83 | as there is exactly one implementation of this function. 84 | -} 85 | (#>) : Mom r a -> b -> Mom r b 86 | (#>) = 87 | flip (<$) 88 | 89 | {-| 90 | Transforms values of a computational effect by the given function in the computational effect. 91 | 92 | Due to parametricity, this documentation is worthless, 93 | as there is exactly one implementation of this function. 94 | -} 95 | ap : Mom r (a -> b) -> Mom r a -> Mom r b 96 | ap (Mom k) (Mom h) = 97 | Mom (\j -> k (\f -> h (\a -> j (f a)))) 98 | 99 | {-| 100 | An operator alias for `ap`. 101 | 102 | Due to parametricity, this documentation is worthless, 103 | as there is exactly one implementation of this function. 104 | -} 105 | (<*>) : Mom r (a -> b) -> Mom r a -> Mom r b 106 | (<*>) = 107 | ap 108 | 109 | {-| 110 | Executes both computational effects ignoring the value of the second. 111 | -} 112 | (<*) : Mom r a -> Mom r b -> Mom r a 113 | (<*) k h = 114 | always <$> k <*> h 115 | 116 | {-| 117 | Executes both computational effects ignoring the value of the first. 118 | -} 119 | (*>) : Mom r a -> Mom r b -> Mom r b 120 | (*>) = 121 | flip (<*) 122 | 123 | {-| 124 | Embeds a pure value into an effectful computation. 125 | 126 | Due to parametricity, this documentation is worthless, 127 | as there is exactly one implementation of this function. 128 | -} 129 | pure : a -> Mom r a 130 | pure a = 131 | Mom (\f -> f a) 132 | 133 | {-| 134 | Substitues a value in an effectful computation. 135 | 136 | Due to parametricity, this documentation is worthless, 137 | as there is exactly one implementation of this function. 138 | -} 139 | bind : (a -> Mom r b) -> Mom r a -> Mom r b 140 | bind f (Mom k) = 141 | Mom (\h -> k (\a -> run (f a) h)) 142 | 143 | {-| 144 | Removes a layer of computational effects. 145 | 146 | Due to parametricity, this documentation is worthless, 147 | as there is exactly one implementation of this function. 148 | -} 149 | join : Mom r (Mom r a) -> Mom r a 150 | join = 151 | bind (\x -> x) 152 | 153 | {-| 154 | An operator alias for `bind`. 155 | 156 | Due to parametricity, this documentation is worthless, 157 | as there is exactly one implementation of this function. 158 | -} 159 | (=<<) : (a -> Mom r b) -> Mom r a -> Mom r b 160 | (=<<) = 161 | bind 162 | 163 | {-| 164 | Flipped version of `(=<<)`. 165 | 166 | Due to parametricity, this documentation is worthless, 167 | as there is exactly one implementation of this function. 168 | -} 169 | (>>=) : Mom r a -> (a -> Mom r b) -> Mom r b 170 | (>>=) = 171 | flip bind 172 | 173 | {-| 174 | Sequences two computational effect substitutions. 175 | 176 | Due to parametricity, this documentation is worthless, 177 | as there is exactly one implementation of this function. 178 | -} 179 | (>=>) : (a -> Mom r b) -> (b -> Mom r c) -> a -> Mom r c 180 | (>=>) f g a = 181 | f a >>= g 182 | 183 | {-| 184 | Flipped version of `(>=>)`. 185 | 186 | Due to parametricity, this documentation is worthless, 187 | as there is exactly one implementation of this function. 188 | -} 189 | (<=<) : (b -> Mom r c) -> (a -> Mom r b) -> a -> Mom r c 190 | (<=<) = 191 | flip (>=>) 192 | 193 | {-| 194 | Control flow primitive for effectful computations. 195 | 196 | Due to parametricity, this documentation is worthless, 197 | as there is exactly one implementation of this function. 198 | -} 199 | callCC : ((a -> Mom r b) -> Mom r a) -> Mom r a 200 | callCC f = 201 | Mom (\k -> run (f (\a -> Mom (\_ -> k a))) k) 202 | 203 | {-| 204 | Executes the effectful computation only when the `Bool` is true. 205 | -} 206 | when : Bool -> Mom r () -> Mom r () 207 | when b general = 208 | if b then 209 | general 210 | else 211 | pure () 212 | 213 | {-| 214 | Executes the effectful computation only when the `Bool` is false. 215 | -} 216 | unless : Bool -> Mom r () -> Mom r () 217 | unless b = 218 | when (not b) 219 | 220 | {-| 221 | Executes the effectful computation forever. 222 | -} 223 | forever : Mom r a -> Mom r b 224 | forever general = 225 | general *> forever general 226 | --------------------------------------------------------------------------------