├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── bower.json ├── examples └── Simple.purs ├── generated-docs └── Elm │ ├── Apply.md │ ├── Array.md │ ├── Basics.md │ ├── Bind.md │ ├── Bitwise.md │ ├── Char.md │ ├── Color.md │ ├── Date.md │ ├── Debug.md │ ├── Default.md │ ├── Dict.md │ ├── Foldable.md │ ├── FunctorWithIndex.md │ ├── Json │ ├── Decode.md │ └── Encode.md │ ├── List.md │ ├── Maybe.md │ ├── Monoid.md │ ├── Platform.md │ ├── Platform │ ├── Cmd.md │ └── Sub.md │ ├── Process.md │ ├── Random.md │ ├── Regex.md │ ├── Result.md │ ├── Set.md │ ├── String.md │ ├── Task.md │ ├── Time.md │ ├── Trampoline.md │ ├── Transform2D.md │ └── Tuple.md ├── package.json ├── src └── Elm │ ├── Apply.purs │ ├── Array.purs │ ├── Basics.js │ ├── Basics.purs │ ├── Bind.purs │ ├── Bitwise.purs │ ├── Char.js │ ├── Char.purs │ ├── Color.purs │ ├── Date.js │ ├── Date.purs │ ├── Debug.purs │ ├── Default.purs │ ├── Dict.purs │ ├── Foldable.purs │ ├── FunctorWithIndex.purs │ ├── Json │ ├── Decode.js │ ├── Decode.purs │ ├── Encode.js │ └── Encode.purs │ ├── List.purs │ ├── Maybe.purs │ ├── Monoid.purs │ ├── Platform.purs │ ├── Platform │ ├── Cmd.purs │ └── Sub.purs │ ├── Process.purs │ ├── Random.js │ ├── Random.purs │ ├── Regex.js │ ├── Regex.purs │ ├── Result.purs │ ├── Set.purs │ ├── String.js │ ├── String.purs │ ├── Task.purs │ ├── Time.purs │ ├── Trampoline.purs │ ├── Transform2D.purs │ └── Tuple.purs └── test └── Test ├── Elm ├── Array.purs ├── Basics.purs ├── BasicsElm.purs ├── Bitwise.purs ├── Char.purs ├── Color.purs ├── Date.purs ├── Dict.purs ├── Json.purs ├── List.purs ├── ListElm.purs ├── Maybe.purs ├── Random.purs ├── Regex.purs ├── Result.purs ├── Set.purs ├── String.purs ├── Task.js ├── Task.purs ├── Time.purs └── Trampoline.purs └── Main.purs /.gitignore: -------------------------------------------------------------------------------- 1 | /bower_components/ 2 | /node_modules/ 3 | /.pulp-cache/ 4 | /output/ 5 | /.psci* 6 | /docs/ 7 | /**/.DS_Store 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | dist: trusty 3 | sudo: true 4 | node_js: 6 5 | env: 6 | - PATH=./node_modules/.bin:$PATH 7 | install: 8 | - npm install 9 | script: 10 | - pulp build -- --censor-lib 11 | - pulp test 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The original Elm modules upon which this work is based are subject to 2 | the following license. 3 | 4 | Copyright (c) 2014-present, Evan Czaplicki 5 | 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are met: 10 | 11 | * Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 14 | * Redistributions in binary form must reproduce the above 15 | copyright notice, this list of conditions and the following 16 | disclaimer in the documentation and/or other materials provided 17 | with the distribution. 18 | 19 | * Neither the name of Evan Czaplicki nor the names of other 20 | contributors may be used to endorse or promote products derived 21 | from this software without specific prior written permission. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 29 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 33 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 | 35 | ------ 36 | 37 | The Elm.Result module is substantially derived from Purescript's 38 | `Data.Either` module, which is subject to the following license: 39 | 40 | Copyright (c) 2014 PureScript 41 | 42 | Permission is hereby granted, free of charge, to any person obtaining a copy of 43 | this software and associated documentation files (the "Software"), to deal in 44 | the Software without restriction, including without limitation the rights to 45 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 46 | the Software, and to permit persons to whom the Software is furnished to do so, 47 | subject to the following conditions: 48 | 49 | The above copyright notice and this permission notice shall be included in all 50 | copies or substantial portions of the Software. 51 | 52 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 53 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 54 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 55 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 56 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 57 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 58 | 59 | ------ 60 | 61 | The original work involved in converting the modules to Purescript is 62 | subject to the following license. 63 | 64 | Copyright (c) 2016-2018 Ryan Rempel 65 | 66 | Permission is hereby granted, free of charge, to any person obtaining a copy of 67 | this software and associated documentation files (the "Software"), to deal in 68 | the Software without restriction, including without limitation the rights to 69 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 70 | the Software, and to permit persons to whom the Software is furnished to do so, 71 | subject to the following conditions: 72 | 73 | The above copyright notice and this permission notice shall be included in all 74 | copies or substantial portions of the Software. 75 | 76 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 77 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 78 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 79 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 80 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 81 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 82 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "purescript-pselm-core", 3 | "homepage": "https://github.com/pselm/core", 4 | "description": "Purescript implementation of Elm's `core` library", 5 | "license": "BSD3", 6 | "ignore": [ 7 | "**/.*", 8 | "node_modules", 9 | "bower_components", 10 | "examples", 11 | "generated-docs", 12 | "output" 13 | ], 14 | "dependencies": { 15 | "purescript-aff": "^4.0.0", 16 | "purescript-canvas": "^3.3.0", 17 | "purescript-colors": "^4.3.0", 18 | "purescript-datetime": "^3.0.0", 19 | "purescript-debug": "^3.0.0", 20 | "purescript-either": "^3.2.0", 21 | "purescript-foldable-traversable": "^3.6.1", 22 | "purescript-foreign": "^4.0.1", 23 | "purescript-foreign-generic": "^5.0.0", 24 | "purescript-int-53": "^3.0.0", 25 | "purescript-integers": "^3.2.0", 26 | "purescript-io": "^5.0.0", 27 | "purescript-js-date": "4 - 5", 28 | "purescript-js-timers": "^3.0.0", 29 | "purescript-leibniz": "^4.1.0", 30 | "purescript-lists": "^4.0.0", 31 | "purescript-maybe": "^3.0.0", 32 | "purescript-now": "^3.0.0", 33 | "purescript-orders": "^3.0.0", 34 | "purescript-partial": "^1.0.0", 35 | "purescript-prelude": "^3.0.0", 36 | "purescript-sequences": "^1.0.0", 37 | "purescript-sets": "^3.0.0", 38 | "purescript-strings": "^3.0.0", 39 | "purescript-unsafe-reference": "^2.0.0" 40 | }, 41 | "devDependencies": { 42 | "purescript-test-unit": "^13.0.0", 43 | "purescript-generics": "^4.0.0", 44 | "purescript-quickcheck-laws": "^3.0.0" 45 | }, 46 | "repository": { 47 | "type": "git", 48 | "url": "git://github.com/pselm/core.git" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/Simple.purs: -------------------------------------------------------------------------------- 1 | module Examples.Simple where 2 | 3 | 4 | import Elm.Default 5 | 6 | import Control.Monad.Aff (launchAff_) 7 | import Control.Monad.Aff.Class (liftAff) 8 | import Control.Monad.Aff.Console (logShow) 9 | import Control.Monad.Eff (Eff) 10 | import Control.Monad.IO (INFINITY, runIO) 11 | import Data.Tuple.Nested ((/\)) 12 | import Elm.Platform (program, runProgram) 13 | import Elm.Platform.Cmd as Cmd 14 | import Elm.Task (Task) 15 | import Elm.Task (perform) as Task 16 | import Elm.Time (Time) 17 | import Elm.Time (every) as Elm.Time 18 | import Prelude (class Show, Unit, unit, discard, ($), (<<<)) 19 | 20 | 21 | type Model = 22 | { counter :: Int 23 | , currentTime :: Time 24 | } 25 | 26 | 27 | emptyModel :: Model 28 | emptyModel = 29 | { counter : 0 30 | , currentTime : 0.0 31 | } 32 | 33 | 34 | data Msg 35 | = HandleTime Time 36 | | NoOp 37 | 38 | 39 | init :: Tuple Model (Cmd Msg) 40 | init = 41 | Tuple emptyModel Cmd.none 42 | 43 | 44 | update :: Msg -> Model -> Tuple Model (Cmd Msg) 45 | update msg model = 46 | case msg of 47 | HandleTime time -> 48 | model { currentTime = time } 49 | /\ Task.perform (always NoOp) (log time) 50 | 51 | NoOp -> 52 | model /\ Cmd.none 53 | 54 | 55 | subscriptions :: Model -> Sub Msg 56 | subscriptions model = 57 | Elm.Time.every 1000.0 HandleTime 58 | 59 | 60 | log :: ∀ x a. Show a => a -> Task x Unit 61 | log = liftAff <<< logShow 62 | 63 | 64 | main :: Eff (infinity :: INFINITY ) Unit 65 | main = 66 | launchAff_ $ runIO do 67 | liftAff $ logShow "About to launch Elm program!" 68 | runProgram unit $ 69 | program {init, update, subscriptions} 70 | -------------------------------------------------------------------------------- /generated-docs/Elm/Apply.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Apply 2 | 3 | Elm modules typically use `map2` through `map5` for what Purescript's 4 | `Apply` class would call `lift2` through `lift5`. 5 | 6 | So, we define `map2` through `map5` here as synonyms for `lift2` through 7 | `lift5`. We also re-export these in the individual Elm modules that use 8 | them, so that that the API matches with the Elm API. 9 | 10 | A few Elm modules use up to `map8`, so we implement those here as well. 11 | 12 | We also make `andMap` a synonym for Purescript's `apply`. 13 | 14 | #### `andMap` 15 | 16 | ``` purescript 17 | andMap :: forall a b f. Apply f => f (a -> b) -> f a -> f b 18 | ``` 19 | 20 | Map a function in a container to a value in a container. 21 | 22 | This is the equivalent of Purescript's `apply`. 23 | 24 | #### `map2` 25 | 26 | ``` purescript 27 | map2 :: forall w a b c. Apply w => (a -> b -> c) -> w a -> w b -> w c 28 | ``` 29 | 30 | Map a function of two arguments over some container type. 31 | 32 | The equivalent of Purescript's `lift2`. 33 | 34 | #### `map3` 35 | 36 | ``` purescript 37 | map3 :: forall w a b c d. Apply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d 38 | ``` 39 | 40 | Map a function of three arguments over some container type. 41 | 42 | The equivalent of Purescript's `lift3`. 43 | 44 | #### `map4` 45 | 46 | ``` purescript 47 | map4 :: forall w a b c d e. Apply w => (a -> b -> c -> d -> e) -> w a -> w b -> w c -> w d -> w e 48 | ``` 49 | 50 | Map a function of four arguments over some container type. 51 | 52 | The equivalent of Purescript's `lift4`. 53 | 54 | #### `map5` 55 | 56 | ``` purescript 57 | map5 :: forall w a b c d e f. Apply w => (a -> b -> c -> d -> e -> f) -> w a -> w b -> w c -> w d -> w e -> w f 58 | ``` 59 | 60 | Map a function of five arguments over some container type. 61 | 62 | The equivalent of Purescript's `lift5`. 63 | 64 | #### `map6` 65 | 66 | ``` purescript 67 | map6 :: forall w a b c d e f g. Apply w => (a -> b -> c -> d -> e -> f -> g) -> w a -> w b -> w c -> w d -> w e -> w f -> w g 68 | ``` 69 | 70 | Map a function of six arguments over some container type. 71 | 72 | #### `map7` 73 | 74 | ``` purescript 75 | map7 :: forall w a b c d e f g h. Apply w => (a -> b -> c -> d -> e -> f -> g -> h) -> w a -> w b -> w c -> w d -> w e -> w f -> w g -> w h 76 | ``` 77 | 78 | Map a function of seven arguments over some container type. 79 | 80 | #### `map8` 81 | 82 | ``` purescript 83 | map8 :: forall w a b c d e f g h i. Apply w => (a -> b -> c -> d -> e -> f -> g -> h -> i) -> w a -> w b -> w c -> w d -> w e -> w f -> w g -> w h -> w i 84 | ``` 85 | 86 | Map a function of eight arguments over some container type. 87 | 88 | 89 | -------------------------------------------------------------------------------- /generated-docs/Elm/Array.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Array 2 | 3 | > A library for fast immutable arrays. The elements in an array must have the 4 | > same type. 5 | 6 | This is based on the Purescript `Data.Sequence` package -- an `Array` is a 7 | `Data.Sequence.Seq`, so you can use additional functions from that package 8 | as well. 9 | 10 | Note that the Purescript primitive `Array` type is something different -- 11 | it is actually a Javascript array. So, if you're importing this unqualified, 12 | you'll probably need to do something like: 13 | 14 | import Prim hiding (Array) 15 | 16 | to avoid an ambiguity. 17 | 18 | #### `Array` 19 | 20 | ``` purescript 21 | type Array = Seq 22 | ``` 23 | 24 | The `Array` type is synonym for `Data.Sequence.Seq`. 25 | 26 | #### `fromList` 27 | 28 | ``` purescript 29 | fromList :: forall f a. Foldable f => f a -> Array a 30 | ``` 31 | 32 | > Create an array from a list. 33 | 34 | Note that this actually works with any `Foldable`. 35 | 36 | #### `toList` 37 | 38 | ``` purescript 39 | toList :: forall f a. Functor f => Unfoldable f => Array a -> f a 40 | ``` 41 | 42 | > Create a list of elements from an array. 43 | > 44 | > toList (fromList [3,5,8]) == [3,5,8] 45 | 46 | Note that this actually works with any type that is both a 47 | `Functor` and an `Unfoldable`. 48 | 49 | #### `toIndexedList` 50 | 51 | ``` purescript 52 | toIndexedList :: forall f a. Applicative f => Monoid (f (Tuple Int a)) => Array a -> f (Tuple Int a) 53 | ``` 54 | 55 | > Create an indexed list from an array. Each element of the array will be 56 | > paired with its index. 57 | > 58 | > toIndexedList (fromList ["cat","dog"]) == [Tuple 0 "cat", Tuple 1 "dog"] 59 | 60 | The container in the return type is defined polymorphically to accommodate 61 | `List` and Purescript's `Array`, among others. 62 | 63 | #### `repeat` 64 | 65 | ``` purescript 66 | repeat :: forall a. Int -> a -> Array a 67 | ``` 68 | 69 | > Creates an array with a given length, filled with a default element. 70 | > 71 | > repeat 5 0 == fromList [0,0,0,0,0] 72 | > repeat 3 "cat" == fromList ["cat","cat","cat"] 73 | > 74 | > Notice that `repeat 3 x` is the same as `initialize 3 (always x)`. 75 | 76 | #### `push` 77 | 78 | ``` purescript 79 | push :: forall a. a -> Array a -> Array a 80 | ``` 81 | 82 | > Push an element to the end of an array. 83 | > 84 | > push 3 (fromList [1,2]) == fromList [1,2,3] 85 | 86 | Equivalent to Purescript's `snoc`, but with the arguments flipped. 87 | 88 | #### `get` 89 | 90 | ``` purescript 91 | get :: forall a. Int -> Array a -> Maybe a 92 | ``` 93 | 94 | > Return Just the element at the index or Nothing if the index is out of range. 95 | > 96 | > get 0 (fromList [0,5,3]) == Just 0 97 | > get 2 (fromList [0,5,3]) == Just 3 98 | > get 5 (fromList [0,5,3]) == Nothing 99 | > get -1 (fromList [0,5,3]) == Nothing 100 | 101 | Equivalent to Purescript's `index`. 102 | 103 | #### `set` 104 | 105 | ``` purescript 106 | set :: forall a. Int -> a -> Array a -> Array a 107 | ``` 108 | 109 | > Set the element at a particular index. Returns an updated array. 110 | > If the index is out of range, the array is unaltered. 111 | > 112 | > set 1 7 (fromList [1,2,3]) == fromList [1,7,3] 113 | 114 | Equivalent to Purescript's `replace`, but with the arguments flipped. 115 | 116 | #### `slice` 117 | 118 | ``` purescript 119 | slice :: forall a. Int -> Int -> Array a -> Array a 120 | ``` 121 | 122 | > Get a sub-section of an array: `(slice start end array)`. The `start` is a 123 | > zero-based index where we will start our slice. The `end` is a zero-based index 124 | > that indicates the end of the slice. The slice extracts up to but not including 125 | > `end`. 126 | > 127 | > slice 0 3 (fromList [0,1,2,3,4]) == fromList [0,1,2] 128 | > slice 1 4 (fromList [0,1,2,3,4]) == fromList [1,2,3] 129 | > 130 | > Both the `start` and `end` indexes can be negative, indicating an offset from 131 | > the end of the array. 132 | > 133 | > slice 1 -1 (fromList [0,1,2,3,4]) == fromList [1,2,3] 134 | > slice -2 5 (fromList [0,1,2,3,4]) == fromList [3,4] 135 | > 136 | > This makes it pretty easy to `pop` the last element off of an array: `slice 0 -1 array` 137 | 138 | #### `indexedMap` 139 | 140 | ``` purescript 141 | indexedMap :: forall a b. (Int -> a -> b) -> Array a -> Array b 142 | ``` 143 | 144 | > Apply a function on every element with its index as first argument. 145 | > 146 | > indexedMap (*) (fromList [5,5,5]) == fromList [0,5,10] 147 | 148 | #### `initialize` 149 | 150 | ``` purescript 151 | initialize :: forall a. Int -> (Int -> a) -> Array a 152 | ``` 153 | 154 | > Initialize an array. `initialize n f` creates an array of length `n` with 155 | > the element at index `i` initialized to the result of `(f i)`. 156 | > 157 | > initialize 4 identity == fromList [0,1,2,3] 158 | > initialize 4 (\n -> n*n) == fromList [0,1,4,9] 159 | > initialize 4 (always 0) == fromList [0,0,0,0] 160 | 161 | 162 | ### Re-exported from Data.Array: 163 | 164 | #### `foldr` 165 | 166 | ``` purescript 167 | foldr :: forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b 168 | ``` 169 | 170 | ### Re-exported from Data.Sequence: 171 | 172 | #### `length` 173 | 174 | ``` purescript 175 | length :: forall a. Seq a -> Int 176 | ``` 177 | 178 | O(1). The number of elements in the sequence. 179 | 180 | #### `filter` 181 | 182 | ``` purescript 183 | filter :: forall a. (a -> Boolean) -> Seq a -> Seq a 184 | ``` 185 | 186 | O(n). Create a new Seq which contains only those elements of the input 187 | Seq which satisfy the given predicate. 188 | 189 | #### `empty` 190 | 191 | ``` purescript 192 | empty :: forall a. Seq a 193 | ``` 194 | 195 | A sequence with no elements. 196 | 197 | ### Re-exported from Elm.Foldable: 198 | 199 | #### `foldl` 200 | 201 | ``` purescript 202 | foldl :: forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b 203 | ``` 204 | 205 | Reduce a container from the left. 206 | 207 | Equivalent to Purescript's `foldl`, but the function you supply is flipped. 208 | 209 | ### Re-exported from Prelude: 210 | 211 | #### `append` 212 | 213 | ``` purescript 214 | append :: forall a. Semigroup a => a -> a -> a 215 | ``` 216 | 217 | #### `map` 218 | 219 | ``` purescript 220 | map :: forall a b f. Functor f => (a -> b) -> f a -> f b 221 | ``` 222 | 223 | -------------------------------------------------------------------------------- /generated-docs/Elm/Bind.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Bind 2 | 3 | Elm modules typically use `andThen` for what Purescript would call `bind`. 4 | We define the synomyn here generically so that we don't have to define the 5 | function multiple times. And, we can re-export it (as Elm code expects) 6 | without producing conflicts, since it's all the same function. 7 | 8 | #### `andThen` 9 | 10 | ``` purescript 11 | andThen :: forall m a b. Bind m => (a -> m b) -> m a -> m b 12 | ``` 13 | 14 | Given some computation, chain its result with another computation. 15 | 16 | Equivalent to Purescript's `bind`. 17 | 18 | The order of the arguments was flipped in Elm 0.18. 19 | 20 | 21 | -------------------------------------------------------------------------------- /generated-docs/Elm/Bitwise.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Bitwise 2 | 3 | > Library for [bitwise operations](http://en.wikipedia.org/wiki/Bitwise_operation) 4 | 5 | Implemented using Purescript's [`Data.Int.Bits`](https://pursuit.purescript.org/packages/purescript-integers) module. 6 | 7 | #### `and` 8 | 9 | ``` purescript 10 | and :: Int -> Int -> Int 11 | ``` 12 | 13 | > Bitwise AND 14 | 15 | Equivalent to Purescript's `(.&.)` 16 | 17 | #### `or` 18 | 19 | ``` purescript 20 | or :: Int -> Int -> Int 21 | ``` 22 | 23 | > Bitwise OR 24 | 25 | Equivalent to Purescript's `(.|.)` 26 | 27 | #### `xor` 28 | 29 | ``` purescript 30 | xor :: Int -> Int -> Int 31 | ``` 32 | 33 | > Bitwise XOR 34 | 35 | Equivalent to Purescript's `(.^.)` 36 | 37 | #### `shiftLeft` 38 | 39 | ``` purescript 40 | shiftLeft :: Int -> Int -> Int 41 | ``` 42 | 43 | > Shift bits to the left by a given offset, filling new bits with zeros. 44 | > This can be used to multiply numbers by powers of two. 45 | > 46 | > 8 `shiftLeft` 1 == 16 47 | > 8 `shiftLeft` 2 == 32 48 | 49 | Equivalent to Purescript's `shl` 50 | 51 | This function was removed in Elm 0.18, in favour of `shiftLeftBy`, 52 | which has its arguments flipped. 53 | 54 | #### `shiftRight` 55 | 56 | ``` purescript 57 | shiftRight :: Int -> Int -> Int 58 | ``` 59 | 60 | > Shift bits to the right by a given offset, filling new bits with 61 | > whatever is the topmost bit. This can be used to divide numbers by powers of two. 62 | > 63 | > 32 `shiftRight` 1 == 16 64 | > 32 `shiftRight` 2 == 8 65 | > -32 `shiftRight` 1 == -16 66 | > 67 | > This is called an 68 | > [arithmetic right shift](http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift), 69 | > often written (>>), and sometimes called a sign-propagating 70 | > right shift because it fills empty spots with copies of the highest bit. 71 | 72 | Equivalent to Purescript's `shr` 73 | 74 | This function was removed in Elm 0.18, in favour of `shiftRightBy`, 75 | which has its arguments flipped. 76 | 77 | #### `shiftRightLogical` 78 | 79 | ``` purescript 80 | shiftRightLogical :: Int -> Int -> Int 81 | ``` 82 | 83 | > Shift bits to the right by a given offset, filling new bits with 84 | > zeros. 85 | > 86 | > 32 `shiftRightLogical` 1 == 16 87 | > 32 `shiftRightLogical` 2 == 8 88 | > -32 `shiftRightLogical` 1 == 2147483632 89 | > 90 | > This is called an 91 | > [logical right shift](http://en.wikipedia.org/wiki/Bitwise_operation#Logical_shift), 92 | > often written (>>>), and sometimes called a zero-fill right shift because 93 | > it fills empty spots with zeros. 94 | 95 | Equivalent to Purescript's `zshr`. 96 | 97 | This function was removed in Elm 0.18, in favour of `shiftRightZfBy`, 98 | which has its arguments flipped. 99 | 100 | #### `shiftLeftBy` 101 | 102 | ``` purescript 103 | shiftLeftBy :: Int -> Int -> Int 104 | ``` 105 | 106 | > Shift bits to the left by a given offset, filling new bits with zeros. 107 | > This can be used to multiply numbers by powers of two. 108 | > 109 | > shiftLeftBy 1 5 == 10 110 | > shiftLeftBy 5 1 == 32 111 | 112 | Equivalent to Purescript's `shl`, but with the arguemnts flipped. 113 | 114 | This function was introduced in Elm 0.18. 115 | 116 | #### `shiftRightBy` 117 | 118 | ``` purescript 119 | shiftRightBy :: Int -> Int -> Int 120 | ``` 121 | 122 | > Shift bits to the right by a given offset, filling new bits with 123 | > whatever is the topmost bit. This can be used to divide numbers by powers of two. 124 | > 125 | > shiftRightBy 1 32 == 16 126 | > shiftRightBy 2 32 == 8 127 | > shiftRightBy 1 -32 == -16 128 | > 129 | > This is called an 130 | > [arithmetic right shift](http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift), 131 | > often written (>>), and sometimes called a sign-propagating 132 | > right shift because it fills empty spots with copies of the highest bit. 133 | 134 | Equivalent to Purescript's `shr`, but with the arguments flipped. 135 | 136 | This function was introduced in Elm 0.18. 137 | 138 | #### `shiftRightZfBy` 139 | 140 | ``` purescript 141 | shiftRightZfBy :: Int -> Int -> Int 142 | ``` 143 | 144 | > Shift bits to the right by a given offset, filling new bits with 145 | > zeros. 146 | > 147 | > shiftRightZfBy 1 32 == 16 148 | > shiftRightZfBy 2 32 == 8 149 | > shiftRightZfBy 1 -32 == 2147483632 150 | > 151 | > This is called an 152 | > [logical right shift](http://en.wikipedia.org/wiki/Bitwise_operation#Logical_shift), 153 | > often written (>>>), and sometimes called a zero-fill right shift because 154 | > it fills empty spots with zeros. 155 | 156 | Equivalent to Purescript's `zshr`, but with its arguments flipped. 157 | 158 | This function was added in Elm 0.18. 159 | 160 | 161 | ### Re-exported from Data.Int.Bits: 162 | 163 | #### `complement` 164 | 165 | ``` purescript 166 | complement :: Int -> Int 167 | ``` 168 | 169 | Bitwise NOT. 170 | 171 | -------------------------------------------------------------------------------- /generated-docs/Elm/Char.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Char 2 | 3 | > Functions for working with characters. Character literals are enclosed in 4 | > `'a'` pair of single quotes. 5 | 6 | Implemented using Purescript's [`Data.Char`](https://pursuit.purescript.org/packages/purescript-strings) module. 7 | 8 | #### `KeyCode` 9 | 10 | ``` purescript 11 | type KeyCode = Int 12 | ``` 13 | 14 | > Keyboard keys can be represented as integers. These are called *key codes*. 15 | > You can use [`toCode`](#toCode) and [`fromCode`](#fromCode) to convert between 16 | > key codes and characters. 17 | 18 | #### `toCode` 19 | 20 | ``` purescript 21 | toCode :: Char -> KeyCode 22 | ``` 23 | 24 | > Convert to key code. 25 | 26 | #### `fromCode` 27 | 28 | ``` purescript 29 | fromCode :: KeyCode -> Char 30 | ``` 31 | 32 | > Convert from key code. 33 | 34 | #### `isUpper` 35 | 36 | ``` purescript 37 | isUpper :: Char -> Bool 38 | ``` 39 | 40 | > True for upper case ASCII letters. 41 | 42 | #### `isLower` 43 | 44 | ``` purescript 45 | isLower :: Char -> Bool 46 | ``` 47 | 48 | > True for lower case ASCII letters. 49 | 50 | #### `isDigit` 51 | 52 | ``` purescript 53 | isDigit :: Char -> Bool 54 | ``` 55 | 56 | > True for ASCII digits `[0-9]`. 57 | 58 | #### `isOctDigit` 59 | 60 | ``` purescript 61 | isOctDigit :: Char -> Bool 62 | ``` 63 | 64 | > True for ASCII octal digits `[0-7]`. 65 | 66 | #### `isHexDigit` 67 | 68 | ``` purescript 69 | isHexDigit :: Char -> Bool 70 | ``` 71 | 72 | > True for ASCII hexadecimal digits `[0-9a-fA-F]`. 73 | 74 | #### `toLocaleUpper` 75 | 76 | ``` purescript 77 | toLocaleUpper :: Char -> Char 78 | ``` 79 | 80 | > Convert to upper case, according to any locale-specific case mappings. 81 | 82 | #### `toLocaleLower` 83 | 84 | ``` purescript 85 | toLocaleLower :: Char -> Char 86 | ``` 87 | 88 | > Convert to lower case, according to any locale-specific case mappings. 89 | 90 | 91 | ### Re-exported from Data.Char: 92 | 93 | #### `toUpper` 94 | 95 | ``` purescript 96 | toUpper :: Char -> Char 97 | ``` 98 | 99 | Converts a character to uppercase. 100 | 101 | #### `toLower` 102 | 103 | ``` purescript 104 | toLower :: Char -> Char 105 | ``` 106 | 107 | Converts a character to lowercase. 108 | 109 | -------------------------------------------------------------------------------- /generated-docs/Elm/Date.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Date 2 | 3 | > Library for working with dates. 4 | 5 | See notes below about the types used for `Date`, `Day` and `Month`. 6 | 7 | #### `Date` 8 | 9 | ``` purescript 10 | type Date = JSDate 11 | ``` 12 | 13 | Elm's `Date` type is implemented here in terms of Purescript's `JSDate`, 14 | which, in both cases, is a Javascript Date object. 15 | 16 | #### `fromString` 17 | 18 | ``` purescript 19 | fromString :: String -> Result String Date 20 | ``` 21 | 22 | Attempt to read a date from a string. 23 | 24 | #### `Time` 25 | 26 | ``` purescript 27 | type Time = Number 28 | ``` 29 | 30 | An alias for units of time, representing milliseconds. 31 | 32 | #### `toTime` 33 | 34 | ``` purescript 35 | toTime :: Date -> Time 36 | ``` 37 | 38 | > Convert a `Date` to a time in milliseconds. 39 | > 40 | > A time is the number of milliseconds since 41 | > [the Unix epoch](http://en.wikipedia.org/wiki/Unix_time). 42 | 43 | #### `fromTime` 44 | 45 | ``` purescript 46 | fromTime :: Time -> Date 47 | ``` 48 | 49 | > Convert a time in milliseconds into a `Date`. 50 | > 51 | > A time is the number of milliseconds since 52 | > [the Unix epoch](http://en.wikipedia.org/wiki/Unix_time). 53 | 54 | #### `Day` 55 | 56 | ``` purescript 57 | type Day = Weekday 58 | ``` 59 | 60 | Elm's `Day` type is equivalent to `Weekday` in Purescript. 61 | 62 | However, note that in Purescript the constructors spell out the name of the day 63 | ... i.e. `Saturday` instead of `Sat`. 64 | 65 | #### `year` 66 | 67 | ``` purescript 68 | year :: Date -> Int 69 | ``` 70 | 71 | > Extract the year of a given date. Given the date 23 June 1990 at 11:45AM 72 | > this returns the integer `1990`. 73 | 74 | As in the Elm implementation, this implicitly uses the current locale. 75 | 76 | #### `month` 77 | 78 | ``` purescript 79 | month :: Date -> Month 80 | ``` 81 | 82 | > Extract the month of a given date. Given the date 23 June 1990 at 11:45AM 83 | > this returns the month `June` as defined below. 84 | 85 | Note that in Purescript, the constructors for `Month` are fully spelled out, 86 | so it is 'June` instead of `Jun`. 87 | 88 | As in the Elm implementation, this implicitly uses the current locale. 89 | 90 | #### `day` 91 | 92 | ``` purescript 93 | day :: Date -> Int 94 | ``` 95 | 96 | > Extract the day of a given date. Given the date 23 June 1990 at 11:45AM 97 | > this returns the integer `23`. 98 | 99 | As in the Elm implementation, this implicitly uses the current locale. 100 | 101 | #### `dayOfWeek` 102 | 103 | ``` purescript 104 | dayOfWeek :: Date -> Day 105 | ``` 106 | 107 | > Extract the day of the week for a given date. Given the date 23 June 108 | > 1990 at 11:45AM this returns the day `Saturday` as defined below. 109 | 110 | Note that in Purescript, the days of the week are fully spelled out, 111 | so it is `Thursday` instead of `Thu`. 112 | 113 | As in the Elm implementation, this implicitly uses the current locale. 114 | 115 | #### `hour` 116 | 117 | ``` purescript 118 | hour :: Date -> Int 119 | ``` 120 | 121 | > Extract the hour of a given date. Given the date 23 June 1990 at 11:45AM 122 | > this returns the integer `11`. 123 | 124 | As in the Elm implementation, this implicitly uses the current locale. 125 | 126 | #### `minute` 127 | 128 | ``` purescript 129 | minute :: Date -> Int 130 | ``` 131 | 132 | > Extract the minute of a given date. Given the date 23 June 1990 at 11:45AM 133 | > this returns the integer `45`. 134 | 135 | As in the Elm implementation, this implicitly uses the current locale. 136 | 137 | #### `second` 138 | 139 | ``` purescript 140 | second :: Date -> Int 141 | ``` 142 | 143 | > Extract the second of a given date. Given the date 23 June 1990 at 11:45AM 144 | > this returns the integer `0`. 145 | 146 | As in the Elm implementation, this implicitly uses the current locale. 147 | 148 | #### `millisecond` 149 | 150 | ``` purescript 151 | millisecond :: Date -> Int 152 | ``` 153 | 154 | > Extract the millisecond of a given date. Given the date 23 June 1990 at 11:45:30.123AM 155 | > this returns the integer `123`. 156 | 157 | As in the Elm implementation, this implicitly uses the current locale. 158 | 159 | #### `now` 160 | 161 | ``` purescript 162 | now :: forall x. Task x Date 163 | ``` 164 | 165 | > Get the `Date` at the moment when this task is run. 166 | 167 | Added in Elm 0.17 / version 4.0.0 of elm-lang/core 168 | 169 | 170 | ### Re-exported from Data.Date: 171 | 172 | #### `Month` 173 | 174 | ``` purescript 175 | data Month 176 | = January 177 | | February 178 | | March 179 | | April 180 | | May 181 | | June 182 | | July 183 | | August 184 | | September 185 | | October 186 | | November 187 | | December 188 | ``` 189 | 190 | A month component for a date in the Gregorian calendar. 191 | 192 | ##### Instances 193 | ``` purescript 194 | Eq Month 195 | Ord Month 196 | Generic Month 197 | Bounded Month 198 | Enum Month 199 | BoundedEnum Month 200 | Show Month 201 | ``` 202 | 203 | -------------------------------------------------------------------------------- /generated-docs/Elm/Debug.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Debug 2 | 3 | This library is for investigating bugs or performance problems. 4 | 5 | #### `log` 6 | 7 | ``` purescript 8 | log :: forall a. String -> a -> a 9 | ``` 10 | 11 | Log a tagged value on the developer console, and then return the value. 12 | 13 | 1 + log "number" 1 -- equals 2, logs "number: 1" 14 | length (log "start" []) -- equals 0, logs "start: []" 15 | 16 | Notice that `log` is not a pure function! It should *only* be used for 17 | investigating bugs or performance problems. 18 | 19 | #### `crash` 20 | 21 | ``` purescript 22 | crash :: forall a. String -> a 23 | ``` 24 | 25 | Crash the program with an error message. 26 | 27 | Equivalent to Purescript's `Partial.Unsafe.unsafeCrashWith` 28 | 29 | 30 | -------------------------------------------------------------------------------- /generated-docs/Elm/Dict.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Dict 2 | 3 | > A dictionary mapping unique keys to values. The keys can be any type which 4 | > has an instance of the `Ord` class. 5 | 6 | This is implemented in terms of Purescript's `Data.Map`. 7 | 8 | #### `Dict` 9 | 10 | ``` purescript 11 | type Dict = Map 12 | ``` 13 | 14 | Elm's `Dict` type is a synonym for Purescript's `Data.Map`. 15 | 16 | #### `get` 17 | 18 | ``` purescript 19 | get :: forall k v. Ord k => k -> Dict k v -> Maybe v 20 | ``` 21 | 22 | > Get the value associated with a key. If the key is not found, return 23 | > `Nothing`. This is useful when you are not sure if a key will be in the 24 | > dictionary. 25 | > 26 | > animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ] 27 | > 28 | > get "Tom" animals == Just Cat 29 | > get "Jerry" animals == Just Mouse 30 | > get "Spike" animals == Nothing 31 | 32 | Equivalent to Purescript's `lookup`. 33 | 34 | #### `remove` 35 | 36 | ``` purescript 37 | remove :: forall k v. Ord k => k -> Dict k v -> Dict k v 38 | ``` 39 | 40 | > Remove a key-value pair from a dictionary. If the key is not found, 41 | > no changes are made. 42 | 43 | Equivalent to Purescript's `delete`. 44 | 45 | #### `update` 46 | 47 | ``` purescript 48 | update :: forall k v. Ord k => k -> (Maybe v -> Maybe v) -> Dict k v -> Dict k v 49 | ``` 50 | 51 | > Update the value of a dictionary for a specific key with a given function. 52 | 53 | Like Purescript's `alter`, but with flipped arguments. 54 | 55 | #### `intersect` 56 | 57 | ``` purescript 58 | intersect :: forall k v. Ord k => Dict k v -> Dict k v -> Dict k v 59 | ``` 60 | 61 | > Keep a key-value pair when its key appears in the second dictionary. 62 | > Preference is given to values in the first dictionary. 63 | 64 | #### `diff` 65 | 66 | ``` purescript 67 | diff :: forall k v. Ord k => Dict k v -> Dict k v -> Dict k v 68 | ``` 69 | 70 | > Keep a key-value pair when its key does not appear in the second dictionary. 71 | 72 | #### `filter` 73 | 74 | ``` purescript 75 | filter :: forall k v. Ord k => (k -> v -> Bool) -> Dict k v -> Dict k v 76 | ``` 77 | 78 | > Keep a key-value pair when it satisfies a predicate. 79 | 80 | Equivalent to Purescript's `filterWithKey` 81 | 82 | #### `partition` 83 | 84 | ``` purescript 85 | partition :: forall k v. Ord k => (k -> v -> Bool) -> Dict k v -> Tuple (Dict k v) (Dict k v) 86 | ``` 87 | 88 | > Partition a dictionary according to a predicate. The first dictionary 89 | > contains all key-value pairs which satisfy the predicate, and the second 90 | > contains the rest. 91 | 92 | #### `merge` 93 | 94 | ``` purescript 95 | merge :: forall k a b result. Ord k => (k -> a -> result -> result) -> (k -> a -> b -> result -> result) -> (k -> b -> result -> result) -> Dict k a -> Dict k b -> result -> result 96 | ``` 97 | 98 | > The most general way of combining two dictionaries. You provide three 99 | > accumulators for when a given key appears: 100 | > 101 | > 1. Only in the left dictionary. 102 | > 2. In both dictionaries. 103 | > 3. Only in the right dictionary. 104 | > 105 | > You then traverse all the keys from lowest to highest, building up whatever 106 | > you want. 107 | 108 | Introduced in Elm 0.17. 109 | 110 | #### `map` 111 | 112 | ``` purescript 113 | map :: forall k a b. Ord k => (k -> a -> b) -> Dict k a -> Dict k b 114 | ``` 115 | 116 | > Apply a function to all values in a dictionary. 117 | 118 | Equivalent to Purescript's `mapWithKey` 119 | 120 | #### `foldl` 121 | 122 | ``` purescript 123 | foldl :: forall k v b. Ord k => (k -> v -> b -> b) -> b -> Dict k v -> b 124 | ``` 125 | 126 | > Fold over the key-value pairs in a dictionary, in order from lowest 127 | > key to highest key. 128 | 129 | #### `foldr` 130 | 131 | ``` purescript 132 | foldr :: forall k v b. Ord k => (k -> v -> b -> b) -> b -> Dict k v -> b 133 | ``` 134 | 135 | > Fold over the key-value pairs in a dictionary, in order from highest 136 | > key to lowest key. 137 | 138 | #### `toUnfoldable` 139 | 140 | ``` purescript 141 | toUnfoldable :: forall f k v. Unfoldable f => Dict k v -> f (Tuple k v) 142 | ``` 143 | 144 | Produces tuples of keys and values in any container that has an 145 | `Unfoldable` instance. This is defined polymorphically to accommodate Purescript `Array`, 146 | among others. 147 | 148 | Note that this is not in the Elm API. 149 | 150 | #### `toList` 151 | 152 | ``` purescript 153 | toList :: forall f k v. Unfoldable f => Dict k v -> f (Tuple k v) 154 | ``` 155 | 156 | > Convert a dictionary into an association list of key-value pairs, sorted by keys. 157 | 158 | #### `fromList` 159 | 160 | ``` purescript 161 | fromList :: forall f k v. Ord k => Foldable f => f (Tuple k v) -> Dict k v 162 | ``` 163 | 164 | 165 | ### Re-exported from Data.Map: 166 | 167 | #### `values` 168 | 169 | ``` purescript 170 | values :: forall k v. Map k v -> List v 171 | ``` 172 | 173 | Get a list of the values contained in a map 174 | 175 | #### `union` 176 | 177 | ``` purescript 178 | union :: forall k v. Ord k => Map k v -> Map k v -> Map k v 179 | ``` 180 | 181 | Compute the union of two maps, preferring values from the first map in the case 182 | of duplicate keys 183 | 184 | #### `size` 185 | 186 | ``` purescript 187 | size :: forall k v. Map k v -> Int 188 | ``` 189 | 190 | Calculate the number of key/value pairs in a map 191 | 192 | #### `singleton` 193 | 194 | ``` purescript 195 | singleton :: forall k v. k -> v -> Map k v 196 | ``` 197 | 198 | Create a map with one key/value pair 199 | 200 | #### `member` 201 | 202 | ``` purescript 203 | member :: forall k v. Ord k => k -> Map k v -> Boolean 204 | ``` 205 | 206 | Test if a key is a member of a map 207 | 208 | #### `keys` 209 | 210 | ``` purescript 211 | keys :: forall k v. Map k v -> List k 212 | ``` 213 | 214 | Get a list of the keys contained in a map 215 | 216 | #### `isEmpty` 217 | 218 | ``` purescript 219 | isEmpty :: forall k v. Map k v -> Boolean 220 | ``` 221 | 222 | Test if a map is empty 223 | 224 | #### `insert` 225 | 226 | ``` purescript 227 | insert :: forall k v. Ord k => k -> v -> Map k v -> Map k v 228 | ``` 229 | 230 | Insert or replace a key/value pair in a map 231 | 232 | #### `fromFoldable` 233 | 234 | ``` purescript 235 | fromFoldable :: forall f k v. Ord k => Foldable f => f (Tuple k v) -> Map k v 236 | ``` 237 | 238 | Convert any foldable collection of key/value pairs to a map. 239 | On key collision, later values take precedence over earlier ones. 240 | 241 | #### `empty` 242 | 243 | ``` purescript 244 | empty :: forall k v. Map k v 245 | ``` 246 | 247 | An empty map 248 | 249 | -------------------------------------------------------------------------------- /generated-docs/Elm/Foldable.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Foldable 2 | 3 | Elm modules define `foldl` with a different signature than Purescript's. 4 | So, we define that alternative `foldl` here. 5 | 6 | #### `foldl` 7 | 8 | ``` purescript 9 | foldl :: forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b 10 | ``` 11 | 12 | Reduce a container from the left. 13 | 14 | Equivalent to Purescript's `foldl`, but the function you supply is flipped. 15 | 16 | 17 | -------------------------------------------------------------------------------- /generated-docs/Elm/FunctorWithIndex.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.FunctorWithIndex 2 | 3 | Elm modules sometimes define `indexedMap` as a synonym for Purescript's 4 | `mapWithIndex`. So, we define that generally here. 5 | 6 | #### `indexedMap` 7 | 8 | ``` purescript 9 | indexedMap :: forall i f a b. FunctorWithIndex i f => (i -> a -> b) -> f a -> f b 10 | ``` 11 | 12 | Map over a container with an index. 13 | 14 | Equivalent to Purescript's `mapWithIndex` 15 | 16 | 17 | -------------------------------------------------------------------------------- /generated-docs/Elm/Json/Encode.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Json.Encode 2 | 3 | A library for turning Elm values into Json values. 4 | 5 | This is mainly implemented via the `toForeign` method in 6 | [purescript-foreign](https://pursuit.purescript.org/packages/purescript-foreign/0.7.2/docs/Data.Foreign#v:toForeign). 7 | 8 | You could also consider the purescript-argonaut-* modules. 9 | 10 | #### `Value` 11 | 12 | ``` purescript 13 | type Value = Foreign 14 | ``` 15 | 16 | Represents a JavaScript value. 17 | 18 | #### `encode` 19 | 20 | ``` purescript 21 | encode :: Int -> Value -> String 22 | ``` 23 | 24 | Convert a `Value` into a prettified string. The first argument specifies 25 | the amount of indentation in the resulting string. 26 | 27 | person = 28 | object 29 | [ Tuple "name" (string "Tom") 30 | , Tuple "age" (int 42) 31 | ] 32 | 33 | compact = encode 0 person 34 | -- {"name":"Tom","age":42} 35 | 36 | readable = encode 4 person 37 | -- { 38 | -- "name": "Tom", 39 | -- "age": 42 40 | -- } 41 | 42 | #### `string` 43 | 44 | ``` purescript 45 | string :: String -> Value 46 | ``` 47 | 48 | Turn a `String` into a `Value`. 49 | 50 | #### `int` 51 | 52 | ``` purescript 53 | int :: Int -> Value 54 | ``` 55 | 56 | Turn an `Int` into a `Value`. 57 | 58 | #### `float` 59 | 60 | ``` purescript 61 | float :: Float -> Value 62 | ``` 63 | 64 | Encode a Float. `Infinity` and `NaN` are encoded as `null`. 65 | 66 | #### `bool` 67 | 68 | ``` purescript 69 | bool :: Bool -> Value 70 | ``` 71 | 72 | Encode a `Bool`. 73 | 74 | #### `null` 75 | 76 | ``` purescript 77 | null :: Value 78 | ``` 79 | 80 | Encode a null value. 81 | 82 | #### `list` 83 | 84 | ``` purescript 85 | list :: List Value -> Value 86 | ``` 87 | 88 | Encode a `List`. 89 | 90 | #### `array` 91 | 92 | ``` purescript 93 | array :: forall f. Foldable f => f Value -> Value 94 | ``` 95 | 96 | Encode an array type. Uses a polymorphic type in order to accommodate 97 | Purescript `Array` and `Elm.Array`, among others. 98 | 99 | #### `object` 100 | 101 | ``` purescript 102 | object :: forall f. Foldable f => f (Tuple String Value) -> Value 103 | ``` 104 | 105 | Encode a JSON object. 106 | 107 | The signature uses `Foldable` in order to work with `List` or 108 | `Array`, amongst others. 109 | 110 | 111 | -------------------------------------------------------------------------------- /generated-docs/Elm/Maybe.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Maybe 2 | 3 | > This library fills a bunch of important niches in Elm. A `Maybe` can help 4 | > you with optional arguments, error handling, and records with optional fields. 5 | 6 | This is implemented in terms of Purescript's `Data.Maybe`, so you can use functions 7 | from there on `Maybe` values as well. 8 | 9 | #### `withDefault` 10 | 11 | ``` purescript 12 | withDefault :: forall a. a -> Maybe a -> a 13 | ``` 14 | 15 | > Provide a default value, turning an optional value into a normal 16 | > value. This comes in handy when paired with functions like 17 | > [`Dict.get`](Dict#get) which gives back a `Maybe`. 18 | > 19 | > withDefault 100 (Just 42) -- 42 20 | > withDefault 100 Nothing -- 100 21 | > 22 | > withDefault "unknown" (Dict.get "Tom" Dict.empty) -- "unknown" 23 | 24 | Equivalent to Purescript's 'fromMaybe`. 25 | 26 | 27 | ### Re-exported from Data.Foldable: 28 | 29 | #### `oneOf` 30 | 31 | ``` purescript 32 | oneOf :: forall f g a. Foldable f => Plus g => f (g a) -> g a 33 | ``` 34 | 35 | Combines a collection of elements using the `Alt` operation. 36 | 37 | ### Re-exported from Data.Maybe: 38 | 39 | #### `Maybe` 40 | 41 | ``` purescript 42 | data Maybe a 43 | = Nothing 44 | | Just a 45 | ``` 46 | 47 | The `Maybe` type is used to represent optional values and can be seen as 48 | something like a type-safe `null`, where `Nothing` is `null` and `Just x` 49 | is the non-null value `x`. 50 | 51 | ##### Instances 52 | ``` purescript 53 | Functor Maybe 54 | Apply Maybe 55 | Applicative Maybe 56 | Alt Maybe 57 | Plus Maybe 58 | Alternative Maybe 59 | Bind Maybe 60 | Monad Maybe 61 | MonadZero Maybe 62 | Extend Maybe 63 | Invariant Maybe 64 | (Semigroup a) => Semigroup (Maybe a) 65 | (Semigroup a) => Monoid (Maybe a) 66 | (Eq a) => Eq (Maybe a) 67 | Eq1 Maybe 68 | (Ord a) => Ord (Maybe a) 69 | Ord1 Maybe 70 | (Bounded a) => Bounded (Maybe a) 71 | (Show a) => Show (Maybe a) 72 | ``` 73 | 74 | ### Re-exported from Elm.Apply: 75 | 76 | #### `map5` 77 | 78 | ``` purescript 79 | map5 :: forall w a b c d e f. Apply w => (a -> b -> c -> d -> e -> f) -> w a -> w b -> w c -> w d -> w e -> w f 80 | ``` 81 | 82 | Map a function of five arguments over some container type. 83 | 84 | The equivalent of Purescript's `lift5`. 85 | 86 | #### `map4` 87 | 88 | ``` purescript 89 | map4 :: forall w a b c d e. Apply w => (a -> b -> c -> d -> e) -> w a -> w b -> w c -> w d -> w e 90 | ``` 91 | 92 | Map a function of four arguments over some container type. 93 | 94 | The equivalent of Purescript's `lift4`. 95 | 96 | #### `map3` 97 | 98 | ``` purescript 99 | map3 :: forall w a b c d. Apply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d 100 | ``` 101 | 102 | Map a function of three arguments over some container type. 103 | 104 | The equivalent of Purescript's `lift3`. 105 | 106 | #### `map2` 107 | 108 | ``` purescript 109 | map2 :: forall w a b c. Apply w => (a -> b -> c) -> w a -> w b -> w c 110 | ``` 111 | 112 | Map a function of two arguments over some container type. 113 | 114 | The equivalent of Purescript's `lift2`. 115 | 116 | ### Re-exported from Elm.Bind: 117 | 118 | #### `andThen` 119 | 120 | ``` purescript 121 | andThen :: forall m a b. Bind m => (a -> m b) -> m a -> m b 122 | ``` 123 | 124 | Given some computation, chain its result with another computation. 125 | 126 | Equivalent to Purescript's `bind`. 127 | 128 | The order of the arguments was flipped in Elm 0.18. 129 | 130 | ### Re-exported from Prelude: 131 | 132 | #### `map` 133 | 134 | ``` purescript 135 | map :: forall a b f. Functor f => (a -> b) -> f a -> f b 136 | ``` 137 | 138 | -------------------------------------------------------------------------------- /generated-docs/Elm/Monoid.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Monoid 2 | 3 | Elm modules sometimes define a `none` function that corresponds to Purescript's 4 | `mempty`, and a `batch` function that corresponds to Purescript's `fold`. So, 5 | we re-export these here with the Elm-ish names. 6 | 7 | #### `batch` 8 | 9 | ``` purescript 10 | batch :: forall f m. Foldable f => Monoid m => f m -> m 11 | ``` 12 | 13 | Smush together a bunch of things. 14 | 15 | Equivalent to Purescript's `fold` 16 | 17 | #### `none` 18 | 19 | ``` purescript 20 | none :: forall m. Monoid m => m 21 | ``` 22 | 23 | Produce an "empty" value of the relevant type. 24 | 25 | Equivalent to Purescript's `mempty`. 26 | 27 | 28 | -------------------------------------------------------------------------------- /generated-docs/Elm/Platform/Cmd.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Platform.Cmd 2 | 3 | # Effects 4 | 5 | Elm has **managed effects**, meaning that things like HTTP requests or writing 6 | to disk are all treated as *data* in Elm. When this data is given to the Elm 7 | runtime system, it can do some “query optimization” before actually performing 8 | the effect. Perhaps unexpectedly, this managed effects idea is the heart of why 9 | Elm is so nice for testing, reuse, reproducibility, etc. 10 | 11 | There are two kinds of managed effects you will use in your programs: commands 12 | and subscriptions. 13 | 14 | #### `withCmds` 15 | 16 | ``` purescript 17 | withCmds :: forall f model cmd. Foldable f => Monoid cmd => model -> f cmd -> Tuple model cmd 18 | ``` 19 | 20 | #### `(!)` 21 | 22 | ``` purescript 23 | infixl 5 withCmds as ! 24 | ``` 25 | 26 | 27 | ### Re-exported from Elm.Monoid: 28 | 29 | #### `none` 30 | 31 | ``` purescript 32 | none :: forall m. Monoid m => m 33 | ``` 34 | 35 | Produce an "empty" value of the relevant type. 36 | 37 | Equivalent to Purescript's `mempty`. 38 | 39 | #### `batch` 40 | 41 | ``` purescript 42 | batch :: forall f m. Foldable f => Monoid m => f m -> m 43 | ``` 44 | 45 | Smush together a bunch of things. 46 | 47 | Equivalent to Purescript's `fold` 48 | 49 | ### Re-exported from Elm.Platform: 50 | 51 | #### `Cmd` 52 | 53 | ``` purescript 54 | newtype Cmd msg 55 | ``` 56 | 57 | > A command is a way of telling Elm, “Hey, I want you to do this thing!” 58 | > So if you want to send an HTTP request, you would need to command Elm to do it. 59 | > Or if you wanted to ask for geolocation, you would need to command Elm to go 60 | > get it. 61 | > 62 | > Every `Cmd` specifies (1) which effects you need access to and (2) the type of 63 | > messages that will come back into your application. 64 | > 65 | > **Note:** Do not worry if this seems confusing at first! As with every Elm user 66 | > ever, commands will make more sense as you work through [the Elm Architecture 67 | > Tutorial](http://guide.elm-lang.org/architecture/index.html) and see how they 68 | > fit into a real application! 69 | 70 | ##### Instances 71 | ``` purescript 72 | Functor Cmd 73 | Semigroup (Cmd msg) 74 | Monoid (Cmd msg) 75 | ``` 76 | 77 | ### Re-exported from Prelude: 78 | 79 | #### `map` 80 | 81 | ``` purescript 82 | map :: forall a b f. Functor f => (a -> b) -> f a -> f b 83 | ``` 84 | 85 | -------------------------------------------------------------------------------- /generated-docs/Elm/Platform/Sub.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Platform.Sub 2 | 3 | 4 | ### Re-exported from Elm.Monoid: 5 | 6 | #### `none` 7 | 8 | ``` purescript 9 | none :: forall m. Monoid m => m 10 | ``` 11 | 12 | Produce an "empty" value of the relevant type. 13 | 14 | Equivalent to Purescript's `mempty`. 15 | 16 | #### `batch` 17 | 18 | ``` purescript 19 | batch :: forall f m. Foldable f => Monoid m => f m -> m 20 | ``` 21 | 22 | Smush together a bunch of things. 23 | 24 | Equivalent to Purescript's `fold` 25 | 26 | ### Re-exported from Elm.Platform: 27 | 28 | #### `Sub` 29 | 30 | ``` purescript 31 | newtype Sub msg 32 | ``` 33 | 34 | > A subscription is a way of telling Elm, “Hey, let me know if anything 35 | > interesting happens over there!” So if you want to listen for messages on a web 36 | > socket, you would tell Elm to create a subscription. If you want to get clock 37 | > ticks, you would tell Elm to subscribe to that. The cool thing here is that 38 | > this means *Elm* manages all the details of subscriptions instead of *you*. 39 | > So if a web socket goes down, *you* do not need to manually reconnect with an 40 | > exponential backoff strategy, *Elm* does this all for you behind the scenes! 41 | > 42 | > Every `Sub` specifies (1) which effects you need access to and (2) the type of 43 | > messages that will come back into your application. 44 | > 45 | > **Note:** Do not worry if this seems confusing at first! As with every Elm user 46 | > ever, subscriptions will make more sense as you work through [the Elm Architecture 47 | > Tutorial](http://guide.elm-lang.org/architecture/index.html) and see how they fit 48 | > into a real application! 49 | 50 | ##### Instances 51 | ``` purescript 52 | Functor Sub 53 | Semigroup (Sub msg) 54 | Monoid (Sub msg) 55 | ``` 56 | 57 | ### Re-exported from Prelude: 58 | 59 | #### `map` 60 | 61 | ``` purescript 62 | map :: forall a b f. Functor f => (a -> b) -> f a -> f b 63 | ``` 64 | 65 | -------------------------------------------------------------------------------- /generated-docs/Elm/Process.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Process 2 | 3 | > Right now, this library is pretty sparse. For example, there is no public API 4 | > for processes to communicate with each other. This is a really important 5 | > ability, but it is also something that is extraordinarily easy to get wrong! 6 | 7 | #### `Id` 8 | 9 | ``` purescript 10 | type Id = ProcessId 11 | ``` 12 | 13 | > A light-weight process that runs concurrently. You can use `spawn` to 14 | > get a bunch of different tasks running in different processes. The Elm runtime 15 | > will interleave their progress. So if a task is taking too long, we will pause 16 | > it at an `andThen` and switch over to other stuff. 17 | > 18 | > **Note:** We make a distinction between *concurrency* which means interleaving 19 | > different sequences and *parallelism* which means running different 20 | > sequences at the exact same time. For example, a 21 | > [time-sharing system](https://en.wikipedia.org/wiki/Time-sharing) is definitely 22 | > concurrent, but not necessarily parallel. So even though JS runs within a 23 | > single OS-level thread, Elm can still run things concurrently. 24 | 25 | #### `spawn` 26 | 27 | ``` purescript 28 | spawn :: forall x y a. Task x a -> Task y Id 29 | ``` 30 | 31 | > Run a task in its own light-weight process. In the following example, 32 | > `task1` and `task2` will be interleaved. If `task1` makes a long HTTP request 33 | > or is just taking a long time, we can hop over to `task2` and do some work 34 | > there. 35 | > 36 | > spawn task1 37 | > |> Task.andThen (\_ -> spawn task2) 38 | > 39 | > **Note:** This creates a relatively restricted kind of `Process` because it 40 | > cannot receive any messages. More flexibility for user-defined processes will 41 | > come in a later release! 42 | 43 | #### `sleep` 44 | 45 | ``` purescript 46 | sleep :: forall x. Time -> Task x Unit 47 | ``` 48 | 49 | > Block progress on the current process for a given amount of time. The 50 | > JavaScript equivalent of this is [`setTimeout`][setTimeout] which lets you 51 | > delay work until later. 52 | > 53 | > [setTimeout]: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout 54 | 55 | #### `kill` 56 | 57 | ``` purescript 58 | kill :: forall y. Id -> Task y Unit 59 | ``` 60 | 61 | > Sometimes you `spawn` a process, but later decide it would be a waste to 62 | > have it keep running and doing stuff. The `kill` function will force a process 63 | > to bail on whatever task it is running. So if there is an HTTP request in 64 | > flight, it will also abort the request. 65 | 66 | 67 | -------------------------------------------------------------------------------- /generated-docs/Elm/Regex.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Regex 2 | 3 | > A library for working with regular expressions. It uses the same kind of 4 | > regular expressions 5 | > [accepted by JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions). 6 | 7 | Purescript has its own regular expression library in `Data.String.Regex`. 8 | However, the `Elm.Regex` API is sufficiently different that it is 9 | re-implemented here. 10 | 11 | #### `Regex` 12 | 13 | ``` purescript 14 | data Regex :: Type 15 | ``` 16 | 17 | > A regular expression, describing a certain set of strings. 18 | 19 | Note that this is (unfortunatley) not interchangeable with Purescript's `Data.String.Regex`, 20 | because the Elm code requires that the `Regex` be created with the `g` flag. 21 | 22 | ##### Instances 23 | ``` purescript 24 | Show Regex 25 | ``` 26 | 27 | #### `regex` 28 | 29 | ``` purescript 30 | regex :: String -> Regex 31 | ``` 32 | 33 | > Create a Regex that matches patterns 34 | > [as specified in JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Writing_a_Regular_Expression_Pattern). 35 | > 36 | > Be careful to escape backslashes properly! For example, `"\w"` is escaping the 37 | > letter `w` which is probably not what you want. You probably want `"\\w"` 38 | > instead, which escapes the backslash. 39 | 40 | #### `escape` 41 | 42 | ``` purescript 43 | escape :: String -> String 44 | ``` 45 | 46 | > Escape strings to be regular expressions, making all special characters 47 | > safe. So `regex (escape "^a+")` will match exactly `"^a+"` instead of a series 48 | > of `a`’s that start at the beginning of the line. 49 | 50 | #### `caseInsensitive` 51 | 52 | ``` purescript 53 | caseInsensitive :: Regex -> Regex 54 | ``` 55 | 56 | > Make a regex case insensitive. 57 | 58 | #### `HowMany` 59 | 60 | ``` purescript 61 | data HowMany 62 | = All 63 | | AtMost Int 64 | ``` 65 | 66 | > `HowMany` is used to specify how many matches you want to make. So 67 | > `replace All` would replace every match, but `replace (AtMost 2)` would 68 | > replace at most two matches (i.e. zero, one, two, but never three or more). 69 | 70 | #### `Match` 71 | 72 | ``` purescript 73 | type Match = { match :: String, submatches :: List (Maybe String), index :: Int, number :: Int } 74 | ``` 75 | 76 | > A `Match` represents all of the details about a particular match in a string. 77 | > Here are details on each field: 78 | > 79 | > * `match` — the full string of the match. 80 | > 81 | > * `submatches` — a regex might have 82 | > [subpatterns, surrounded by parentheses](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Parenthesized_Substring_Matches). 83 | > If there are N subpatterns, there will be N elements in the `submatches` list. 84 | > Each submatch in this list is a `Maybe` because not all subpatterns may trigger. 85 | > For example, `(regex "(a+)|(b+)")` will either match many `a`’s or 86 | > many `b`’s, but never both. 87 | > 88 | > * `index` — the index of the match in the original string. 89 | > 90 | > * `number` — if you find many matches, you can think of each one 91 | > as being labeled with a `number` starting at one. So the first time you 92 | > find a match, that is match `number` one. Second time is match `number` two. 93 | > This is useful when paired with `replace All` if replacement is dependent on how 94 | > many times a pattern has appeared before. 95 | 96 | #### `contains` 97 | 98 | ``` purescript 99 | contains :: Regex -> String -> Bool 100 | ``` 101 | 102 | > Check to see if a Regex is contained in a string. 103 | > 104 | > contains (regex "123") "12345" == true 105 | > contains (regex "b+") "aabbcc" == true 106 | > 107 | > contains (regex "789") "12345" == false 108 | > contains (regex "z+") "aabbcc" == false 109 | 110 | #### `find` 111 | 112 | ``` purescript 113 | find :: HowMany -> Regex -> String -> List Match 114 | ``` 115 | 116 | > Find matches in a string: 117 | > 118 | > findTwoCommas = find (AtMost 2) (regex ",") 119 | > 120 | > -- map .index (findTwoCommas "a,b,c,d,e") == [1,3] 121 | > -- map .index (findTwoCommas "a b c d e") == [] 122 | > 123 | > places = find All (regex "[oi]n a (\\w+)") "I am on a boat in a lake." 124 | > 125 | > -- map .match places == ["on a boat", "in a lake"] 126 | > -- map .submatches places == [ [Just "boat"], [Just "lake"] ] 127 | 128 | #### `replace` 129 | 130 | ``` purescript 131 | replace :: HowMany -> Regex -> (Match -> String) -> String -> String 132 | ``` 133 | 134 | > Replace matches. The function from `Match` to `String` lets 135 | > you use the details of a specific match when making replacements. 136 | > 137 | > devowel = replace All (regex "[aeiou]") (\_ -> "") 138 | > 139 | > -- devowel "The quick brown fox" == "Th qck brwn fx" 140 | > 141 | > reverseWords = replace All (regex "\\w+") (\{match} -> String.reverse match) 142 | > 143 | > -- reverseWords "deliver mined parts" == "reviled denim strap" 144 | 145 | #### `split` 146 | 147 | ``` purescript 148 | split :: HowMany -> Regex -> String -> List String 149 | ``` 150 | 151 | > Split a string, using the regex as the separator. 152 | > 153 | > split (AtMost 1) (regex ",") "tom,99,90,85" == ["tom","99,90,85"] 154 | > 155 | > split All (regex ",") "a,b,c,d" == ["a","b","c","d"] 156 | 157 | 158 | -------------------------------------------------------------------------------- /generated-docs/Elm/Result.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Result 2 | 3 | A `Result` is the result of a computation that may fail. 4 | 5 | Normally, I would have wanted to implement this in terms of Purescript's 6 | `Either` module, since it is essentially equivalent. 7 | 8 | However, the difficulty is that there is no way to alias the data constructors 9 | `Left` and `Right`, so that you could use Elm's `Ok` and `Err` instead. 10 | So, in order to require fewer changes to code coming from Elm, I've 11 | implemented a separate `Result` type here. 12 | 13 | #### `Result` 14 | 15 | ``` purescript 16 | data Result error value 17 | = Ok value 18 | | Err error 19 | ``` 20 | 21 | A `Result` is either `Ok` meaning the computation succeeded, or it is an 22 | `Err` meaning that there was some failure. 23 | 24 | ##### Instances 25 | ``` purescript 26 | Functor (Result a) 27 | Bifunctor Result 28 | Apply (Result e) 29 | Applicative (Result e) 30 | Alt (Result e) 31 | Bind (Result e) 32 | Monad (Result e) 33 | Extend (Result e) 34 | (Show a, Show b) => Show (Result a b) 35 | (Eq a, Eq b) => Eq (Result a b) 36 | (Ord a, Ord b) => Ord (Result a b) 37 | (Bounded a, Bounded b) => Bounded (Result a b) 38 | Foldable (Result a) 39 | Bifoldable Result 40 | Traversable (Result a) 41 | Bitraversable Result 42 | (Semiring b) => Semiring (Result a b) 43 | (Semigroup b) => Semigroup (Result a b) 44 | ``` 45 | 46 | #### `withDefault` 47 | 48 | ``` purescript 49 | withDefault :: forall x a. a -> Result x a -> a 50 | ``` 51 | 52 | If the result is `Ok` return the value, but if the result is an `Err` then 53 | return a given default value. The following examples try to parse integers. 54 | 55 | Result.withDefault 0 (String.toInt "123") == 123 56 | Result.withDefault 0 (String.toInt "abc") == 0 57 | 58 | #### `toMaybe` 59 | 60 | ``` purescript 61 | toMaybe :: forall x a. Result x a -> Maybe a 62 | ``` 63 | 64 | Convert to a simpler `Maybe` if the actual error message is not needed or 65 | you need to interact with some code that primarily uses maybes. 66 | 67 | parseInt :: String -> Result ParseError Int 68 | 69 | maybeParseInt :: String -> Maybe Int 70 | maybeParseInt string = 71 | toMaybe (parseInt string) 72 | 73 | #### `fromMaybe` 74 | 75 | ``` purescript 76 | fromMaybe :: forall x a. x -> Maybe a -> Result x a 77 | ``` 78 | 79 | Convert from a simple `Maybe` to interact with some code that primarily 80 | uses `Results`. 81 | 82 | parseInt :: String -> Maybe Int 83 | 84 | resultParseInt :: String -> Result String Int 85 | resultParseInt string = 86 | fromMaybe ("error parsing string: " <> toString string) (parseInt string) 87 | 88 | #### `formatError` 89 | 90 | ``` purescript 91 | formatError :: forall error error' a. (error -> error') -> Result error a -> Result error' a 92 | ``` 93 | 94 | Format the error value of a result. If the result is `Ok`, it stays exactly 95 | the same, but if the result is an `Err` we will format the error. For example, 96 | say the errors we get have too much information: 97 | 98 | parseInt :: String -> Result ParseError Int 99 | 100 | type ParseError = 101 | { message : String 102 | , code : Int 103 | , position : (Int,Int) 104 | } 105 | 106 | formatError .message (parseInt "123") == Ok 123 107 | formatError .message (parseInt "abc") == Err "char 'a' is not a number" 108 | 109 | Equivalent to Purescript's `lmap`. 110 | 111 | Renamed `mapError` in Elm 0.18. 112 | 113 | #### `mapError` 114 | 115 | ``` purescript 116 | mapError :: forall x y a. (x -> y) -> Result x a -> Result y a 117 | ``` 118 | 119 | Transform an `Err` value. For example, say the errors we get have too much 120 | information: 121 | 122 | mapError .message (parseInt "123") == Ok 123 123 | mapError .message (parseInt "abc") == Err "char 'a' is not a number" 124 | 125 | Equivalent to Purescript's `lmap`. 126 | 127 | Was called `formatError` prior to Elm 0.18. 128 | 129 | 130 | ### Re-exported from Elm.Apply: 131 | 132 | #### `map5` 133 | 134 | ``` purescript 135 | map5 :: forall w a b c d e f. Apply w => (a -> b -> c -> d -> e -> f) -> w a -> w b -> w c -> w d -> w e -> w f 136 | ``` 137 | 138 | Map a function of five arguments over some container type. 139 | 140 | The equivalent of Purescript's `lift5`. 141 | 142 | #### `map4` 143 | 144 | ``` purescript 145 | map4 :: forall w a b c d e. Apply w => (a -> b -> c -> d -> e) -> w a -> w b -> w c -> w d -> w e 146 | ``` 147 | 148 | Map a function of four arguments over some container type. 149 | 150 | The equivalent of Purescript's `lift4`. 151 | 152 | #### `map3` 153 | 154 | ``` purescript 155 | map3 :: forall w a b c d. Apply w => (a -> b -> c -> d) -> w a -> w b -> w c -> w d 156 | ``` 157 | 158 | Map a function of three arguments over some container type. 159 | 160 | The equivalent of Purescript's `lift3`. 161 | 162 | #### `map2` 163 | 164 | ``` purescript 165 | map2 :: forall w a b c. Apply w => (a -> b -> c) -> w a -> w b -> w c 166 | ``` 167 | 168 | Map a function of two arguments over some container type. 169 | 170 | The equivalent of Purescript's `lift2`. 171 | 172 | ### Re-exported from Elm.Bind: 173 | 174 | #### `andThen` 175 | 176 | ``` purescript 177 | andThen :: forall m a b. Bind m => (a -> m b) -> m a -> m b 178 | ``` 179 | 180 | Given some computation, chain its result with another computation. 181 | 182 | Equivalent to Purescript's `bind`. 183 | 184 | The order of the arguments was flipped in Elm 0.18. 185 | 186 | ### Re-exported from Prelude: 187 | 188 | #### `map` 189 | 190 | ``` purescript 191 | map :: forall a b f. Functor f => (a -> b) -> f a -> f b 192 | ``` 193 | 194 | -------------------------------------------------------------------------------- /generated-docs/Elm/Set.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Set 2 | 3 | A set of unique values. The values can be any type with an 4 | `Ord` instance. 5 | 6 | This is implemented in terms of Purescript's `Data.Set`, so 7 | you can also use functions from that module on a `Set`. 8 | 9 | #### `remove` 10 | 11 | ``` purescript 12 | remove :: forall a. Ord a => a -> Set a -> Set a 13 | ``` 14 | 15 | Remove a value from a set. If the value is not found, no changes are made. 16 | 17 | Equivalent to Purescript's `delete`. 18 | 19 | #### `intersect` 20 | 21 | ``` purescript 22 | intersect :: forall a. Ord a => Set a -> Set a -> Set a 23 | ``` 24 | 25 | Get the intersection of two sets. Keeps values that appear in both sets. 26 | 27 | Equivalent to Purescript's `intersection`. 28 | 29 | #### `diff` 30 | 31 | ``` purescript 32 | diff :: forall a. Ord a => Set a -> Set a -> Set a 33 | ``` 34 | 35 | Get the difference between the first set and the second. Keeps values 36 | that do not appear in the second set. 37 | 38 | Equivalent to Purescript's `difference`. 39 | 40 | #### `filter` 41 | 42 | ``` purescript 43 | filter :: forall a. Ord a => (a -> Bool) -> Set a -> Set a 44 | ``` 45 | 46 | Create a new set consisting only of elements which satisfy a predicate. 47 | 48 | #### `partition` 49 | 50 | ``` purescript 51 | partition :: forall a. Ord a => (a -> Bool) -> Set a -> Tuple (Set a) (Set a) 52 | ``` 53 | 54 | Create two new sets; the first consisting of elements which satisfy a 55 | predicate, the second consisting of elements which do not. 56 | 57 | #### `map` 58 | 59 | ``` purescript 60 | map :: forall a b. Ord a => Ord b => (a -> b) -> Set a -> Set b 61 | ``` 62 | 63 | Map a function onto a set, creating a new set with no duplicates. 64 | 65 | #### `toList` 66 | 67 | ``` purescript 68 | toList :: forall a f. Unfoldable f => Ord a => Set a -> f a 69 | ``` 70 | 71 | Convert a set into a list, sorted from lowest to highest. 72 | 73 | * Uses a polymorphic container type to accommodate `List` and 74 | `Array`, among others. * 75 | 76 | #### `fromList` 77 | 78 | ``` purescript 79 | fromList :: forall a f. Foldable f => Ord a => f a -> Set a 80 | ``` 81 | 82 | Convert a list into a set, removing any duplicates. 83 | 84 | * Uses a polymorphic container type to accommodate `List` and 85 | `Array, among others. * 86 | 87 | 88 | ### Re-exported from Data.Foldable: 89 | 90 | #### `foldr` 91 | 92 | ``` purescript 93 | foldr :: forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b 94 | ``` 95 | 96 | ### Re-exported from Data.Set: 97 | 98 | #### `Set` 99 | 100 | ``` purescript 101 | data Set a 102 | ``` 103 | 104 | `Set a` represents a set of values of type `a` 105 | 106 | ##### Instances 107 | ``` purescript 108 | (Eq a) => Eq (Set a) 109 | Eq1 Set 110 | (Show a) => Show (Set a) 111 | (Ord a) => Ord (Set a) 112 | Ord1 Set 113 | (Ord a) => Monoid (Set a) 114 | (Ord a) => Semigroup (Set a) 115 | Foldable Set 116 | ``` 117 | 118 | #### `union` 119 | 120 | ``` purescript 121 | union :: forall a. Ord a => Set a -> Set a -> Set a 122 | ``` 123 | 124 | Form the union of two sets 125 | 126 | Running time: `O(n * log(m))` 127 | 128 | #### `size` 129 | 130 | ``` purescript 131 | size :: forall a. Set a -> Int 132 | ``` 133 | 134 | Find the size of a set 135 | 136 | #### `singleton` 137 | 138 | ``` purescript 139 | singleton :: forall a. a -> Set a 140 | ``` 141 | 142 | Create a set with one element 143 | 144 | #### `member` 145 | 146 | ``` purescript 147 | member :: forall a. Ord a => a -> Set a -> Boolean 148 | ``` 149 | 150 | Test if a value is a member of a set 151 | 152 | #### `isEmpty` 153 | 154 | ``` purescript 155 | isEmpty :: forall a. Set a -> Boolean 156 | ``` 157 | 158 | Test if a set is empty 159 | 160 | #### `insert` 161 | 162 | ``` purescript 163 | insert :: forall a. Ord a => a -> Set a -> Set a 164 | ``` 165 | 166 | Insert a value into a set 167 | 168 | #### `empty` 169 | 170 | ``` purescript 171 | empty :: forall a. Set a 172 | ``` 173 | 174 | An empty set 175 | 176 | ### Re-exported from Elm.Foldable: 177 | 178 | #### `foldl` 179 | 180 | ``` purescript 181 | foldl :: forall a b f. Foldable f => (a -> b -> b) -> b -> f a -> b 182 | ``` 183 | 184 | Reduce a container from the left. 185 | 186 | Equivalent to Purescript's `foldl`, but the function you supply is flipped. 187 | 188 | -------------------------------------------------------------------------------- /generated-docs/Elm/Time.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Time 2 | 3 | Library for working with time 4 | 5 | #### `Time` 6 | 7 | ``` purescript 8 | type Time = Number 9 | ``` 10 | 11 | Type alias to make it clearer when you are working with time values. 12 | Using the `Time` helpers like `second` and `inSeconds` instead of raw numbers 13 | is very highly recommended. 14 | 15 | Note that Purescript's `Data.Time` class does something similar with its 16 | `Duration` class, which has separate types for `Hours`, `Minutes`, `Seconds` 17 | and `Milliseconds`. 18 | 19 | #### `toTime` 20 | 21 | ``` purescript 22 | toTime :: forall a. Duration a => a -> Time 23 | ``` 24 | 25 | Convert any of Purescript's `Duration` types to `Time`. 26 | 27 | #### `fromTime` 28 | 29 | ``` purescript 30 | fromTime :: forall a. Duration a => Time -> a 31 | ``` 32 | 33 | Convert from `Time` to any of Purescript's `Duration` types. 34 | 35 | #### `now` 36 | 37 | ``` purescript 38 | now :: forall x. Task x Time 39 | ``` 40 | 41 | Get the `Time` at the moment when this task is run. 42 | 43 | #### `every` 44 | 45 | ``` purescript 46 | every :: forall msg. Time -> (Time -> msg) -> Sub msg 47 | ``` 48 | 49 | Subscribe to the current time. First you provide an interval describing how 50 | frequently you want updates. Second, you give a tagger that turns a time into a 51 | message for your `update` function. So if you want to hear about the current 52 | time every second, you would say something like this: 53 | 54 | type Msg = Tick Time | ... 55 | 56 | subscriptions model = 57 | every second Tick 58 | 59 | Check out the [Elm Architecture Tutorial][arch] for more info on how 60 | subscriptions work. 61 | 62 | [arch]: https://github.com/evancz/elm-architecture-tutorial/ 63 | 64 | **Note:** this function is not for animation! You need to use something based 65 | on `requestAnimationFrame` to get smooth animations. This is based on 66 | `setInterval` which is better for recurring tasks like “check on something 67 | every 30 seconds”. 68 | 69 | #### `millisecond` 70 | 71 | ``` purescript 72 | millisecond :: Time 73 | ``` 74 | 75 | Units of time, making it easier to specify things like a half-second 76 | `(500 * millisecond)` without remembering Elm’s underlying units of time. 77 | 78 | #### `second` 79 | 80 | ``` purescript 81 | second :: Time 82 | ``` 83 | 84 | #### `minute` 85 | 86 | ``` purescript 87 | minute :: Time 88 | ``` 89 | 90 | #### `hour` 91 | 92 | ``` purescript 93 | hour :: Time 94 | ``` 95 | 96 | #### `inMilliseconds` 97 | 98 | ``` purescript 99 | inMilliseconds :: Time -> Float 100 | ``` 101 | 102 | #### `inSeconds` 103 | 104 | ``` purescript 105 | inSeconds :: Time -> Float 106 | ``` 107 | 108 | #### `inMinutes` 109 | 110 | ``` purescript 111 | inMinutes :: Time -> Float 112 | ``` 113 | 114 | #### `inHours` 115 | 116 | ``` purescript 117 | inHours :: Time -> Float 118 | ``` 119 | 120 | 121 | ### Re-exported from Data.Time.Duration: 122 | 123 | #### `Duration` 124 | 125 | ``` purescript 126 | class Duration a 127 | ``` 128 | 129 | A class for enabling conversions between duration types. 130 | 131 | ##### Instances 132 | ``` purescript 133 | Duration Milliseconds 134 | Duration Seconds 135 | Duration Minutes 136 | Duration Hours 137 | Duration Days 138 | ``` 139 | 140 | -------------------------------------------------------------------------------- /generated-docs/Elm/Trampoline.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Trampoline 2 | 3 | A [trampoline](http://en.wikipedia.org/wiki/Tail-recursive_function#Through_trampolining) 4 | makes it possible to recursively call a function without growing the stack. 5 | 6 | Popular JavaScript implementations do not perform any tail-call elimination, so 7 | recursive functions can cause a stack overflow if they go too deep. Trampolines 8 | permit unbounded recursion despite limitations in JavaScript. 9 | 10 | This strategy may create many intermediate closures, which is very expensive in 11 | JavaScript, so use this library only when it is essential that you recurse deeply. 12 | 13 | Note that in Purescript, there is tail-call elimination, so you may not need this if you 14 | arrange your code to use tail-calls. If you do need a trampoline module, you could 15 | also consider [Control.Monad.Trampoline](https://pursuit.purescript.org/packages/purescript-free/0.9.1/docs/Control.Monad.Trampoline). 16 | 17 | * In Elm 0.17, this module was moved from core to its own package. * 18 | 19 | #### `Trampoline` 20 | 21 | ``` purescript 22 | data Trampoline a 23 | ``` 24 | 25 | A computation that has been broken up into a bunch of smaller chunks. The 26 | programmer explicitly adds "pause points" so each chunk of computation can be 27 | run without making the stack any deeper. 28 | 29 | #### `done` 30 | 31 | ``` purescript 32 | done :: forall a. a -> Trampoline a 33 | ``` 34 | 35 | When you do not want a computation to go through the trampoline. 36 | 37 | #### `jump` 38 | 39 | ``` purescript 40 | jump :: forall a. (Unit -> Trampoline a) -> Trampoline a 41 | ``` 42 | 43 | When you want a computation to be delayed so that it is handled by the 44 | trampoline. 45 | 46 | #### `evaluate` 47 | 48 | ``` purescript 49 | evaluate :: forall a. Trampoline a -> a 50 | ``` 51 | 52 | Evaluate a trampolined value in constant space. 53 | 54 | 55 | -------------------------------------------------------------------------------- /generated-docs/Elm/Transform2D.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Transform2D 2 | 3 | A library for performing 2D matrix transformations. 4 | It is used primarily with the `groupTransform` function from 5 | `Elm.Graphics.Collage` and allows you to do things 6 | like rotation, scaling, translation, shearing, and reflection. 7 | 8 | Note that all the matrices in this library are 3x3 matrices of homogeneous 9 | coordinates, used for [affine transformations](http://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations). 10 | Since the bottom row is always `0 0 1` in these matrices, it is omitted in 11 | the diagrams below. 12 | 13 | This is implemented as a wrapper around the purescript-canvas module, and its `Transform` type. 14 | 15 | Note that this was removed from elm-lange/core in Elm 0.17. 16 | 17 | #### `Transform2D` 18 | 19 | ``` purescript 20 | type Transform2D = Transform 21 | ``` 22 | 23 | A matrix representing a 2D transformation. 24 | 25 | Equivalent to Purescript's `Graphics.Canvas.Transform`. 26 | 27 | #### `identity` 28 | 29 | ``` purescript 30 | identity :: Transform2D 31 | ``` 32 | 33 | Create an identity transform. Transforming by the identity does 34 | not change anything, but it can come in handy as a default or 35 | base case. 36 | 37 | / 1 0 0 \ 38 | \ 0 1 0 / 39 | 40 | #### `matrix` 41 | 42 | ``` purescript 43 | matrix :: Float -> Float -> Float -> Float -> Float -> Float -> Transform2D 44 | ``` 45 | 46 | Create a transformation matrix. This lets you create transforms 47 | such as scales, shears, reflections, and translations. 48 | 49 | matrix a b c d x y 50 | 51 | / a b x \ 52 | \ c d y / 53 | 54 | Note that `x` and `y` are the translation values. 55 | 56 | #### `multiply` 57 | 58 | ``` purescript 59 | multiply :: Transform2D -> Transform2D -> Transform2D 60 | ``` 61 | 62 | Multiply two transforms together. 63 | 64 | multiply m n 65 | 66 | / ma mb mx \ / na nb nx \ 67 | | mc md my | . | nc nd ny | 68 | \ 0 0 1 / \ 0 0 1 / 69 | 70 | #### `rotation` 71 | 72 | ``` purescript 73 | rotation :: Float -> Transform2D 74 | ``` 75 | 76 | Create a [rotation matrix](http://en.wikipedia.org/wiki/Rotation_matrix). 77 | Given an angle t, it creates a counterclockwise rotation matrix: 78 | 79 | rotation t 80 | 81 | / cos t -sin t 0 \ 82 | \ sin t cos t 0 / 83 | 84 | #### `translation` 85 | 86 | ``` purescript 87 | translation :: Float -> Float -> Transform2D 88 | ``` 89 | 90 | Create a transformation matrix for translation. 91 | 92 | translation x y 93 | 94 | / 1 0 x \ 95 | \ 0 1 y / 96 | 97 | #### `scale` 98 | 99 | ``` purescript 100 | scale :: Float -> Transform2D 101 | ``` 102 | 103 | Creates a transformation matrix for scaling by all directions. 104 | 105 | scale s 106 | 107 | / s 0 0 \ 108 | \ 0 s 0 / 109 | 110 | #### `scaleX` 111 | 112 | ``` purescript 113 | scaleX :: Float -> Transform2D 114 | ``` 115 | 116 | Create a transformation for horizontal scaling. 117 | 118 | #### `scaleY` 119 | 120 | ``` purescript 121 | scaleY :: Float -> Transform2D 122 | ``` 123 | 124 | Create a transformation for vertical scaling. 125 | 126 | #### `toCSS` 127 | 128 | ``` purescript 129 | toCSS :: Transform2D -> String 130 | ``` 131 | 132 | 133 | -------------------------------------------------------------------------------- /generated-docs/Elm/Tuple.md: -------------------------------------------------------------------------------- 1 | ## Module Elm.Tuple 2 | 3 | Some helpers for working with 2-tuples. 4 | 5 | **Note:** For larger chunks of data, it is best to switch to using records. So 6 | instead of representing a 3D point as `(3,4,5)` and wondering why there are no 7 | helper functions, represent it as `{ x = 3, y = 4, z = 5 }` and use all the 8 | built-in syntax for records. 9 | 10 | This module was added in Elm 0.18. 11 | 12 | Implemented using Purescript's `Data.Tuple` 13 | 14 | #### `first` 15 | 16 | ``` purescript 17 | first :: forall a1 a2. Tuple a1 a2 -> a1 18 | ``` 19 | 20 | Extract the first value from a tuple. 21 | 22 | first (Tuple 3 4) == 3 23 | first (Tuple "john" "doe") == "john" 24 | 25 | Equivalent to Purescript's `fst` 26 | 27 | #### `second` 28 | 29 | ``` purescript 30 | second :: forall a1 a2. Tuple a1 a2 -> a2 31 | ``` 32 | 33 | Extract the second value from a tuple. 34 | 35 | second (Tuple 3 4) == 4 36 | second (Tuple "john" "doe") == "doe" 37 | 38 | Equivalent to Purescript's `snd` 39 | 40 | #### `mapFirst` 41 | 42 | ``` purescript 43 | mapFirst :: forall a b a2. (a -> b) -> Tuple a a2 -> Tuple b a2 44 | ``` 45 | 46 | Transform the first value in a tuple. 47 | 48 | import String 49 | 50 | mapFirst String.reverse (Tuple "stressed" 16) == (Tuple "desserts" 16) 51 | mapFirst String.length (Tuple "stressed" 16) == (Tuple 8 16) 52 | 53 | Equivalent to Purescript's `lmap` 54 | 55 | #### `mapSecond` 56 | 57 | ``` purescript 58 | mapSecond :: forall a b a1. (a -> b) -> Tuple a1 a -> Tuple a1 b 59 | ``` 60 | 61 | Transform the second value in a tuple. 62 | 63 | import String 64 | 65 | mapSecond sqrt ("stressed", 16) == ("stressed", 4) 66 | mapSecond (\x -> x + 1) ("stressed", 16) == ("stressed", 17) 67 | 68 | Equivalent to Purescript's `map` 69 | 70 | 71 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "postinstall": "bower install", 5 | "build": "pulp build", 6 | "clean": "rimraf output && rimraf .pulp-cache", 7 | "docs": "pulp docs", 8 | "test": "pulp test", 9 | "simple": "pulp run -m Examples.Simple -I examples" 10 | }, 11 | "devDependencies": { 12 | "bower": "^1.8.4", 13 | "pulp": "^12.0.0", 14 | "purescript": "^0.11.7", 15 | "purescript-psa": "^0.6.0", 16 | "rimraf": "^2.6.2" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Elm/Apply.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | Elm modules typically use `map2` through `map5` for what Purescript's 3 | -- | `Apply` class would call `lift2` through `lift5`. 4 | -- | 5 | -- | So, we define `map2` through `map5` here as synonyms for `lift2` through 6 | -- | `lift5`. We also re-export these in the individual Elm modules that use 7 | -- | them, so that that the API matches with the Elm API. 8 | -- | 9 | -- | A few Elm modules use up to `map8`, so we implement those here as well. 10 | -- | 11 | -- | We also make `andMap` a synonym for Purescript's `apply`. 12 | 13 | module Elm.Apply 14 | ( andMap 15 | , map2, map3, map4, map5, map6, map7, map8 16 | ) where 17 | 18 | 19 | import Control.Apply (lift2, lift3, lift4, lift5) 20 | import Prelude (class Apply, apply, (<$>), (<*>)) 21 | 22 | 23 | -- | Map a function of two arguments over some container type. 24 | -- | 25 | -- | The equivalent of Purescript's `lift2`. 26 | map2 :: ∀ w a b c. (Apply w) => (a -> b -> c) -> w a -> w b -> w c 27 | map2 = lift2 28 | 29 | 30 | -- | Map a function of three arguments over some container type. 31 | -- | 32 | -- | The equivalent of Purescript's `lift3`. 33 | map3 :: ∀ w a b c d. (Apply w) => (a -> b -> c -> d) -> w a -> w b -> w c -> w d 34 | map3 = lift3 35 | 36 | 37 | -- | Map a function of four arguments over some container type. 38 | -- | 39 | -- | The equivalent of Purescript's `lift4`. 40 | map4 :: ∀ w a b c d e. (Apply w) => (a -> b -> c -> d -> e) -> w a -> w b -> w c -> w d -> w e 41 | map4 = lift4 42 | 43 | 44 | -- | Map a function of five arguments over some container type. 45 | -- | 46 | -- | The equivalent of Purescript's `lift5`. 47 | map5 :: ∀ w a b c d e f. (Apply w) => (a -> b -> c -> d -> e -> f) -> w a -> w b -> w c -> w d -> w e -> w f 48 | map5 = lift5 49 | 50 | 51 | -- | Map a function of six arguments over some container type. 52 | map6 :: ∀ w a b c d e f g. (Apply w) => (a -> b -> c -> d -> e -> f -> g) -> w a -> w b -> w c -> w d -> w e -> w f -> w g 53 | map6 func a b c d e f = 54 | func <$> a <*> b <*> c <*> d <*> e <*> f 55 | 56 | 57 | -- | Map a function of seven arguments over some container type. 58 | map7 :: ∀ w a b c d e f g h. (Apply w) => (a -> b -> c -> d -> e -> f -> g -> h) -> w a -> w b -> w c -> w d -> w e -> w f -> w g -> w h 59 | map7 func a b c d e f g = 60 | func <$> a <*> b <*> c <*> d <*> e <*> f <*> g 61 | 62 | 63 | -- | Map a function of eight arguments over some container type. 64 | map8 :: ∀ w a b c d e f g h i. (Apply w) => (a -> b -> c -> d -> e -> f -> g -> h -> i) -> w a -> w b -> w c -> w d -> w e -> w f -> w g -> w h -> w i 65 | map8 func a b c d e f g h = 66 | func <$> a <*> b <*> c <*> d <*> e <*> f <*> g <*> h 67 | 68 | 69 | -- | Map a function in a container to a value in a container. 70 | -- | 71 | -- | This is the equivalent of Purescript's `apply`. 72 | andMap :: ∀ a b f. (Apply f) => f (a -> b) -> f a -> f b 73 | andMap = apply 74 | -------------------------------------------------------------------------------- /src/Elm/Array.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | > A library for fast immutable arrays. The elements in an array must have the 3 | -- | > same type. 4 | -- | 5 | -- | This is based on the Purescript `Data.Sequence` package -- an `Array` is a 6 | -- | `Data.Sequence.Seq`, so you can use additional functions from that package 7 | -- | as well. 8 | -- | 9 | -- | Note that the Purescript primitive `Array` type is something different -- 10 | -- | it is actually a Javascript array. So, if you're importing this unqualified, 11 | -- | you'll probably need to do something like: 12 | -- | 13 | -- | import Prim hiding (Array) 14 | -- | 15 | -- | to avoid an ambiguity. 16 | 17 | module Elm.Array 18 | ( module Virtual 19 | , Array, fromList, toList, toIndexedList 20 | , repeat, push, get, set 21 | , slice, indexedMap, initialize 22 | ) where 23 | 24 | 25 | -- For re-export 26 | 27 | import Data.Sequence (filter, empty, length) as Virtual 28 | import Data.Foldable (foldr) as Virtual 29 | import Prelude (append, map) as Virtual 30 | import Elm.Foldable (foldl) as Virtual 31 | 32 | -- Internal 33 | 34 | import Data.Sequence 35 | ( Seq, toUnfoldable, fromFoldable, empty, replace 36 | , snoc, index, null, take, drop, length 37 | ) 38 | 39 | -- Prevents conflict with the locally-defined `Array` type. 40 | import Prim hiding (Array) 41 | 42 | import Elm.Basics (Bool) 43 | import Data.Array as DA 44 | import Data.Foldable (class Foldable) 45 | import Data.Foldable as Foldable 46 | import Data.Unfoldable (class Unfoldable) 47 | import Data.Ord (clamp) 48 | import Elm.Maybe (Maybe) 49 | import Data.Tuple (Tuple(..), snd) 50 | import Data.Monoid (class Monoid, mempty) 51 | 52 | import Prelude 53 | ( class Functor, (<$>) 54 | , class Applicative, pure 55 | , ($), (-), const, flip, (>=), (<=), (+), (<<<), (<>) 56 | ) 57 | 58 | -- | The `Array` type is synonym for `Data.Sequence.Seq`. 59 | type Array = Seq 60 | 61 | 62 | -- | > Initialize an array. `initialize n f` creates an array of length `n` with 63 | -- | > the element at index `i` initialized to the result of `(f i)`. 64 | -- | > 65 | -- | > initialize 4 identity == fromList [0,1,2,3] 66 | -- | > initialize 4 (\n -> n*n) == fromList [0,1,4,9] 67 | -- | > initialize 4 (always 0) == fromList [0,0,0,0] 68 | initialize :: ∀ a. Int -> (Int -> a) -> Array a 69 | initialize len func = 70 | if len <= 0 71 | then empty 72 | else 73 | func <$> 74 | fromFoldable (DA.range 0 (len - 1)) 75 | 76 | 77 | -- | > Creates an array with a given length, filled with a default element. 78 | -- | > 79 | -- | > repeat 5 0 == fromList [0,0,0,0,0] 80 | -- | > repeat 3 "cat" == fromList ["cat","cat","cat"] 81 | -- | > 82 | -- | > Notice that `repeat 3 x` is the same as `initialize 3 (always x)`. 83 | repeat :: ∀ a. Int -> a -> Array a 84 | repeat n e = 85 | initialize n (const e) 86 | 87 | 88 | -- | > Create an array from a list. 89 | -- | 90 | -- | Note that this actually works with any `Foldable`. 91 | fromList :: ∀ f a. (Foldable f) => f a -> Array a 92 | fromList = fromFoldable 93 | 94 | 95 | -- | > Create a list of elements from an array. 96 | -- | > 97 | -- | > toList (fromList [3,5,8]) == [3,5,8] 98 | -- | 99 | -- | Note that this actually works with any type that is both a 100 | -- | `Functor` and an `Unfoldable`. 101 | toList :: ∀ f a. Functor f => Unfoldable f => Array a -> f a 102 | toList = toUnfoldable 103 | 104 | 105 | -- | > Create an indexed list from an array. Each element of the array will be 106 | -- | > paired with its index. 107 | -- | > 108 | -- | > toIndexedList (fromList ["cat","dog"]) == [Tuple 0 "cat", Tuple 1 "dog"] 109 | -- | 110 | -- | The container in the return type is defined polymorphically to accommodate 111 | -- | `List` and Purescript's `Array`, among others. 112 | toIndexedList :: ∀ f a. Applicative f => Monoid (f (Tuple Int a)) => Array a -> f (Tuple Int a) 113 | toIndexedList arr = 114 | snd $ Foldable.foldr step (Tuple ((length arr) - 1) mempty) arr 115 | where 116 | step item (Tuple index list) = 117 | Tuple (index - 1) ((pure $ Tuple index item) <> list) 118 | 119 | 120 | -- | > Apply a function on every element with its index as first argument. 121 | -- | > 122 | -- | > indexedMap (*) (fromList [5,5,5]) == fromList [0,5,10] 123 | indexedMap :: ∀ a b. (Int -> a -> b) -> Array a -> Array b 124 | indexedMap func = 125 | snd <<< Foldable.foldl step (Tuple 0 empty) 126 | where 127 | step (Tuple index seq) item = 128 | Tuple (index + 1) (snoc seq (func index item)) 129 | 130 | 131 | -- | > Push an element to the end of an array. 132 | -- | > 133 | -- | > push 3 (fromList [1,2]) == fromList [1,2,3] 134 | -- | 135 | -- | Equivalent to Purescript's `snoc`, but with the arguments flipped. 136 | push :: ∀ a. a -> Array a -> Array a 137 | push = flip snoc 138 | 139 | 140 | -- | > Return Just the element at the index or Nothing if the index is out of range. 141 | -- | > 142 | -- | > get 0 (fromList [0,5,3]) == Just 0 143 | -- | > get 2 (fromList [0,5,3]) == Just 3 144 | -- | > get 5 (fromList [0,5,3]) == Nothing 145 | -- | > get -1 (fromList [0,5,3]) == Nothing 146 | -- | 147 | -- | Equivalent to Purescript's `index`. 148 | get :: ∀ a. Int -> Array a -> Maybe a 149 | get = index 150 | 151 | 152 | -- | > Set the element at a particular index. Returns an updated array. 153 | -- | > If the index is out of range, the array is unaltered. 154 | -- | > 155 | -- | > set 1 7 (fromList [1,2,3]) == fromList [1,7,3] 156 | -- | 157 | -- | Equivalent to Purescript's `replace`, but with the arguments flipped. 158 | set :: ∀ a. Int -> a -> Array a -> Array a 159 | set = flip replace 160 | 161 | 162 | -- | > Get a sub-section of an array: `(slice start end array)`. The `start` is a 163 | -- | > zero-based index where we will start our slice. The `end` is a zero-based index 164 | -- | > that indicates the end of the slice. The slice extracts up to but not including 165 | -- | > `end`. 166 | -- | > 167 | -- | > slice 0 3 (fromList [0,1,2,3,4]) == fromList [0,1,2] 168 | -- | > slice 1 4 (fromList [0,1,2,3,4]) == fromList [1,2,3] 169 | -- | > 170 | -- | > Both the `start` and `end` indexes can be negative, indicating an offset from 171 | -- | > the end of the array. 172 | -- | > 173 | -- | > slice 1 -1 (fromList [0,1,2,3,4]) == fromList [1,2,3] 174 | -- | > slice -2 5 (fromList [0,1,2,3,4]) == fromList [3,4] 175 | -- | > 176 | -- | > This makes it pretty easy to `pop` the last element off of an array: `slice 0 -1 array` 177 | slice :: ∀ a. Int -> Int -> Array a -> Array a 178 | slice start end array = 179 | let 180 | len = 181 | length array 182 | 183 | clamper = 184 | clamp 0 len 185 | 186 | toDrop = 187 | clamper $ 188 | if start >= 0 189 | then start 190 | else len + start 191 | 192 | toTake = 193 | clamper $ 194 | if end >= 0 195 | then end - toDrop 196 | else len + end - toDrop 197 | 198 | in 199 | take toTake $ drop toDrop array 200 | 201 | 202 | -- | > Determine if an array is empty. 203 | -- | > 204 | -- | > isEmpty empty == true 205 | -- | 206 | -- | Equivalent to Purescript's `null`. 207 | isEmpty :: ∀ a. Array a -> Bool 208 | isEmpty = null 209 | -------------------------------------------------------------------------------- /src/Elm/Basics.js: -------------------------------------------------------------------------------- 1 | /* global exports */ 2 | "use strict"; 3 | 4 | // module Elm.Basics 5 | 6 | exports.truncate = function (num) { 7 | return num | 0; 8 | } 9 | -------------------------------------------------------------------------------- /src/Elm/Bind.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | Elm modules typically use `andThen` for what Purescript would call `bind`. 3 | -- | We define the synomyn here generically so that we don't have to define the 4 | -- | function multiple times. And, we can re-export it (as Elm code expects) 5 | -- | without producing conflicts, since it's all the same function. 6 | 7 | module Elm.Bind (andThen) where 8 | 9 | 10 | import Prelude (class Bind, bind, flip) 11 | 12 | 13 | -- | Given some computation, chain its result with another computation. 14 | -- | 15 | -- | Equivalent to Purescript's `bind`. 16 | -- | 17 | -- | The order of the arguments was flipped in Elm 0.18. 18 | andThen :: ∀ m a b. (Bind m) => (a -> m b) -> m a -> m b 19 | andThen = flip bind 20 | -------------------------------------------------------------------------------- /src/Elm/Bitwise.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | > Library for [bitwise operations](http://en.wikipedia.org/wiki/Bitwise_operation) 3 | -- | 4 | -- | Implemented using Purescript's [`Data.Int.Bits`](https://pursuit.purescript.org/packages/purescript-integers) module. 5 | 6 | module Elm.Bitwise 7 | ( module Virtual 8 | , and, or, xor 9 | , shiftLeft, shiftRight, shiftRightLogical 10 | , shiftLeftBy, shiftRightBy, shiftRightZfBy 11 | ) where 12 | 13 | 14 | -- For re-export 15 | 16 | import Data.Int.Bits (complement) as Virtual 17 | 18 | -- Internal 19 | 20 | import Data.Int.Bits ((.&.), (.|.), (.^.), shl, shr, zshr) 21 | import Prelude (flip) 22 | 23 | 24 | -- | > Bitwise AND 25 | -- | 26 | -- | Equivalent to Purescript's `(.&.)` 27 | and :: Int -> Int -> Int 28 | and = (.&.) 29 | 30 | 31 | -- | > Bitwise OR 32 | -- | 33 | -- | Equivalent to Purescript's `(.|.)` 34 | or :: Int -> Int -> Int 35 | or = (.|.) 36 | 37 | 38 | -- | > Bitwise XOR 39 | -- | 40 | -- | Equivalent to Purescript's `(.^.)` 41 | xor :: Int -> Int -> Int 42 | xor = (.^.) 43 | 44 | 45 | -- | > Shift bits to the left by a given offset, filling new bits with zeros. 46 | -- | > This can be used to multiply numbers by powers of two. 47 | -- | > 48 | -- | > 8 `shiftLeft` 1 == 16 49 | -- | > 8 `shiftLeft` 2 == 32 50 | -- | 51 | -- | Equivalent to Purescript's `shl` 52 | -- | 53 | -- | This function was removed in Elm 0.18, in favour of `shiftLeftBy`, 54 | -- | which has its arguments flipped. 55 | shiftLeft :: Int -> Int -> Int 56 | shiftLeft = shl 57 | 58 | 59 | -- | > Shift bits to the left by a given offset, filling new bits with zeros. 60 | -- | > This can be used to multiply numbers by powers of two. 61 | -- | > 62 | -- | > shiftLeftBy 1 5 == 10 63 | -- | > shiftLeftBy 5 1 == 32 64 | -- | 65 | -- | Equivalent to Purescript's `shl`, but with the arguemnts flipped. 66 | -- | 67 | -- | This function was introduced in Elm 0.18. 68 | shiftLeftBy :: Int -> Int -> Int 69 | shiftLeftBy = flip shl 70 | 71 | 72 | -- | > Shift bits to the right by a given offset, filling new bits with 73 | -- | > whatever is the topmost bit. This can be used to divide numbers by powers of two. 74 | -- | > 75 | -- | > 32 `shiftRight` 1 == 16 76 | -- | > 32 `shiftRight` 2 == 8 77 | -- | > -32 `shiftRight` 1 == -16 78 | -- | > 79 | -- | > This is called an 80 | -- | > [arithmetic right shift](http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift), 81 | -- | > often written (>>), and sometimes called a sign-propagating 82 | -- | > right shift because it fills empty spots with copies of the highest bit. 83 | -- | 84 | -- | Equivalent to Purescript's `shr` 85 | -- | 86 | -- | This function was removed in Elm 0.18, in favour of `shiftRightBy`, 87 | -- | which has its arguments flipped. 88 | shiftRight :: Int -> Int -> Int 89 | shiftRight = shr 90 | 91 | 92 | -- | > Shift bits to the right by a given offset, filling new bits with 93 | -- | > whatever is the topmost bit. This can be used to divide numbers by powers of two. 94 | -- | > 95 | -- | > shiftRightBy 1 32 == 16 96 | -- | > shiftRightBy 2 32 == 8 97 | -- | > shiftRightBy 1 -32 == -16 98 | -- | > 99 | -- | > This is called an 100 | -- | > [arithmetic right shift](http://en.wikipedia.org/wiki/Bitwise_operation#Arithmetic_shift), 101 | -- | > often written (>>), and sometimes called a sign-propagating 102 | -- | > right shift because it fills empty spots with copies of the highest bit. 103 | -- | 104 | -- | Equivalent to Purescript's `shr`, but with the arguments flipped. 105 | -- | 106 | -- | This function was introduced in Elm 0.18. 107 | shiftRightBy :: Int -> Int -> Int 108 | shiftRightBy = flip shr 109 | 110 | 111 | -- | > Shift bits to the right by a given offset, filling new bits with 112 | -- | > zeros. 113 | -- | > 114 | -- | > 32 `shiftRightLogical` 1 == 16 115 | -- | > 32 `shiftRightLogical` 2 == 8 116 | -- | > -32 `shiftRightLogical` 1 == 2147483632 117 | -- | > 118 | -- | > This is called an 119 | -- | > [logical right shift](http://en.wikipedia.org/wiki/Bitwise_operation#Logical_shift), 120 | -- | > often written (>>>), and sometimes called a zero-fill right shift because 121 | -- | > it fills empty spots with zeros. 122 | -- | 123 | -- | Equivalent to Purescript's `zshr`. 124 | -- | 125 | -- | This function was removed in Elm 0.18, in favour of `shiftRightZfBy`, 126 | -- | which has its arguments flipped. 127 | shiftRightLogical :: Int -> Int -> Int 128 | shiftRightLogical = zshr 129 | 130 | 131 | -- | > Shift bits to the right by a given offset, filling new bits with 132 | -- | > zeros. 133 | -- | > 134 | -- | > shiftRightZfBy 1 32 == 16 135 | -- | > shiftRightZfBy 2 32 == 8 136 | -- | > shiftRightZfBy 1 -32 == 2147483632 137 | -- | > 138 | -- | > This is called an 139 | -- | > [logical right shift](http://en.wikipedia.org/wiki/Bitwise_operation#Logical_shift), 140 | -- | > often written (>>>), and sometimes called a zero-fill right shift because 141 | -- | > it fills empty spots with zeros. 142 | -- | 143 | -- | Equivalent to Purescript's `zshr`, but with its arguments flipped. 144 | -- | 145 | -- | This function was added in Elm 0.18. 146 | shiftRightZfBy :: Int -> Int -> Int 147 | shiftRightZfBy = flip zshr 148 | -------------------------------------------------------------------------------- /src/Elm/Char.js: -------------------------------------------------------------------------------- 1 | /* global exports */ 2 | "use strict"; 3 | 4 | // module Elm.Char 5 | 6 | exports.toLocaleUpper = function (c) { 7 | return c.toLocaleUpperCase(); 8 | }; 9 | 10 | exports.toLocaleLower = function (c) { 11 | return c.toLocaleLowerCase(); 12 | }; 13 | -------------------------------------------------------------------------------- /src/Elm/Char.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | > Functions for working with characters. Character literals are enclosed in 3 | -- | > `'a'` pair of single quotes. 4 | -- | 5 | -- | Implemented using Purescript's [`Data.Char`](https://pursuit.purescript.org/packages/purescript-strings) module. 6 | 7 | module Elm.Char 8 | ( module Virtual 9 | , KeyCode, toCode, fromCode 10 | , isUpper, isLower, isDigit, isOctDigit, isHexDigit 11 | , toLocaleUpper, toLocaleLower 12 | ) where 13 | 14 | 15 | -- For re-export 16 | 17 | import Data.Char (toLower, toUpper) as Virtual 18 | 19 | -- Internal 20 | 21 | import Data.Char (toCharCode, fromCharCode) 22 | import Elm.Basics (Bool) 23 | import Prelude ((&&), (||), (>=), (<=)) 24 | 25 | 26 | isBetween :: Char -> Char -> Char -> Bool 27 | isBetween low high char = 28 | (code >= toCode low) && (code <= toCode high) 29 | where 30 | code = 31 | toCode char 32 | 33 | 34 | -- | > True for upper case ASCII letters. 35 | isUpper :: Char -> Bool 36 | isUpper = isBetween 'A' 'Z' 37 | 38 | 39 | -- | > True for lower case ASCII letters. 40 | isLower :: Char -> Bool 41 | isLower = isBetween 'a' 'z' 42 | 43 | 44 | -- | > True for ASCII digits `[0-9]`. 45 | isDigit :: Char -> Bool 46 | isDigit = isBetween '0' '9' 47 | 48 | 49 | -- | > True for ASCII octal digits `[0-7]`. 50 | isOctDigit :: Char -> Bool 51 | isOctDigit = isBetween '0' '7' 52 | 53 | 54 | -- | > True for ASCII hexadecimal digits `[0-9a-fA-F]`. 55 | isHexDigit :: Char -> Bool 56 | isHexDigit char = 57 | isDigit char || isBetween 'a' 'f' char || isBetween 'A' 'F' char 58 | 59 | 60 | -- | > Convert to upper case, according to any locale-specific case mappings. 61 | foreign import toLocaleUpper :: Char -> Char 62 | 63 | 64 | -- | > Convert to lower case, according to any locale-specific case mappings. 65 | foreign import toLocaleLower :: Char -> Char 66 | 67 | 68 | -- | > Keyboard keys can be represented as integers. These are called *key codes*. 69 | -- | > You can use [`toCode`](#toCode) and [`fromCode`](#fromCode) to convert between 70 | -- | > key codes and characters. 71 | type KeyCode = Int 72 | 73 | 74 | -- | > Convert to key code. 75 | toCode :: Char -> KeyCode 76 | toCode = toCharCode 77 | 78 | 79 | -- | > Convert from key code. 80 | fromCode :: KeyCode -> Char 81 | fromCode = fromCharCode 82 | -------------------------------------------------------------------------------- /src/Elm/Date.js: -------------------------------------------------------------------------------- 1 | /* global exports */ 2 | "use strict"; 3 | 4 | // module Elm.Date 5 | 6 | exports.fromStringImpl = function (str) { 7 | return new Date(str); 8 | }; 9 | 10 | exports.fromTime = function (time) { 11 | return new Date(time); 12 | }; 13 | -------------------------------------------------------------------------------- /src/Elm/Date.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | > Library for working with dates. 3 | -- | 4 | -- | See notes below about the types used for `Date`, `Day` and `Month`. 5 | 6 | module Elm.Date 7 | ( module Virtual 8 | , Date(..), fromString 9 | , Time, toTime, fromTime 10 | , Day(..), year, month, day, dayOfWeek 11 | , hour, minute, second, millisecond 12 | , now 13 | ) where 14 | 15 | 16 | -- For re-export 17 | 18 | import Data.Date.Component (Month(..)) as Virtual 19 | 20 | -- Internal 21 | 22 | import Data.JSDate 23 | ( JSDate, isValid, getTime 24 | , getFullYear, getMonth, getDate, getDay 25 | , getHours, getMinutes, getSeconds, getMilliseconds 26 | ) 27 | 28 | import Data.Date (Weekday(..), Month) 29 | import Data.Maybe (fromJust) 30 | import Data.Enum (toEnum) 31 | import Data.Int (round) 32 | import Elm.Result (Result(..)) 33 | import Elm.Task (Task) 34 | import Elm.Time as Time 35 | 36 | import Partial (crashWith) 37 | import Partial.Unsafe (unsafePartial) 38 | import Control.Monad.Eff.Unsafe (unsafePerformEff) 39 | 40 | import Prelude ((<<<), (<>), show, ($), (<$>), (+)) 41 | 42 | 43 | -- | Elm's `Date` type is implemented here in terms of Purescript's `JSDate`, 44 | -- | which, in both cases, is a Javascript Date object. 45 | type Date = JSDate 46 | 47 | 48 | -- | Elm's `Day` type is equivalent to `Weekday` in Purescript. 49 | -- | 50 | -- | However, note that in Purescript the constructors spell out the name of the day 51 | -- | ... i.e. `Saturday` instead of `Sat`. 52 | type Day = Weekday 53 | 54 | 55 | -- | An alias for units of time, representing milliseconds. 56 | type Time = Number 57 | 58 | 59 | -- | Attempt to read a date from a string. 60 | fromString :: String -> Result String Date 61 | fromString str = 62 | let 63 | result = 64 | fromStringImpl str 65 | 66 | in 67 | if isValid result 68 | then Ok result 69 | else Err ("unable to parse '" <> str <> "' as a date") 70 | 71 | 72 | -- Basically, calls `new Date(d)` 73 | foreign import fromStringImpl :: String -> Date 74 | 75 | 76 | -- | > Convert a `Date` to a time in milliseconds. 77 | -- | > 78 | -- | > A time is the number of milliseconds since 79 | -- | > [the Unix epoch](http://en.wikipedia.org/wiki/Unix_time). 80 | toTime :: Date -> Time 81 | toTime = getTime 82 | 83 | 84 | -- | > Convert a time in milliseconds into a `Date`. 85 | -- | > 86 | -- | > A time is the number of milliseconds since 87 | -- | > [the Unix epoch](http://en.wikipedia.org/wiki/Unix_time). 88 | foreign import fromTime :: Time -> Date 89 | 90 | 91 | -- | > Extract the year of a given date. Given the date 23 June 1990 at 11:45AM 92 | -- | > this returns the integer `1990`. 93 | -- | 94 | -- | As in the Elm implementation, this implicitly uses the current locale. 95 | year :: Date -> Int 96 | year = round <<< unsafePerformEff <<< getFullYear 97 | 98 | 99 | -- | > Extract the month of a given date. Given the date 23 June 1990 at 11:45AM 100 | -- | > this returns the month `June` as defined below. 101 | -- | 102 | -- | Note that in Purescript, the constructors for `Month` are fully spelled out, 103 | -- | so it is 'June` instead of `Jun`. 104 | -- | 105 | -- | As in the Elm implementation, this implicitly uses the current locale. 106 | month :: Date -> Month 107 | month d = 108 | -- Should be safe, given what `getMonth` can return 109 | unsafePartial (fromJust (toEnum (round (unsafePerformEff (getMonth d)) + 1))) 110 | 111 | 112 | -- | > Extract the day of a given date. Given the date 23 June 1990 at 11:45AM 113 | -- | > this returns the integer `23`. 114 | -- | 115 | -- | As in the Elm implementation, this implicitly uses the current locale. 116 | day :: Date -> Int 117 | day = round <<< unsafePerformEff <<< getDate 118 | 119 | 120 | -- Day is an Enum, but the numbering is different, so this is best 121 | jsDayToDay :: Partial => Int -> Day 122 | jsDayToDay d = 123 | case d of 124 | 0 -> Sunday 125 | 1 -> Monday 126 | 2 -> Tuesday 127 | 3 -> Wednesday 128 | 4 -> Thursday 129 | 5 -> Friday 130 | 6 -> Saturday 131 | _ -> crashWith ("Invalid day of week: " <> show d) 132 | 133 | 134 | -- | > Extract the day of the week for a given date. Given the date 23 June 135 | -- | > 1990 at 11:45AM this returns the day `Saturday` as defined below. 136 | -- | 137 | -- | Note that in Purescript, the days of the week are fully spelled out, 138 | -- | so it is `Thursday` instead of `Thu`. 139 | -- | 140 | -- | As in the Elm implementation, this implicitly uses the current locale. 141 | dayOfWeek :: Date -> Day 142 | dayOfWeek = 143 | -- Should be safe, given what `getDay` can return 144 | unsafePartial $ jsDayToDay <<< round <<< unsafePerformEff <<< getDay 145 | 146 | 147 | -- | > Extract the hour of a given date. Given the date 23 June 1990 at 11:45AM 148 | -- | > this returns the integer `11`. 149 | -- | 150 | -- | As in the Elm implementation, this implicitly uses the current locale. 151 | hour :: Date -> Int 152 | hour = round <<< unsafePerformEff <<< getHours 153 | 154 | 155 | -- | > Extract the minute of a given date. Given the date 23 June 1990 at 11:45AM 156 | -- | > this returns the integer `45`. 157 | -- | 158 | -- | As in the Elm implementation, this implicitly uses the current locale. 159 | minute :: Date -> Int 160 | minute = round <<< unsafePerformEff <<< getMinutes 161 | 162 | 163 | -- | > Extract the second of a given date. Given the date 23 June 1990 at 11:45AM 164 | -- | > this returns the integer `0`. 165 | -- | 166 | -- | As in the Elm implementation, this implicitly uses the current locale. 167 | second :: Date -> Int 168 | second = round <<< unsafePerformEff <<< getSeconds 169 | 170 | 171 | -- | > Extract the millisecond of a given date. Given the date 23 June 1990 at 11:45:30.123AM 172 | -- | > this returns the integer `123`. 173 | -- | 174 | -- | As in the Elm implementation, this implicitly uses the current locale. 175 | millisecond :: Date -> Int 176 | millisecond = round <<< unsafePerformEff <<< getMilliseconds 177 | 178 | 179 | -- | > Get the `Date` at the moment when this task is run. 180 | -- | 181 | -- | Added in Elm 0.17 / version 4.0.0 of elm-lang/core 182 | now :: ∀ x. Task x Date 183 | now = 184 | fromTime <$> Time.now 185 | -------------------------------------------------------------------------------- /src/Elm/Debug.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | This library is for investigating bugs or performance problems. 3 | 4 | module Elm.Debug 5 | ( log, crash 6 | ) where 7 | 8 | -- TODO: Is there anything sensible to do with `watch`, `watchSummary` and `trace`? 9 | 10 | 11 | import Debug.Trace (trace, spy) 12 | import Prelude ((<>)) 13 | import Partial.Unsafe (unsafeCrashWith) 14 | 15 | 16 | -- | Log a tagged value on the developer console, and then return the value. 17 | -- | 18 | -- | 1 + log "number" 1 -- equals 2, logs "number: 1" 19 | -- | length (log "start" []) -- equals 0, logs "start: []" 20 | -- | 21 | -- | Notice that `log` is not a pure function! It should *only* be used for 22 | -- | investigating bugs or performance problems. 23 | log :: ∀ a. String -> a -> a 24 | log tag value = 25 | trace (tag <> ": ") (\_ -> spy value) 26 | 27 | 28 | -- | Crash the program with an error message. 29 | -- | 30 | -- | Equivalent to Purescript's `Partial.Unsafe.unsafeCrashWith` 31 | crash :: ∀ a. String -> a 32 | crash = unsafeCrashWith 33 | -------------------------------------------------------------------------------- /src/Elm/Default.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | This module re-exports the things which Elm imports by default. 3 | -- | 4 | -- | So, if you want the Elm default imports, you can do 5 | -- | 6 | -- | `import Elm.Default` 7 | 8 | module Elm.Default 9 | ( module Virtual 10 | , module Elm.Basics 11 | ) where 12 | 13 | 14 | import Data.Maybe (Maybe (Just, Nothing)) as Virtual 15 | import Data.List (List, (:)) as Virtual 16 | import Data.Tuple (Tuple(..)) as Virtual 17 | import Data.Tuple.Nested (type (/\), (/\)) as Virtual 18 | import Elm.Basics 19 | import Elm.Monoid (none) as Virtual 20 | import Elm.Platform (Program) as Virtual 21 | import Elm.Platform.Cmd (Cmd, (!)) as Virtual 22 | import Elm.Platform.Sub (Sub) as Virtual 23 | import Elm.Result (Result (Ok, Err)) as Virtual 24 | 25 | 26 | -- These are Elm's default imports ... 27 | -- 28 | -- 29 | -- 30 | -- import Basics exposing (..) 31 | -- import List exposing (List, (::)) 32 | -- import Maybe exposing (Maybe(..)) 33 | -- import Result exposing (Result(..)) 34 | -- import String exposing (String) 35 | -- import Char exposing (Char) 36 | -- import Tuple 37 | -- 38 | -- import Debug 39 | -- 40 | -- import Platform exposing ( Program ) 41 | -- import Platform.Cmd as Cmd exposing ( Cmd ) 42 | -- import Platform.Sub as Sub exposing ( Sub ) 43 | -------------------------------------------------------------------------------- /src/Elm/Dict.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | > A dictionary mapping unique keys to values. The keys can be any type which 3 | -- | > has an instance of the `Ord` class. 4 | -- | 5 | -- | This is implemented in terms of Purescript's `Data.Map`. 6 | 7 | module Elm.Dict 8 | ( module Virtual 9 | , Dict, get, remove, update 10 | , intersect, diff, filter, partition, merge 11 | , map, foldl, foldr 12 | , toUnfoldable, toList, fromList 13 | ) where 14 | 15 | 16 | -- For re-export 17 | 18 | import Data.Bifunctor (lmap, rmap) 19 | import Data.Foldable (class Foldable) 20 | import Data.List (List(..), (:)) 21 | import Data.Map (Map, alter, delete, empty, filterWithKey, fromFoldable, insert, lookup, mapWithKey, member, toAscUnfoldable) 22 | import Data.Map (empty, isEmpty, size, member, singleton, insert, fromFoldable, keys, values, union) as Virtual 23 | import Data.Maybe (Maybe) 24 | import Data.Tuple (Tuple(..)) 25 | import Data.Unfoldable (class Unfoldable) 26 | import Elm.Basics (Bool) 27 | import Elm.List as ElmList 28 | import Prelude (class Ord, flip, (<), (>)) 29 | 30 | 31 | -- | Elm's `Dict` type is a synonym for Purescript's `Data.Map`. 32 | type Dict = Map 33 | 34 | 35 | -- TODO: It feels as though there ought to be a better implementation available 36 | -- of various functions below, perhaps via bifunctor, profunctor or traversable? 37 | 38 | 39 | -- | > Get the value associated with a key. If the key is not found, return 40 | -- | > `Nothing`. This is useful when you are not sure if a key will be in the 41 | -- | > dictionary. 42 | -- | > 43 | -- | > animals = fromList [ ("Tom", Cat), ("Jerry", Mouse) ] 44 | -- | > 45 | -- | > get "Tom" animals == Just Cat 46 | -- | > get "Jerry" animals == Just Mouse 47 | -- | > get "Spike" animals == Nothing 48 | -- | 49 | -- | Equivalent to Purescript's `lookup`. 50 | get :: ∀ k v. (Ord k) => k -> Dict k v -> Maybe v 51 | get = lookup 52 | 53 | 54 | -- | > Remove a key-value pair from a dictionary. If the key is not found, 55 | -- | > no changes are made. 56 | -- | 57 | -- | Equivalent to Purescript's `delete`. 58 | remove :: ∀ k v. (Ord k) => k -> Dict k v -> Dict k v 59 | remove = delete 60 | 61 | 62 | -- | > Update the value of a dictionary for a specific key with a given function. 63 | -- | 64 | -- | Like Purescript's `alter`, but with flipped arguments. 65 | update :: ∀ k v. (Ord k) => k -> (Maybe v -> Maybe v) -> Dict k v -> Dict k v 66 | update = flip alter 67 | 68 | 69 | -- | > Keep a key-value pair when its key appears in the second dictionary. 70 | -- | > Preference is given to values in the first dictionary. 71 | intersect :: ∀ k v. (Ord k) => Dict k v -> Dict k v -> Dict k v 72 | intersect t1 t2 = 73 | filter (\k _ -> member k t2) t1 74 | 75 | 76 | -- | > Keep a key-value pair when its key does not appear in the second dictionary. 77 | diff :: ∀ k v. (Ord k) => Dict k v -> Dict k v -> Dict k v 78 | diff t1 t2 = 79 | foldl (\k v t -> remove k t) t1 t2 80 | 81 | 82 | -- | > Keep a key-value pair when it satisfies a predicate. 83 | -- | 84 | -- | Equivalent to Purescript's `filterWithKey` 85 | filter :: ∀ k v. (Ord k) => (k -> v -> Bool) -> Dict k v -> Dict k v 86 | filter = filterWithKey 87 | 88 | 89 | -- | > Partition a dictionary according to a predicate. The first dictionary 90 | -- | > contains all key-value pairs which satisfy the predicate, and the second 91 | -- | > contains the rest. 92 | partition :: ∀ k v. (Ord k) => (k -> v -> Bool) -> Dict k v -> Tuple (Dict k v) (Dict k v) 93 | partition predicate = 94 | foldl add (Tuple empty empty) 95 | 96 | where 97 | add key value = 98 | (if predicate key value then lmap else rmap) (insert key value) 99 | 100 | 101 | -- | > Apply a function to all values in a dictionary. 102 | -- | 103 | -- | Equivalent to Purescript's `mapWithKey` 104 | map :: ∀ k a b. (Ord k) => (k -> a -> b) -> Dict k a -> Dict k b 105 | map = mapWithKey 106 | 107 | 108 | -- | > Fold over the key-value pairs in a dictionary, in order from lowest 109 | -- | > key to highest key. 110 | foldl :: ∀ k v b. (Ord k) => (k -> v -> b -> b) -> b -> Dict k v -> b 111 | foldl f acc dict = 112 | -- TODO: There has got to be a way to do this without constructing an 113 | -- intermediate list. 114 | let 115 | tuples :: List (Tuple k v) 116 | tuples = toList dict 117 | 118 | folder :: Tuple k v -> b -> b 119 | folder (Tuple k v) = f k v 120 | 121 | in 122 | ElmList.foldl folder acc tuples 123 | 124 | 125 | -- | > Fold over the key-value pairs in a dictionary, in order from highest 126 | -- | > key to lowest key. 127 | foldr :: ∀ k v b. (Ord k) => (k -> v -> b -> b) -> b -> Dict k v -> b 128 | foldr f acc dict = 129 | -- TODO: There has got to be a way to do this without constructing an 130 | -- intermediate list. 131 | let 132 | tuples :: List (Tuple k v) 133 | tuples = toList dict 134 | 135 | folder :: Tuple k v -> b -> b 136 | folder (Tuple k v) = f k v 137 | 138 | in 139 | ElmList.foldr folder acc tuples 140 | 141 | 142 | -- | Produces tuples of keys and values in any container that has an 143 | -- | `Unfoldable` instance. This is defined polymorphically to accommodate Purescript `Array`, 144 | -- | among others. 145 | -- | 146 | -- | Note that this is not in the Elm API. 147 | toUnfoldable :: ∀ f k v. Unfoldable f => Dict k v -> f (Tuple k v) 148 | toUnfoldable = 149 | toAscUnfoldable 150 | 151 | 152 | -- | > Convert a dictionary into an association list of key-value pairs, sorted by keys. 153 | toList :: ∀ f k v. Unfoldable f => Dict k v -> f (Tuple k v) 154 | toList = toAscUnfoldable 155 | 156 | 157 | fromList :: ∀ f k v. Ord k => Foldable f => f (Tuple k v) -> Dict k v 158 | fromList = fromFoldable 159 | 160 | 161 | -- | > The most general way of combining two dictionaries. You provide three 162 | -- | > accumulators for when a given key appears: 163 | -- | > 164 | -- | > 1. Only in the left dictionary. 165 | -- | > 2. In both dictionaries. 166 | -- | > 3. Only in the right dictionary. 167 | -- | > 168 | -- | > You then traverse all the keys from lowest to highest, building up whatever 169 | -- | > you want. 170 | -- | 171 | -- | Introduced in Elm 0.17. 172 | merge 173 | :: ∀ k a b result. Ord k 174 | => (k -> a -> result -> result) 175 | -> (k -> a -> b -> result -> result) 176 | -> (k -> b -> result -> result) 177 | -> Dict k a 178 | -> Dict k b 179 | -> result 180 | -> result 181 | merge leftStep bothStep rightStep leftDict rightDict initialResult = 182 | let 183 | stepState rKey rValue (Tuple list result) = 184 | case list of 185 | Nil -> 186 | Tuple list (rightStep rKey rValue result) 187 | 188 | Tuple lKey lValue : rest -> 189 | if lKey < rKey then 190 | stepState rKey rValue (Tuple rest (leftStep lKey lValue result)) 191 | else if lKey > rKey then 192 | Tuple list (rightStep rKey rValue result) 193 | else 194 | Tuple rest (bothStep lKey lValue rValue result) 195 | 196 | (Tuple leftovers intermediateResult) = 197 | foldl stepState (Tuple (toList leftDict) initialResult) rightDict 198 | in 199 | ElmList.foldl (\(Tuple k v) result -> leftStep k v result) intermediateResult leftovers 200 | -------------------------------------------------------------------------------- /src/Elm/Foldable.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | Elm modules define `foldl` with a different signature than Purescript's. 3 | -- | So, we define that alternative `foldl` here. 4 | 5 | module Elm.Foldable (foldl) where 6 | 7 | 8 | import Data.Foldable (class Foldable) 9 | import Data.Foldable as Foldable 10 | import Prelude (flip, (<<<)) 11 | 12 | 13 | -- | Reduce a container from the left. 14 | -- | 15 | -- | Equivalent to Purescript's `foldl`, but the function you supply is flipped. 16 | foldl :: ∀ a b f. (Foldable f) => (a -> b -> b) -> b -> f a -> b 17 | foldl = Foldable.foldl <<< flip 18 | -------------------------------------------------------------------------------- /src/Elm/FunctorWithIndex.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | Elm modules sometimes define `indexedMap` as a synonym for Purescript's 3 | -- | `mapWithIndex`. So, we define that generally here. 4 | 5 | module Elm.FunctorWithIndex (indexedMap) where 6 | 7 | 8 | import Data.FunctorWithIndex (class FunctorWithIndex, mapWithIndex) 9 | 10 | 11 | -- | Map over a container with an index. 12 | -- | 13 | -- | Equivalent to Purescript's `mapWithIndex` 14 | indexedMap :: ∀ i f a b. FunctorWithIndex i f => (i -> a -> b) -> f a -> f b 15 | indexedMap = mapWithIndex 16 | -------------------------------------------------------------------------------- /src/Elm/Json/Decode.js: -------------------------------------------------------------------------------- 1 | /* global exports */ 2 | "use strict"; 3 | 4 | // module Elm.Json.Decode 5 | 6 | 7 | exports.unsafeKeys = function (object) { 8 | var keys = []; 9 | 10 | for (var key in object) { 11 | keys.push(key); 12 | } 13 | 14 | return keys; 15 | } 16 | -------------------------------------------------------------------------------- /src/Elm/Json/Encode.js: -------------------------------------------------------------------------------- 1 | /* global exports */ 2 | "use strict"; 3 | 4 | // module Elm.Json.Encode 5 | 6 | exports.encode = function (indentLevel) { 7 | return function (value) { 8 | return JSON.stringify(value, null, indentLevel); 9 | } 10 | } 11 | 12 | exports.encodeNull = null; 13 | 14 | -------------------------------------------------------------------------------- /src/Elm/Json/Encode.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | A library for turning Elm values into Json values. 3 | -- | 4 | -- | This is mainly implemented via the `toForeign` method in 5 | -- | [purescript-foreign](https://pursuit.purescript.org/packages/purescript-foreign/0.7.2/docs/Data.Foreign#v:toForeign). 6 | -- | 7 | -- | You could also consider the purescript-argonaut-* modules. 8 | 9 | module Elm.Json.Encode 10 | ( Value 11 | , encode 12 | , string, int, float, bool, null 13 | , list, array 14 | , object 15 | ) where 16 | 17 | 18 | import Data.Foreign (Foreign, toForeign) 19 | import Data.List (List) 20 | import Data.List as List 21 | import Data.Tuple (Tuple) 22 | import Elm.Basics (Float, Bool) 23 | import Data.Foldable (class Foldable, foldl) 24 | import Prelude ((<<<), flip) 25 | import Data.Array (cons, reverse) 26 | import Data.StrMap as StrMap 27 | 28 | 29 | -- | Represents a JavaScript value. 30 | type Value = Foreign 31 | 32 | 33 | -- | Convert a `Value` into a prettified string. The first argument specifies 34 | -- | the amount of indentation in the resulting string. 35 | -- | 36 | -- | person = 37 | -- | object 38 | -- | [ Tuple "name" (string "Tom") 39 | -- | , Tuple "age" (int 42) 40 | -- | ] 41 | -- | 42 | -- | compact = encode 0 person 43 | -- | -- {"name":"Tom","age":42} 44 | -- | 45 | -- | readable = encode 4 person 46 | -- | -- { 47 | -- | -- "name": "Tom", 48 | -- | -- "age": 42 49 | -- | -- } 50 | foreign import encode :: Int -> Value -> String 51 | 52 | 53 | -- | Turn a `String` into a `Value`. 54 | string :: String -> Value 55 | string = toForeign 56 | 57 | 58 | -- | Turn an `Int` into a `Value`. 59 | int :: Int -> Value 60 | int = toForeign 61 | 62 | 63 | -- | Encode a Float. `Infinity` and `NaN` are encoded as `null`. 64 | float :: Float -> Value 65 | float = toForeign 66 | 67 | 68 | -- | Encode a `Bool`. 69 | bool :: Bool -> Value 70 | bool = toForeign 71 | 72 | 73 | -- | Encode a null value. 74 | null :: Value 75 | null = encodeNull 76 | 77 | foreign import encodeNull :: Value 78 | 79 | 80 | -- | Encode a JSON object. 81 | -- | 82 | -- | The signature uses `Foldable` in order to work with `List` or 83 | -- | `Array`, amongst others. 84 | object :: ∀ f. (Foldable f) => f (Tuple String Value) -> Value 85 | object = toForeign <<< StrMap.fromFoldable 86 | 87 | 88 | -- | Encode Purescript's primitive `Array` type (distinct from Elm's `Array`). 89 | psArray :: Array Value -> Value 90 | psArray = toForeign 91 | 92 | 93 | -- | Encode an array type. Uses a polymorphic type in order to accommodate 94 | -- | Purescript `Array` and `Elm.Array`, among others. 95 | array :: ∀ f. (Foldable f) => f Value -> Value 96 | array = psArray <<< reverse <<< foldl (flip cons) [] 97 | 98 | 99 | -- | Encode a `List`. 100 | list :: List Value -> Value 101 | list = psArray <<< List.toUnfoldable 102 | -------------------------------------------------------------------------------- /src/Elm/Maybe.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | > This library fills a bunch of important niches in Elm. A `Maybe` can help 3 | -- | > you with optional arguments, error handling, and records with optional fields. 4 | -- | 5 | -- | This is implemented in terms of Purescript's `Data.Maybe`, so you can use functions 6 | -- | from there on `Maybe` values as well. 7 | 8 | module Elm.Maybe 9 | ( module Virtual 10 | , withDefault 11 | ) where 12 | 13 | 14 | -- For re-export 15 | 16 | import Data.Foldable (oneOf) as Virtual 17 | import Data.Maybe (Maybe(..)) as Virtual 18 | import Prelude (map) as Virtual 19 | import Elm.Apply (map2, map3, map4, map5) as Virtual 20 | import Elm.Bind (andThen) as Virtual 21 | 22 | -- Internal 23 | 24 | import Data.Maybe (Maybe, fromMaybe) 25 | 26 | 27 | -- | > Provide a default value, turning an optional value into a normal 28 | -- | > value. This comes in handy when paired with functions like 29 | -- | > [`Dict.get`](Dict#get) which gives back a `Maybe`. 30 | -- | > 31 | -- | > withDefault 100 (Just 42) -- 42 32 | -- | > withDefault 100 Nothing -- 100 33 | -- | > 34 | -- | > withDefault "unknown" (Dict.get "Tom" Dict.empty) -- "unknown" 35 | -- | 36 | -- | Equivalent to Purescript's 'fromMaybe`. 37 | withDefault :: ∀ a. a -> Maybe a -> a 38 | withDefault = fromMaybe 39 | -------------------------------------------------------------------------------- /src/Elm/Monoid.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | Elm modules sometimes define a `none` function that corresponds to Purescript's 3 | -- | `mempty`, and a `batch` function that corresponds to Purescript's `fold`. So, 4 | -- | we re-export these here with the Elm-ish names. 5 | 6 | module Elm.Monoid (batch, none) where 7 | 8 | 9 | import Data.Foldable (class Foldable, fold) 10 | import Data.Monoid (class Monoid, mempty) 11 | 12 | 13 | -- | Produce an "empty" value of the relevant type. 14 | -- | 15 | -- | Equivalent to Purescript's `mempty`. 16 | none :: ∀ m. Monoid m => m 17 | none = mempty 18 | 19 | 20 | -- | Smush together a bunch of things. 21 | -- | 22 | -- | Equivalent to Purescript's `fold` 23 | batch :: ∀ f m. Foldable f => Monoid m => f m -> m 24 | batch = fold 25 | -------------------------------------------------------------------------------- /src/Elm/Platform/Cmd.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | # Effects 3 | -- | 4 | -- | Elm has **managed effects**, meaning that things like HTTP requests or writing 5 | -- | to disk are all treated as *data* in Elm. When this data is given to the Elm 6 | -- | runtime system, it can do some “query optimization” before actually performing 7 | -- | the effect. Perhaps unexpectedly, this managed effects idea is the heart of why 8 | -- | Elm is so nice for testing, reuse, reproducibility, etc. 9 | -- | 10 | -- | There are two kinds of managed effects you will use in your programs: commands 11 | -- | and subscriptions. 12 | 13 | module Elm.Platform.Cmd 14 | ( module Virtual 15 | , withCmds 16 | , (!) 17 | ) where 18 | 19 | 20 | import Data.Foldable (class Foldable, fold) 21 | import Data.Monoid (class Monoid) 22 | import Data.Tuple (Tuple(..)) 23 | import Elm.Monoid (batch, none) as Virtual 24 | import Elm.Platform (Cmd) as Virtual 25 | import Prelude ((<<<)) 26 | import Prelude (map) as Virtual 27 | 28 | 29 | withCmds :: ∀ f model cmd. Foldable f => Monoid cmd => model -> f cmd -> Tuple model cmd 30 | withCmds model = 31 | Tuple model <<< fold 32 | 33 | 34 | infixl 5 withCmds as ! 35 | 36 | 37 | -- Wasn't that easy? The real work here is going on in Elm.Platform, of course. 38 | -- It's easier to define the `Sub` type there, in order to avoid cirucular 39 | -- dependencies, and then re-export it here. 40 | -- 41 | -- And, several other functions Elm defines here are based on the instances for 42 | -- Cmd, so they can just be re-exported as well. 43 | -------------------------------------------------------------------------------- /src/Elm/Platform/Sub.purs: -------------------------------------------------------------------------------- 1 | 2 | module Elm.Platform.Sub 3 | ( module Virtual 4 | ) where 5 | 6 | 7 | import Elm.Monoid (batch, none) as Virtual 8 | import Elm.Platform (Sub) as Virtual 9 | import Prelude (map) as Virtual 10 | 11 | 12 | -- Wasn't that easy? The real work here is going on in Elm.Platform, of course. 13 | -- It's easier to define the `Sub` type there, in order to avoid cirucular 14 | -- dependencies, and then re-export it here. 15 | -- 16 | -- Plus, it turns out that everything else you can do with a `Sub` is actually 17 | -- defined by its instances, so we don't have to do anything except re-export 18 | -- stuff. 19 | -------------------------------------------------------------------------------- /src/Elm/Process.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | > Right now, this library is pretty sparse. For example, there is no public API 3 | -- | > for processes to communicate with each other. This is a really important 4 | -- | > ability, but it is also something that is extraordinarily easy to get wrong! 5 | 6 | module Elm.Process 7 | ( Id 8 | , spawn 9 | , sleep 10 | , kill 11 | ) where 12 | 13 | 14 | import Control.Monad.Aff (forkAff, delay, killFiber, apathize) 15 | import Control.Monad.Aff.Class (liftAff) 16 | import Control.Monad.Eff.Exception (error) 17 | import Control.Monad.Except.Trans (ExceptT(..), runExceptT) 18 | import Control.Monad.Trans.Class (lift) 19 | import Data.Either (Either(..)) 20 | import Data.Newtype (unwrap) 21 | import Data.Time.Duration (Milliseconds(..), toDuration) 22 | import Elm.Platform (Task, ProcessId) 23 | import Prelude (Unit, ($), (<$>), (<<<)) 24 | 25 | 26 | -- This is repeated here to avoid a circular dependency 27 | type Time = Number 28 | 29 | 30 | -- | > A light-weight process that runs concurrently. You can use `spawn` to 31 | -- | > get a bunch of different tasks running in different processes. The Elm runtime 32 | -- | > will interleave their progress. So if a task is taking too long, we will pause 33 | -- | > it at an `andThen` and switch over to other stuff. 34 | -- | > 35 | -- | > **Note:** We make a distinction between *concurrency* which means interleaving 36 | -- | > different sequences and *parallelism* which means running different 37 | -- | > sequences at the exact same time. For example, a 38 | -- | > [time-sharing system](https://en.wikipedia.org/wiki/Time-sharing) is definitely 39 | -- | > concurrent, but not necessarily parallel. So even though JS runs within a 40 | -- | > single OS-level thread, Elm can still run things concurrently. 41 | type Id = 42 | ProcessId 43 | 44 | 45 | -- | > Run a task in its own light-weight process. In the following example, 46 | -- | > `task1` and `task2` will be interleaved. If `task1` makes a long HTTP request 47 | -- | > or is just taking a long time, we can hop over to `task2` and do some work 48 | -- | > there. 49 | -- | > 50 | -- | > spawn task1 51 | -- | > |> Task.andThen (\_ -> spawn task2) 52 | -- | > 53 | -- | > **Note:** This creates a relatively restricted kind of `Process` because it 54 | -- | > cannot receive any messages. More flexibility for user-defined processes will 55 | -- | > come in a later release! 56 | spawn :: ∀ x y a. Task x a -> Task y Id 57 | spawn = 58 | lift <<< liftAff <<< forkAff <<< apathize <<< unwrap <<< runExceptT 59 | 60 | 61 | -- | > Block progress on the current process for a given amount of time. The 62 | -- | > JavaScript equivalent of this is [`setTimeout`][setTimeout] which lets you 63 | -- | > delay work until later. 64 | -- | > 65 | -- | > [setTimeout]: https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout 66 | sleep :: ∀ x. Time -> Task x Unit 67 | sleep time = 68 | ExceptT $ liftAff $ Right <$> delay (toDuration $ Milliseconds time) 69 | 70 | 71 | -- | > Sometimes you `spawn` a process, but later decide it would be a waste to 72 | -- | > have it keep running and doing stuff. The `kill` function will force a process 73 | -- | > to bail on whatever task it is running. So if there is an HTTP request in 74 | -- | > flight, it will also abort the request. 75 | kill :: ∀ y. Id -> Task y Unit 76 | kill = 77 | -- We have to specify an specific error ... 78 | lift <<< liftAff <<< killFiber (error "Elm.Process.kill") 79 | -------------------------------------------------------------------------------- /src/Elm/Random.js: -------------------------------------------------------------------------------- 1 | /* global exports */ 2 | "use strict"; 3 | 4 | // module Elm.Random 5 | 6 | // Elm's Random does an Elm.Basics mod, but on a value that is a Javascript 7 | // float. So, it's difficult to represent properly in Purescript ... better to 8 | // special-case it here. 9 | exports.floatMod = function floatMod (a) { 10 | return function (b) { 11 | // The following code is derived from the Elm implementation here: 12 | // 13 | // https://github.com/elm-lang/core/blob/568b384720995ce35b9561fab89f2c0b63c2c3fc/src/Native/Basics.js#L13-L23 14 | if (b === 0) 15 | { 16 | throw new Error('Cannot perform mod 0. Division by zero error.'); 17 | } 18 | var r = a % b; 19 | var m = a === 0 ? 0 : (b > 0 ? (a >= 0 ? r : r + b) : -floatMod(-a)(-b)); 20 | 21 | return m === b ? 0 : m; 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /src/Elm/Regex.js: -------------------------------------------------------------------------------- 1 | /* global exports */ 2 | "use strict"; 3 | 4 | // module Elm.Regex 5 | 6 | // Note that the code here is substantially derived from Elm's `Regex` module. Please 7 | // see the LICENSE file for the Elm license. 8 | 9 | exports._showRegex = function (r) { 10 | return "" + r; 11 | }; 12 | 13 | exports.escape = function (str) { 14 | return str.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); 15 | }; 16 | 17 | exports.regex = function (raw) { 18 | return new RegExp(raw, 'g'); 19 | }; 20 | 21 | exports.caseInsensitive = function (re) { 22 | return new RegExp(re.source, 'gi'); 23 | }; 24 | 25 | exports.contains = function (re) { 26 | return function (string) { 27 | return string.match(re) !== null; 28 | } 29 | }; 30 | 31 | exports._find = function (context) { 32 | return function (n) { 33 | return function (re) { 34 | return function (str) { 35 | var out = context.nil; 36 | var number = 0; 37 | var string = str; 38 | var lastIndex = re.lastIndex; 39 | var prevLastIndex = -1; 40 | var result; 41 | 42 | while (number++ < n && (result = re.exec(string))) { 43 | if (prevLastIndex === re.lastIndex) break; 44 | 45 | var i = result.length - 1; 46 | var subs = context.nil; 47 | 48 | while (i > 0) { 49 | var submatch = result[i]; 50 | i--; 51 | var justSubmatch = submatch === undefined 52 | ? context.nothing 53 | : context.just(submatch); 54 | 55 | subs = context.cons(justSubmatch)(subs); 56 | } 57 | 58 | out = context.cons({ 59 | match: result[0], 60 | submatches: subs, 61 | index: result.index, 62 | number: number 63 | })(out); 64 | 65 | prevLastIndex = re.lastIndex; 66 | } 67 | 68 | re.lastIndex = lastIndex; 69 | return out; 70 | } 71 | } 72 | } 73 | } 74 | 75 | exports._replace = function (context) { 76 | return function (n) { 77 | return function (re) { 78 | return function (replacer) { 79 | return function (string) { 80 | var count = 0; 81 | 82 | function jsReplacer (match) { 83 | if (count++ >= n) { 84 | return match; 85 | } 86 | 87 | var i = arguments.length - 3; 88 | var submatches = context.nil; 89 | 90 | while (i > 0) { 91 | var submatch = arguments[i]; 92 | i--; 93 | var justSubmatch = submatch === undefined 94 | ? context.nothing 95 | : context.just(submatch); 96 | 97 | submatches = context.cons(justSubmatch)(submatches); 98 | } 99 | 100 | return replacer({ 101 | match: match, 102 | submatches: submatches, 103 | index: arguments[arguments.length - 2], 104 | number: count 105 | }); 106 | } 107 | 108 | return string.replace(re, jsReplacer); 109 | } 110 | } 111 | } 112 | } 113 | }; 114 | 115 | exports._split = function (n) { 116 | return function (re) { 117 | return function (str) { 118 | if (n === 9007199254740991) { 119 | return str.split(re); 120 | } 121 | 122 | var string = str; 123 | var result; 124 | var out = []; 125 | var lastIndex = re.lastIndex; 126 | var start = lastIndex; 127 | 128 | while (n--) { 129 | if (!(result = re.exec(string))) break; 130 | out.push(string.slice(start, result.index)); 131 | start = re.lastIndex; 132 | } 133 | 134 | out.push(string.slice(start)); 135 | re.lastIndex = lastIndex; 136 | return out; 137 | } 138 | } 139 | }; 140 | -------------------------------------------------------------------------------- /src/Elm/Regex.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | > A library for working with regular expressions. It uses the same kind of 3 | -- | > regular expressions 4 | -- | > [accepted by JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions). 5 | -- | 6 | -- | Purescript has its own regular expression library in `Data.String.Regex`. 7 | -- | However, the `Elm.Regex` API is sufficiently different that it is 8 | -- | re-implemented here. 9 | 10 | -- Note that the code here is substantially derived from Elm's `Regex` module. Please 11 | -- see the LICENSE file for the Elm license. 12 | 13 | module Elm.Regex 14 | ( Regex 15 | , regex, escape, caseInsensitive 16 | , HowMany(..), Match 17 | , contains, find, replace, split 18 | ) where 19 | 20 | 21 | import Elm.Basics (Bool) 22 | import Elm.List (List(..)) 23 | import Data.List (reverse, fromFoldable) 24 | import Elm.Maybe (Maybe(..)) 25 | import Prelude (class Show, ($)) 26 | 27 | 28 | -- | > A regular expression, describing a certain set of strings. 29 | -- | 30 | -- | Note that this is (unfortunatley) not interchangeable with Purescript's `Data.String.Regex`, 31 | -- | because the Elm code requires that the `Regex` be created with the `g` flag. 32 | foreign import data Regex :: Type 33 | 34 | 35 | foreign import _showRegex :: Regex -> String 36 | 37 | instance showRegex :: Show Regex where 38 | show = _showRegex 39 | 40 | 41 | -- | > Escape strings to be regular expressions, making all special characters 42 | -- | > safe. So `regex (escape "^a+")` will match exactly `"^a+"` instead of a series 43 | -- | > of `a`’s that start at the beginning of the line. 44 | foreign import escape :: String -> String 45 | 46 | 47 | -- | > Create a Regex that matches patterns 48 | -- | > [as specified in JavaScript](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Writing_a_Regular_Expression_Pattern). 49 | -- | > 50 | -- | > Be careful to escape backslashes properly! For example, `"\w"` is escaping the 51 | -- | > letter `w` which is probably not what you want. You probably want `"\\w"` 52 | -- | > instead, which escapes the backslash. 53 | foreign import regex :: String -> Regex 54 | 55 | 56 | -- | > Make a regex case insensitive. 57 | foreign import caseInsensitive :: Regex -> Regex 58 | 59 | 60 | -- | > Check to see if a Regex is contained in a string. 61 | -- | > 62 | -- | > contains (regex "123") "12345" == true 63 | -- | > contains (regex "b+") "aabbcc" == true 64 | -- | > 65 | -- | > contains (regex "789") "12345" == false 66 | -- | > contains (regex "z+") "aabbcc" == false 67 | foreign import contains :: Regex -> String -> Bool 68 | 69 | 70 | -- | > A `Match` represents all of the details about a particular match in a string. 71 | -- | > Here are details on each field: 72 | -- | > 73 | -- | > * `match` — the full string of the match. 74 | -- | > 75 | -- | > * `submatches` — a regex might have 76 | -- | > [subpatterns, surrounded by parentheses](https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions#Using_Parenthesized_Substring_Matches). 77 | -- | > If there are N subpatterns, there will be N elements in the `submatches` list. 78 | -- | > Each submatch in this list is a `Maybe` because not all subpatterns may trigger. 79 | -- | > For example, `(regex "(a+)|(b+)")` will either match many `a`’s or 80 | -- | > many `b`’s, but never both. 81 | -- | > 82 | -- | > * `index` — the index of the match in the original string. 83 | -- | > 84 | -- | > * `number` — if you find many matches, you can think of each one 85 | -- | > as being labeled with a `number` starting at one. So the first time you 86 | -- | > find a match, that is match `number` one. Second time is match `number` two. 87 | -- | > This is useful when paired with `replace All` if replacement is dependent on how 88 | -- | > many times a pattern has appeared before. 89 | type Match = 90 | { match :: String 91 | , submatches :: List (Maybe String) 92 | , index :: Int 93 | , number :: Int 94 | } 95 | 96 | 97 | -- | > `HowMany` is used to specify how many matches you want to make. So 98 | -- | > `replace All` would replace every match, but `replace (AtMost 2)` would 99 | -- | > replace at most two matches (i.e. zero, one, two, but never three or more). 100 | data HowMany 101 | = All 102 | | AtMost Int 103 | 104 | 105 | -- Some context provided to the FFI 106 | type Context a = 107 | { cons :: a -> List a -> List a 108 | , nil :: List a 109 | , just :: a -> Maybe a 110 | , nothing :: Maybe a 111 | } 112 | 113 | context :: ∀ a. Context a 114 | context = 115 | { cons: Cons 116 | , nil: Nil 117 | , just: Just 118 | , nothing: Nothing 119 | } 120 | 121 | 122 | -- | > Find matches in a string: 123 | -- | > 124 | -- | > findTwoCommas = find (AtMost 2) (regex ",") 125 | -- | > 126 | -- | > -- map .index (findTwoCommas "a,b,c,d,e") == [1,3] 127 | -- | > -- map .index (findTwoCommas "a b c d e") == [] 128 | -- | > 129 | -- | > places = find All (regex "[oi]n a (\\w+)") "I am on a boat in a lake." 130 | -- | > 131 | -- | > -- map .match places == ["on a boat", "in a lake"] 132 | -- | > -- map .submatches places == [ [Just "boat"], [Just "lake"] ] 133 | find :: HowMany -> Regex -> String -> List Match 134 | find howMany reg string = 135 | reverse $ 136 | _find context (count howMany) reg string 137 | 138 | 139 | foreign import _find :: ∀ a. Context a -> Int -> Regex -> String -> List Match 140 | 141 | 142 | count :: HowMany -> Int 143 | count All = maxInt 144 | count (AtMost n) = n 145 | 146 | 147 | maxInt :: Int 148 | maxInt = 2147483647 149 | 150 | 151 | -- | > Replace matches. The function from `Match` to `String` lets 152 | -- | > you use the details of a specific match when making replacements. 153 | -- | > 154 | -- | > devowel = replace All (regex "[aeiou]") (\_ -> "") 155 | -- | > 156 | -- | > -- devowel "The quick brown fox" == "Th qck brwn fx" 157 | -- | > 158 | -- | > reverseWords = replace All (regex "\\w+") (\{match} -> String.reverse match) 159 | -- | > 160 | -- | > -- reverseWords "deliver mined parts" == "reviled denim strap" 161 | replace :: HowMany -> Regex -> (Match -> String) -> String -> String 162 | replace howMany = 163 | _replace context (count howMany) 164 | 165 | 166 | foreign import _replace :: ∀ a. Context a -> Int -> Regex -> (Match -> String) -> String -> String 167 | 168 | 169 | 170 | -- | > Split a string, using the regex as the separator. 171 | -- | > 172 | -- | > split (AtMost 1) (regex ",") "tom,99,90,85" == ["tom","99,90,85"] 173 | -- | > 174 | -- | > split All (regex ",") "a,b,c,d" == ["a","b","c","d"] 175 | split :: HowMany -> Regex -> String -> List String 176 | split howMany reg string = 177 | fromFoldable $ 178 | _split (count howMany) reg string 179 | 180 | 181 | foreign import _split :: Int -> Regex -> String -> Array String 182 | -------------------------------------------------------------------------------- /src/Elm/Set.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | A set of unique values. The values can be any type with an 3 | -- | `Ord` instance. 4 | -- | 5 | -- | This is implemented in terms of Purescript's `Data.Set`, so 6 | -- | you can also use functions from that module on a `Set`. 7 | 8 | module Elm.Set 9 | ( module Virtual 10 | , remove, intersect, diff 11 | , filter, partition, map 12 | , toList, fromList 13 | ) where 14 | 15 | 16 | -- For re-export 17 | 18 | import Data.Set 19 | ( Set, empty, singleton, insert 20 | , isEmpty, member, size 21 | , union 22 | ) as Virtual 23 | 24 | import Data.Foldable (foldr) as Virtual 25 | import Elm.Foldable (foldl) as Virtual 26 | 27 | 28 | -- Internal 29 | 30 | import Prelude (class Ord, (<<<)) 31 | import Data.List as List 32 | import Data.Tuple (Tuple(..)) 33 | import Data.Bifunctor (lmap, rmap) 34 | import Data.Foldable (class Foldable, foldr) 35 | import Data.Unfoldable (class Unfoldable) 36 | import Elm.Foldable (foldl) 37 | import Elm.Basics (Bool) 38 | 39 | import Data.Set 40 | ( Set, empty, insert, delete 41 | , difference, intersection 42 | , fromFoldable, toUnfoldable 43 | ) 44 | 45 | 46 | -- | Remove a value from a set. If the value is not found, no changes are made. 47 | -- | 48 | -- | Equivalent to Purescript's `delete`. 49 | remove :: ∀ a. (Ord a) => a -> Set a -> Set a 50 | remove = delete 51 | 52 | 53 | -- | Get the intersection of two sets. Keeps values that appear in both sets. 54 | -- | 55 | -- | Equivalent to Purescript's `intersection`. 56 | intersect :: ∀ a. (Ord a) => Set a -> Set a -> Set a 57 | intersect = intersection 58 | 59 | 60 | -- | Get the difference between the first set and the second. Keeps values 61 | -- | that do not appear in the second set. 62 | -- | 63 | -- | Equivalent to Purescript's `difference`. 64 | diff :: ∀ a. (Ord a) => Set a -> Set a -> Set a 65 | diff = difference 66 | 67 | 68 | -- | Map a function onto a set, creating a new set with no duplicates. 69 | map :: ∀ a b. Ord a => Ord b => (a -> b) -> Set a -> Set b 70 | map func set = 71 | foldl (\a memo -> insert (func a) memo) empty set 72 | 73 | 74 | -- | Create a new set consisting only of elements which satisfy a predicate. 75 | filter :: ∀ a. (Ord a) => (a -> Bool) -> Set a -> Set a 76 | filter func = 77 | fromList <<< List.filter func <<< toList 78 | 79 | 80 | -- | Create two new sets; the first consisting of elements which satisfy a 81 | -- | predicate, the second consisting of elements which do not. 82 | partition :: ∀ a. (Ord a) => (a -> Bool) -> Set a -> Tuple (Set a) (Set a) 83 | partition pred = 84 | foldr step (Tuple empty empty) 85 | 86 | where 87 | step x = 88 | (if pred x then lmap else rmap) (insert x) 89 | 90 | 91 | -- | Convert a set into a list, sorted from lowest to highest. 92 | -- | 93 | -- | * Uses a polymorphic container type to accommodate `List` and 94 | -- | `Array`, among others. * 95 | toList :: ∀ a f. Unfoldable f => Ord a => Set a -> f a 96 | toList = toUnfoldable 97 | 98 | 99 | -- | Convert a list into a set, removing any duplicates. 100 | -- | 101 | -- | * Uses a polymorphic container type to accommodate `List` and 102 | -- | `Array, among others. * 103 | fromList :: ∀ a f. Foldable f => Ord a => f a -> Set a 104 | fromList = fromFoldable 105 | -------------------------------------------------------------------------------- /src/Elm/String.js: -------------------------------------------------------------------------------- 1 | /* global exportss */ 2 | "use strict"; 3 | 4 | // module Elm.String 5 | 6 | exports.foldl = function (f) { 7 | return function (b) { 8 | return function (str) { 9 | var len = str.length; 10 | 11 | for (var i = 0; i < len; ++i) { 12 | b = f(str[i])(b); 13 | } 14 | 15 | return b; 16 | } 17 | } 18 | } 19 | 20 | exports.foldr = function (f) { 21 | return function (b) { 22 | return function (str) { 23 | for (var i = str.length; i--; ) { 24 | b = f(str[i])(b); 25 | } 26 | 27 | return b; 28 | } 29 | } 30 | } 31 | 32 | exports.repeat = function (n) { 33 | return function (str) { 34 | var result = ''; 35 | 36 | while (n > 0) { 37 | if (n & 1) { 38 | result += str; 39 | } 40 | 41 | n >>= 1, str += str; 42 | } 43 | 44 | return result; 45 | } 46 | } 47 | 48 | exports.slice = function (start) { 49 | return function (end) { 50 | return function (str) { 51 | return str.slice(start, end); 52 | } 53 | } 54 | } 55 | 56 | exports.right = function (n) { 57 | return function (str) { 58 | return n < 1 ? '' : str.slice(-n); 59 | } 60 | } 61 | 62 | exports.dropRight = function (n) { 63 | return function (str) { 64 | return n < 1 ? str : str.slice(0, -n); 65 | } 66 | } 67 | 68 | exports.trimLeft = function (str) { 69 | return str.replace(/^\s+/, ''); 70 | } 71 | 72 | exports.trimRight = function (str) { 73 | return str.replace(/\s+$/, ''); 74 | } 75 | 76 | exports._words = function (str) { 77 | return str.trim().split(/\s+/g); 78 | } 79 | 80 | exports._lines = function (str) { 81 | return str.split(/\r\n|\r|\n/g); 82 | } 83 | 84 | exports.any = function (pred) { 85 | return function (str) { 86 | for (var i = str.length; i--; ) { 87 | if (pred(str[i])) { 88 | return true; 89 | } 90 | } 91 | 92 | return false; 93 | } 94 | } 95 | 96 | exports.all = function (pred) { 97 | return function (str) { 98 | for (var i = str.length; i--; ) { 99 | if (!pred(str[i])) { 100 | return false; 101 | } 102 | } 103 | 104 | return true; 105 | } 106 | } 107 | 108 | exports.startsWith = function (sub) { 109 | return function (str) { 110 | return str.indexOf(sub) === 0; 111 | } 112 | } 113 | 114 | exports.endsWith = function (sub) { 115 | return function (str) { 116 | return str.length >= sub.length && 117 | str.lastIndexOf(sub) === str.length - sub.length; 118 | } 119 | } 120 | 121 | exports._indexes = function (sub) { 122 | return function (str) { 123 | var subLen = sub.length; 124 | 125 | if (subLen < 1) { 126 | return []; 127 | } 128 | 129 | var i = 0; 130 | var is = []; 131 | 132 | while ((i = str.indexOf(sub, i)) > -1) { 133 | is.push(i); 134 | i = i + subLen; 135 | } 136 | 137 | return is; 138 | } 139 | } 140 | 141 | exports._toInt = function (helper) { 142 | return function (s) { 143 | var len = s.length; 144 | if (len === 0) { 145 | return helper.err("could not convert string '" + s + "' to an Int" ); 146 | } 147 | 148 | var start = 0; 149 | if (s[0] === '-') { 150 | if (len === 1) { 151 | return helper.err("could not convert string '" + s + "' to an Int" ); 152 | } 153 | start = 1; 154 | } 155 | 156 | for (var i = start; i < len; ++i) { 157 | if (!helper.isDigit(s[i])) { 158 | return helper.err("could not convert string '" + s + "' to an Int" ); 159 | } 160 | } 161 | 162 | return helper.ok(parseInt(s, 10)); 163 | } 164 | } 165 | 166 | exports._toFloat = function (helper) { 167 | return function (s) { 168 | var len = s.length; 169 | if (len === 0) { 170 | return helper.err("could not convert string '" + s + "' to a Float" ); 171 | } 172 | 173 | var start = 0; 174 | if (s[0] === '-') { 175 | if (len === 1) { 176 | return helper.err("could not convert string '" + s + "' to a Float" ); 177 | } 178 | start = 1; 179 | } 180 | 181 | var dotCount = 0; 182 | for (var i = start; i < len; ++i) { 183 | if (helper.isDigit(s[i])) { 184 | continue; 185 | } 186 | 187 | if (s[i] === '.') { 188 | dotCount += 1; 189 | if (dotCount <= 1) { 190 | continue; 191 | } 192 | } 193 | 194 | return helper.err("could not convert string '" + s + "' to a Float" ); 195 | } 196 | 197 | return helper.ok(parseFloat(s)); 198 | } 199 | } 200 | 201 | -------------------------------------------------------------------------------- /src/Elm/Trampoline.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | A [trampoline](http://en.wikipedia.org/wiki/Tail-recursive_function#Through_trampolining) 3 | -- | makes it possible to recursively call a function without growing the stack. 4 | -- | 5 | -- | Popular JavaScript implementations do not perform any tail-call elimination, so 6 | -- | recursive functions can cause a stack overflow if they go too deep. Trampolines 7 | -- | permit unbounded recursion despite limitations in JavaScript. 8 | -- | 9 | -- | This strategy may create many intermediate closures, which is very expensive in 10 | -- | JavaScript, so use this library only when it is essential that you recurse deeply. 11 | -- | 12 | -- | Note that in Purescript, there is tail-call elimination, so you may not need this if you 13 | -- | arrange your code to use tail-calls. If you do need a trampoline module, you could 14 | -- | also consider [Control.Monad.Trampoline](https://pursuit.purescript.org/packages/purescript-free/0.9.1/docs/Control.Monad.Trampoline). 15 | -- | 16 | -- | * In Elm 0.17, this module was moved from core to its own package. * 17 | 18 | module Elm.Trampoline 19 | ( Trampoline 20 | , done, jump 21 | , evaluate 22 | ) where 23 | 24 | -- I tried implementing this in terms of Control.Monad.Trampoline, which worked ... 25 | -- the tricky bit was: 26 | -- 27 | -- jump = delay >>> join 28 | -- 29 | -- But performance was much worse (probably due to the join), so I reverted to this. 30 | 31 | import Prelude (Unit, unit) 32 | 33 | 34 | -- | A computation that has been broken up into a bunch of smaller chunks. The 35 | -- | programmer explicitly adds "pause points" so each chunk of computation can be 36 | -- | run without making the stack any deeper. 37 | data Trampoline a 38 | = Done a 39 | | Jump (Unit -> Trampoline a) 40 | 41 | 42 | -- | When you do not want a computation to go through the trampoline. 43 | done :: ∀ a. a -> Trampoline a 44 | done = Done 45 | 46 | 47 | -- | When you want a computation to be delayed so that it is handled by the 48 | -- | trampoline. 49 | jump :: ∀ a. (Unit -> Trampoline a) -> Trampoline a 50 | jump = Jump 51 | 52 | 53 | -- | Evaluate a trampolined value in constant space. 54 | evaluate :: ∀ a. Trampoline a -> a 55 | evaluate trampoline = 56 | case trampoline of 57 | Done value -> 58 | value 59 | 60 | Jump f -> 61 | evaluate (f unit) 62 | -------------------------------------------------------------------------------- /src/Elm/Transform2D.purs: -------------------------------------------------------------------------------- 1 | -- | A library for performing 2D matrix transformations. 2 | -- | It is used primarily with the `groupTransform` function from 3 | -- | `Elm.Graphics.Collage` and allows you to do things 4 | -- | like rotation, scaling, translation, shearing, and reflection. 5 | -- | 6 | -- | Note that all the matrices in this library are 3x3 matrices of homogeneous 7 | -- | coordinates, used for [affine transformations](http://en.wikipedia.org/wiki/Transformation_matrix#Affine_transformations). 8 | -- | Since the bottom row is always `0 0 1` in these matrices, it is omitted in 9 | -- | the diagrams below. 10 | -- | 11 | -- | This is implemented as a wrapper around the purescript-canvas module, and its `Transform` type. 12 | -- | 13 | -- | Note that this was removed from elm-lange/core in Elm 0.17. 14 | 15 | module Elm.Transform2D 16 | ( Transform2D 17 | , identity, matrix, multiply 18 | , rotation, translation 19 | , scale, scaleX, scaleY 20 | , toCSS 21 | ) where 22 | 23 | 24 | import Graphics.Canvas (Transform) 25 | import Data.String (joinWith) 26 | import Math (cos, sin) 27 | import Prelude ((*), (+), negate, (<), (>), (<>), (&&), show) 28 | import Elm.Basics (Float) 29 | 30 | 31 | -- | A matrix representing a 2D transformation. 32 | -- | 33 | -- | Equivalent to Purescript's `Graphics.Canvas.Transform`. 34 | type Transform2D = Transform 35 | 36 | 37 | toCSS :: Transform2D -> String 38 | toCSS t = 39 | "matrix(" <> 40 | ( joinWith ", " 41 | [ str t.m11 42 | , str t.m21 43 | , str (t.m12) 44 | , str (-t.m22) 45 | , str t.m31 46 | , str t.m32 47 | ] 48 | ) <> 49 | ")" 50 | 51 | 52 | str :: Number -> String 53 | str n = 54 | if n < 0.00001 && n > (-0.00001) 55 | then "0" 56 | else show n 57 | 58 | 59 | -- | Create an identity transform. Transforming by the identity does 60 | -- | not change anything, but it can come in handy as a default or 61 | -- | base case. 62 | -- | 63 | -- | / 1 0 0 \ 64 | -- | \ 0 1 0 / 65 | identity :: Transform2D 66 | identity = translation 0.0 0.0 67 | 68 | 69 | -- | Create a transformation matrix. This lets you create transforms 70 | -- | such as scales, shears, reflections, and translations. 71 | -- | 72 | -- | matrix a b c d x y 73 | -- | 74 | -- | / a b x \ 75 | -- | \ c d y / 76 | -- | 77 | -- | Note that `x` and `y` are the translation values. 78 | matrix :: Float -> Float -> Float -> Float -> Float -> Float -> Transform2D 79 | matrix a b c d x y = 80 | -- Basically, we translate from the order Elm expects to the labels 81 | -- that Graphics.Canvas uses. In Graphics.Canvas, the first number 82 | -- is the column, and the second number the row. 83 | { m11: a 84 | , m12: c 85 | , m21: b 86 | , m22: d 87 | , m31: x 88 | , m32: y 89 | } 90 | 91 | 92 | -- | Create a [rotation matrix](http://en.wikipedia.org/wiki/Rotation_matrix). 93 | -- | Given an angle t, it creates a counterclockwise rotation matrix: 94 | -- | 95 | -- | rotation t 96 | -- | 97 | -- | / cos t -sin t 0 \ 98 | -- | \ sin t cos t 0 / 99 | rotation :: Float -> Transform2D 100 | rotation t = 101 | matrix c (-s) s c 0.0 0.0 102 | 103 | where 104 | c = cos t 105 | s = sin t 106 | 107 | 108 | -- | Create a transformation matrix for translation. 109 | -- | 110 | -- | translation x y 111 | -- | 112 | -- | / 1 0 x \ 113 | -- | \ 0 1 y / 114 | translation :: Float -> Float -> Transform2D 115 | translation = matrix 1.0 0.0 0.0 1.0 116 | 117 | 118 | -- | Creates a transformation matrix for scaling by all directions. 119 | -- | 120 | -- | scale s 121 | -- | 122 | -- | / s 0 0 \ 123 | -- | \ 0 s 0 / 124 | scale :: Float -> Transform2D 125 | scale s = matrix s 0.0 0.0 s 0.0 0.0 126 | 127 | 128 | -- | Create a transformation for horizontal scaling. 129 | scaleX :: Float -> Transform2D 130 | scaleX x = matrix x 0.0 0.0 1.0 0.0 0.0 131 | 132 | 133 | -- | Create a transformation for vertical scaling. 134 | scaleY :: Float -> Transform2D 135 | scaleY y = matrix 1.0 0.0 0.0 y 0.0 0.0 136 | 137 | 138 | -- | Multiply two transforms together. 139 | -- | 140 | -- | multiply m n 141 | -- | 142 | -- | / ma mb mx \ / na nb nx \ 143 | -- | | mc md my | . | nc nd ny | 144 | -- | \ 0 0 1 / \ 0 0 1 / 145 | multiply :: Transform2D -> Transform2D -> Transform2D 146 | multiply a b = 147 | -- This is very translated from Elm's representation to that 148 | -- of Graphics.Canvas ... will need to test! 149 | { m11: (a.m11 * b.m11) + (a.m21 * b.m12) 150 | , m12: (a.m12 * b.m11) + (a.m22 * b.m21) 151 | , m21: (a.m11 * b.m21) + (a.m21 * b.m22) 152 | , m22: (a.m12 * b.m21) + (a.m22 * b.m22) 153 | , m31: (a.m11 * b.m31) + (a.m21 * b.m32) + a.m31 154 | , m32: (a.m12 * b.m31) + (a.m22 * b.m32) + a.m32 155 | } 156 | -------------------------------------------------------------------------------- /src/Elm/Tuple.purs: -------------------------------------------------------------------------------- 1 | 2 | -- | Some helpers for working with 2-tuples. 3 | -- | 4 | -- | **Note:** For larger chunks of data, it is best to switch to using records. So 5 | -- | instead of representing a 3D point as `(3,4,5)` and wondering why there are no 6 | -- | helper functions, represent it as `{ x = 3, y = 4, z = 5 }` and use all the 7 | -- | built-in syntax for records. 8 | -- | 9 | -- | This module was added in Elm 0.18. 10 | -- | 11 | -- | Implemented using Purescript's `Data.Tuple` 12 | 13 | module Elm.Tuple 14 | ( first, second 15 | , mapFirst, mapSecond 16 | ) where 17 | 18 | 19 | import Data.Tuple (Tuple, fst, snd) 20 | import Data.Bifunctor (lmap) 21 | import Prelude (map) 22 | 23 | 24 | -- | Extract the first value from a tuple. 25 | -- | 26 | -- | first (Tuple 3 4) == 3 27 | -- | first (Tuple "john" "doe") == "john" 28 | -- | 29 | -- | Equivalent to Purescript's `fst` 30 | first :: ∀ a1 a2. Tuple a1 a2 -> a1 31 | first = fst 32 | 33 | 34 | -- | Extract the second value from a tuple. 35 | -- | 36 | -- | second (Tuple 3 4) == 4 37 | -- | second (Tuple "john" "doe") == "doe" 38 | -- | 39 | -- | Equivalent to Purescript's `snd` 40 | second :: ∀ a1 a2. Tuple a1 a2 -> a2 41 | second = snd 42 | 43 | 44 | -- | Transform the first value in a tuple. 45 | -- | 46 | -- | import String 47 | -- | 48 | -- | mapFirst String.reverse (Tuple "stressed" 16) == (Tuple "desserts" 16) 49 | -- | mapFirst String.length (Tuple "stressed" 16) == (Tuple 8 16) 50 | -- | 51 | -- | Equivalent to Purescript's `lmap` 52 | mapFirst :: ∀ a b a2. (a -> b) -> Tuple a a2 -> Tuple b a2 53 | mapFirst = lmap 54 | 55 | 56 | -- | Transform the second value in a tuple. 57 | -- | 58 | -- | import String 59 | -- | 60 | -- | mapSecond sqrt ("stressed", 16) == ("stressed", 4) 61 | -- | mapSecond (\x -> x + 1) ("stressed", 16) == ("stressed", 17) 62 | -- | 63 | -- | Equivalent to Purescript's `map` 64 | mapSecond :: ∀ a b a1. (a -> b) -> Tuple a1 a -> Tuple a1 b 65 | mapSecond = map 66 | -------------------------------------------------------------------------------- /test/Test/Elm/Array.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Array (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (assert) 5 | 6 | import Elm.Array as Array 7 | import Elm.List as List 8 | import Data.Array as DA 9 | import Prelude (discard, class Eq, (-), (==), (*), (+), negate, const) 10 | import Data.List (List(..), fromFoldable, (..), (:)) 11 | import Data.Maybe (Maybe(..)) 12 | import Elm.Basics ((<|), identity, sqrt, (%), always) 13 | import Data.Tuple (Tuple(..)) 14 | 15 | 16 | assertEqual :: ∀ a e. (Eq a) => String -> a -> a -> Test e 17 | assertEqual name expected actual = 18 | assert name <| expected == actual 19 | 20 | 21 | mergeSplit :: ∀ a. Int -> Array.Array a -> Array.Array a 22 | mergeSplit n arr = 23 | let 24 | left = 25 | Array.slice 0 n arr 26 | 27 | right = 28 | Array.slice n (Array.length arr) arr 29 | 30 | in 31 | Array.append left right 32 | 33 | 34 | holeArray :: Array.Array Int 35 | holeArray = 36 | List.foldl mergeSplit (Array.fromList (0..100)) (0..100) 37 | 38 | 39 | mapArray :: ∀ a. Array.Array a -> Array.Array a 40 | mapArray array = 41 | Array.indexedMap (\i el -> 42 | case (Array.get i array) of 43 | Just x -> x 44 | Nothing -> el 45 | ) array 46 | 47 | 48 | tests :: ∀ e. TestSuite e 49 | tests = suite "Array" do 50 | test "Creation" do 51 | assertEqual "empty" Array.empty (Array.fromList (Nil :: List Int)) 52 | assertEqual "initialize" (Array.initialize 4 identity) (Array.fromList [0,1,2,3]) 53 | assertEqual "initialize huge" 32768 (Array.length (Array.initialize 32768 identity)) 54 | assertEqual "initialize 2" (Array.initialize 4 (\n -> n*n)) (Array.fromList [0,1,4,9]) 55 | assertEqual "initialize 3" (Array.initialize 4 (always 0)) (Array.fromList [0,0,0,0]) 56 | assertEqual "initialize Empty" (Array.initialize 0 identity) Array.empty 57 | assertEqual "initialize 4" (Array.initialize 2 (always 0)) (Array.fromList [0,0]) 58 | assertEqual "initialize negative" (Array.initialize (-1) identity) Array.empty 59 | assertEqual "repeat" (Array.repeat 5 40) (Array.fromList [40,40,40,40,40]) 60 | assertEqual "repeat 2" (Array.repeat 5 0) (Array.fromList [0,0,0,0,0]) 61 | assertEqual "repeat 3" (Array.repeat 3 "cat") (Array.fromList ["cat","cat","cat"]) 62 | assertEqual "fromList 1" (Array.fromList (Nil :: List Int)) Array.empty 63 | 64 | test "Basics" do 65 | assertEqual "length" 3 (Array.length (Array.fromList [1,2,3])) 66 | assertEqual "length - Long" 10000 (Array.length (Array.repeat 10000 0)) 67 | assertEqual "push" (Array.fromList [1,2,3]) (Array.push 3 (Array.fromList [1,2])) 68 | assertEqual "append" [42,42,81,81,81] (Array.toList (Array.append (Array.repeat 2 42) (Array.repeat 3 81))) 69 | assertEqual "appendEmpty 1" (1..33) (Array.toList (Array.append Array.empty (Array.fromList (1..33)))) 70 | assertEqual "appendEmpty 2" (1..33) (Array.toList (Array.append (Array.fromList (1..33)) Array.empty)) 71 | assertEqual "appendSmall 1" (1..33) (Array.toList (Array.append (Array.fromList (1..30)) (Array.fromList (31..33)))) 72 | assertEqual "appendSmall 2" (1..33) (Array.toList (Array.append (Array.fromList (1..3)) (Array.fromList (4..33)))) 73 | assertEqual "appendAndSlice" (0..100) (Array.toList holeArray) 74 | 75 | test "Get and Set" do 76 | assertEqual "get" (Just 2) (Array.get 1 (Array.fromList [3,2,1])) 77 | assertEqual "get 2" (Nothing :: Maybe Int) (Array.get 5 (Array.fromList [3,2,1])) 78 | assertEqual "get 3" (Nothing :: Maybe Int) (Array.get (-1) (Array.fromList [3,2,1])) 79 | assertEqual "set 1" (Array.fromList [1,7,3]) (Array.set 1 7 (Array.fromList [1,2,3])) 80 | assertEqual "set 0" (Array.fromList [7,2,3]) (Array.set 0 7 (Array.fromList [1,2,3])) 81 | assertEqual "set 2" (Array.fromList [1,2,7]) (Array.set 2 7 (Array.fromList [1,2,3])) 82 | assertEqual "set 3" (Array.fromList [1,2,3]) (Array.set 3 7 (Array.fromList [1,2,3])) 83 | assertEqual "set -1" (Array.fromList [1,2,3]) (Array.set (-1) 7 (Array.fromList [1,2,3])) 84 | 85 | test "Taking Arrays Apart" do 86 | assertEqual "toList" (fromFoldable [3,5,8]) (Array.toList (Array.fromList [3,5,8])) 87 | assertEqual "toList huge" 32768 (List.length (Array.toList (Array.initialize 32768 identity))) 88 | 89 | assertEqual "toIndexedList" (fromFoldable [Tuple 0 "cat", Tuple 1 "dog"]) (Array.toIndexedList (Array.fromList ["cat","dog"])) 90 | assertEqual "bigIndexedList" 32768 (List.length (Array.toIndexedList (Array.fromList (DA.range 0 32767)))) 91 | 92 | assertEqual "slice 1" (Array.fromList [0,1,2]) (Array.slice 0 3 (Array.fromList [0,1,2,3,4])) 93 | assertEqual "slice 2" (Array.fromList [1,2,3]) (Array.slice 1 4 (Array.fromList [0,1,2,3,4])) 94 | assertEqual "slice 3" (Array.fromList [1,2,3]) (Array.slice 1 (-1) (Array.fromList [0,1,2,3,4])) 95 | assertEqual "slice 4" (Array.fromList [2]) (Array.slice (-3) (-2) (Array.fromList [0,1,2,3,4])) 96 | assertEqual "slice 5" 63 (Array.length <| Array.slice 65 (65 + 63) <| Array.fromList (1..200)) 97 | 98 | test "Mapping and Folding" do 99 | assertEqual "map" (Array.fromList [1.0, 2.0, 3.0]) (Array.map sqrt (Array.fromList [1.0, 4.0, 9.0])) 100 | 101 | assertEqual "indexedMap 1" (Array.fromList [0,5,10]) (Array.indexedMap (*) (Array.fromList [5,5,5])) 102 | assertEqual "indexedMap 2" (0..99) (Array.toList (Array.indexedMap const (Array.repeat 100 0))) 103 | 104 | assertEqual "small indexed map" (DA.range 0 (32 - 1)) (Array.toList <| mapArray <| Array.initialize 32 identity) 105 | assertEqual "large indexed map" (DA.range 0 (32768 - 1)) (Array.toList <| mapArray <| Array.initialize 32768 identity) 106 | 107 | assertEqual "foldl 1" (fromFoldable [3,2,1]) (Array.foldl (:) Nil (Array.fromList [1,2,3])) 108 | assertEqual "foldl 2" 33 (Array.foldl (+) 0 (Array.repeat 33 1)) 109 | 110 | assertEqual "foldr 1" 15 (Array.foldr (+) 0 (Array.repeat 3 5)) 111 | assertEqual "foldr 2" (fromFoldable [1,2,3]) (Array.foldr (:) Nil (Array.fromList [1,2,3])) 112 | assertEqual "foldr 3" 53 (Array.foldr (-) 54 (Array.fromList [10,11])) 113 | 114 | assertEqual "filter" (Array.fromList [2,4,6]) (Array.filter (\x -> x % 2 == 0) (Array.fromList (1..6))) 115 | 116 | -------------------------------------------------------------------------------- /test/Test/Elm/Bitwise.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Bitwise (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (assert) 5 | 6 | import Elm.Bitwise as Bitwise 7 | import Prelude (discard, class Eq) 8 | import Elm.Basics ((<|), (==), negate) 9 | 10 | 11 | assertEqual :: ∀ a e. (Eq a) => String -> a -> a -> Test e 12 | assertEqual name expected actual = 13 | assert name <| expected == actual 14 | 15 | 16 | tests :: ∀ e. TestSuite e 17 | tests = suite "Trampoline" do 18 | test "and" do 19 | assertEqual "and with 32 bit integers" 1 (Bitwise.and 5 3) 20 | assertEqual "and with 0 as first argument" 0 (Bitwise.and 0 1450) 21 | assertEqual "and with 0 as second argument" 0 (Bitwise.and 274 0) 22 | assertEqual "and with -1 as first argument" 2671 (Bitwise.and (-1) 2671) 23 | assertEqual "and with -1 as second argument" 96 (Bitwise.and 96 (-1)) 24 | 25 | test "or" do 26 | assertEqual "or with 32 bit integers" 15 (Bitwise.or 9 14) 27 | assertEqual "or with 0 as first argument" 843 (Bitwise.or 0 843) 28 | assertEqual "or with 0 as second argument" 19 (Bitwise.or 19 0) 29 | assertEqual "or with -1 as first argument" (-1) (Bitwise.or (-1) 2360) 30 | assertEqual "or with -1 as second argument" (-1) (Bitwise.or 3 (-1)) 31 | 32 | test "xor" do 33 | assertEqual "xor with 32 bit integers" 604 (Bitwise.xor 580 24) 34 | assertEqual "xor with 0 as first argument" 56 (Bitwise.xor 0 56) 35 | assertEqual "xor with 0 as second argument" (-268) (Bitwise.xor (-268) 0) 36 | assertEqual "xor with -1 as first argument" (-25) (Bitwise.xor (-1) 24) 37 | assertEqual "xor with -1 as second argument" 25601 (Bitwise.xor (-25602) (-1)) 38 | 39 | test "complement" do 40 | assertEqual "complement a positive" (-9) (Bitwise.complement 8) 41 | assertEqual "complement a negative" 278 (Bitwise.complement (-279)) 42 | 43 | test "shiftLeft" do 44 | assertEqual "8 `shiftLeft` 1 == 16" 16 (Bitwise.shiftLeft 8 1) 45 | assertEqual "8 `shiftLeft` 2 == 32" 32 (Bitwise.shiftLeft 8 2) 46 | 47 | test "shiftLeftBy" do 48 | assertEqual "shiftLeftBy 1 8 == 16" 16 (Bitwise.shiftLeftBy 1 8) 49 | assertEqual "shiftLeftBy 2 8 == 32" 32 (Bitwise.shiftLeftBy 2 8) 50 | 51 | test "shiftRight" do 52 | assertEqual "32 `shiftRight` 1 == 16" 16 (Bitwise.shiftRight 32 1) 53 | assertEqual "32 `shiftRight` 2 == 8" 8 (Bitwise.shiftRight 32 2) 54 | assertEqual "-32 `shiftRight` 1 == -16" (-16) (Bitwise.shiftRight (-32) 1) 55 | 56 | test "shiftRightBy" do 57 | assertEqual "shiftRightBy 1 32 == 16" 16 (Bitwise.shiftRightBy 1 32) 58 | assertEqual "shiftRightBy 2 32 == 8" 8 (Bitwise.shiftRightBy 2 32) 59 | assertEqual "shiftRightBy 1 -32 == -16" (-16) (Bitwise.shiftRightBy 1 (-32)) 60 | 61 | test "shiftRightLogical" do 62 | assertEqual "32 `shiftRightLogical` 1 == 16" 16 (Bitwise.shiftRightLogical 32 1) 63 | assertEqual "32 `shiftRightLogical` 2 == 8" 8 (Bitwise.shiftRightLogical 32 2) 64 | assertEqual "-32 `shiftRightLogical` 1 == 2147483632" 2147483632 (Bitwise.shiftRightLogical (-32) 1) 65 | 66 | test "shiftRightZfBy" do 67 | assertEqual "shiftRightLogicalZfBy 1 32 == 16" 16 (Bitwise.shiftRightZfBy 1 32) 68 | assertEqual "shiftRightLogicalZfBy 2 32 == 8" 8 (Bitwise.shiftRightZfBy 2 32) 69 | assertEqual "shiftRightLogicalZfBy 1 -32 == 2147483632" 2147483632 (Bitwise.shiftRightZfBy 1 (-32)) 70 | -------------------------------------------------------------------------------- /test/Test/Elm/Char.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Char (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (assert) 5 | 6 | import Elm.Char 7 | import Prelude (discard, class Eq) 8 | import Elm.Basics ((<|), (==), (|>), (+), (-), flip) 9 | import Elm.List as List 10 | import Data.List (List, (..)) 11 | 12 | 13 | assertEqual :: ∀ a e. (Eq a) => String -> a -> a -> Test e 14 | assertEqual name expected actual = 15 | assert name <| expected == actual 16 | 17 | 18 | charRange :: Char -> Char -> List Char 19 | charRange a b = 20 | List.map fromCode ((toCode a) .. (toCode b)) 21 | 22 | 23 | lower :: List Char 24 | lower = charRange 'a' 'z' 25 | 26 | upper :: List Char 27 | upper = charRange 'A' 'Z' 28 | 29 | dec :: List Char 30 | dec = charRange '0' '9' 31 | 32 | oct :: List Char 33 | oct = List.take 8 dec 34 | 35 | hexLower :: List Char 36 | hexLower = List.take 6 lower 37 | 38 | hexUpper :: List Char 39 | hexUpper = List.take 6 upper 40 | 41 | hex :: List Char 42 | hex = List.append hexLower hexUpper |> List.append dec 43 | 44 | 45 | lowerCodes :: List Int 46 | lowerCodes = (97 .. (97 + List.length lower - 1)) 47 | 48 | upperCodes :: List Int 49 | upperCodes = (65 .. (65 + List.length upper - 1)) 50 | 51 | decCodes :: List Int 52 | decCodes = (48 .. (48 + List.length dec - 1)) 53 | 54 | 55 | oneOf :: ∀ a. (Eq a) => List a -> a -> Boolean 56 | oneOf = flip List.member 57 | 58 | 59 | tests :: ∀ e. TestSuite e 60 | tests = suite "Char" do 61 | test "toCode" do 62 | assertEqual "a-z" (lowerCodes) (List.map toCode lower) 63 | assertEqual "A-Z" (upperCodes) (List.map toCode upper) 64 | assertEqual "0-9" (decCodes) (List.map toCode dec) 65 | 66 | test "fromCode" do 67 | assertEqual "a-z" (lower) (List.map fromCode lowerCodes) 68 | assertEqual "A-Z" (upper) (List.map fromCode upperCodes) 69 | assertEqual "0-9" (dec) (List.map fromCode decCodes) 70 | 71 | test "toLocaleLower" do 72 | assertEqual "a-z" (lower) (List.map toLocaleLower lower) 73 | assertEqual "A-Z" (lower) (List.map toLocaleLower upper) 74 | assertEqual "0-9" (dec) (List.map toLocaleLower dec) 75 | 76 | test "toLocaleUpper" do 77 | assertEqual "a-z" (upper) (List.map toLocaleUpper lower) 78 | assertEqual "A-Z" (upper) (List.map toLocaleUpper upper) 79 | assertEqual "0-9" (dec) (List.map toLocaleUpper dec) 80 | 81 | test "toLower" do 82 | assertEqual "a-z" (lower) (List.map toLower lower) 83 | assertEqual "A-Z" (lower) (List.map toLower upper) 84 | assertEqual "0-9" (dec) (List.map toLower dec) 85 | 86 | test "toUpper" do 87 | assertEqual "a-z" (upper) (List.map toUpper lower) 88 | assertEqual "A-Z" (upper) (List.map toUpper upper) 89 | assertEqual "0-9" (dec) (List.map toUpper dec) 90 | 91 | test "isLower" do 92 | assertEqual "a-z" (true) (List.all isLower lower) 93 | assertEqual "A-Z" (false) (List.any isLower upper) 94 | assertEqual "0-9" (false) (List.any isLower dec) 95 | 96 | test "isUpper" do 97 | assertEqual "a-z" (false) (List.any isUpper lower) 98 | assertEqual "A-Z" (true) (List.all isUpper upper) 99 | assertEqual "0-9" (false) (List.any isUpper dec) 100 | 101 | test "isDigit" do 102 | assertEqual "a-z" (false) (List.any isDigit lower) 103 | assertEqual "A-Z" (false) (List.any isDigit upper) 104 | assertEqual "0-9" (true) (List.all isDigit dec) 105 | 106 | test "isHexDigit" do 107 | assertEqual "a-z" (List.map (oneOf hex) lower) (List.map isHexDigit lower) 108 | assertEqual "A-Z" (List.map (oneOf hex) upper) (List.map isHexDigit upper) 109 | assertEqual "0-9" (true) (List.all isHexDigit dec) 110 | 111 | test "isOctDigit" do 112 | assertEqual "a-z" (false) (List.any isOctDigit lower) 113 | assertEqual "A-Z" (false) (List.any isOctDigit upper) 114 | assertEqual "0-9" (List.map (oneOf oct) dec) (List.map isOctDigit dec) 115 | 116 | -------------------------------------------------------------------------------- /test/Test/Elm/Color.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Color (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test, success, failure) 4 | import Test.Unit.Assert (equal) 5 | 6 | import Elm.Color 7 | import Prelude (flip, discard, class Eq, class Show, show, ($), (-), (<), (<>)) 8 | import Elm.Basics (abs) 9 | 10 | 11 | infixl 9 equals as === 12 | 13 | equals :: ∀ a e. Eq a => Show a => a -> a -> Test e 14 | equals = flip equal 15 | 16 | 17 | infixl 9 close as ~== 18 | 19 | close :: ∀ e. Number -> Number -> Test e 20 | close a b = 21 | if abs (a - b) < 0.00000001 22 | then success 23 | else 24 | failure $ 25 | "Expected " <> (show b) <> ", got " <> (show a) 26 | 27 | 28 | tests :: ∀ e. TestSuite e 29 | tests = 30 | suite "Elm.Color" do 31 | test "rgb" do 32 | let 33 | value = 34 | rgb 10 20 30 35 | 36 | rgbResult = 37 | toRgb value 38 | 39 | hslResult = 40 | toHsl value 41 | 42 | rgbResult.red === 10 43 | rgbResult.green === 20 44 | rgbResult.blue === 30 45 | rgbResult.alpha ~== 1.0 46 | 47 | hslResult.hue ~== 3.66519142918 48 | hslResult.saturation ~== 0.5 49 | hslResult.lightness ~== 0.0784313725 50 | hslResult.alpha ~== 1.0 51 | 52 | test "rgba" do 53 | let 54 | value = 55 | rgba 10 20 30 0.5 56 | 57 | rgbResult = 58 | toRgb value 59 | 60 | hslResult = 61 | toHsl value 62 | 63 | rgbResult.red === 10 64 | rgbResult.blue === 30 65 | rgbResult.green === 20 66 | rgbResult.alpha ~== 0.5 67 | 68 | hslResult.hue ~== 3.66519142918 69 | hslResult.saturation ~== 0.5 70 | hslResult.lightness ~== 0.0784313725 71 | hslResult.alpha ~== 0.5 72 | 73 | test "hsl" do 74 | let 75 | value = 76 | hsl 0.8 0.6 0.4 77 | 78 | rgbResult = 79 | toRgb value 80 | 81 | hslResult = 82 | toHsl value 83 | 84 | hslResult.hue ~== 0.8 85 | hslResult.saturation ~== 0.6 86 | hslResult.lightness ~== 0.4 87 | hslResult.alpha ~== 1.0 88 | 89 | rgbResult.red === 163 90 | rgbResult.green === 134 91 | rgbResult.blue === 41 92 | rgbResult.alpha ~== 1.0 93 | 94 | test "hsla" do 95 | let 96 | value = 97 | hsla 0.8 0.6 0.4 0.5 98 | 99 | rgbResult = 100 | toRgb value 101 | 102 | hslResult = 103 | toHsl value 104 | 105 | hslResult.hue ~== 0.8 106 | hslResult.saturation ~== 0.6 107 | hslResult.lightness ~== 0.4 108 | hslResult.alpha ~== 0.5 109 | 110 | rgbResult.red === 163 111 | rgbResult.green === 134 112 | rgbResult.blue === 41 113 | rgbResult.alpha ~== 0.5 114 | 115 | test "greyscale" do 116 | greyscale 0.5 === rgb 128 128 128 117 | grayscale 0.5 === rgb 128 128 128 118 | 119 | test "complement" do 120 | complement (rgb 10 20 30) === rgb 30 20 10 121 | 122 | test "toCss" do 123 | toCss (hsl 0.8 0.6 0.4) === "hsl(45.84, 60.0%, 40.0%)" 124 | toCss (hsla 0.8 0.6 0.4 0.2) === "hsla(45.84, 60.0%, 40.0%, 0.2)" 125 | 126 | -------------------------------------------------------------------------------- /test/Test/Elm/Date.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Date (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (assert, equal) 5 | 6 | import Elm.Date 7 | import Prelude (class Eq, class Show, discard, flip, (<$>)) 8 | import Elm.Basics ((<|), (==)) 9 | import Data.Date.Component (Weekday(..)) 10 | import Data.JSDate (getTime) 11 | import Elm.Result (toMaybe, Result(..)) 12 | import Data.Maybe (isNothing) 13 | 14 | 15 | infixl 9 equals as ==> 16 | 17 | equals :: ∀ a e. Eq a => Show a => a -> a -> Test e 18 | equals = flip equal 19 | 20 | 21 | tests :: ∀ e. TestSuite e 22 | tests = suite "Date" do 23 | test "conversion" do 24 | assert "fromString good" <| (getTime <$> fromString "May 27, 2014 00:00 CDT") == Ok 1401166800000.0 25 | assert "fromString bad" <| isNothing (toMaybe (fromString "bob")) 26 | 27 | assert "fromTime" <| toTime (fromTime 1318258080000.0) == 1318258080000.0 28 | assert "toTime" <| (toTime <$> (fromString "2011-10-10T14:48:00Z")) == Ok 1318258080000.0 29 | 30 | let sample = fromString("Jun 23 1990 11:45:23") 31 | assert "year" <| (year <$> sample) == Ok 1990 32 | assert "month" <| (month <$> sample) == Ok June 33 | assert "day" <| (day <$> sample) == Ok 23 34 | (dayOfWeek <$> sample) ==> Ok Saturday 35 | (hour <$> sample) ==> Ok 11 36 | assert "minute" <| (minute <$> sample) == Ok 45 37 | assert "second" <| (second <$> sample) == Ok 23 38 | assert "millisecond" <| (millisecond <$> sample) == Ok 0 39 | -------------------------------------------------------------------------------- /test/Test/Elm/Dict.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Dict (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (assert) 5 | 6 | import Elm.Dict as Dict 7 | import Elm.Dict (Dict) 8 | import Elm.Basics (Tuple(..), (++), (<|), (|>), (==)) 9 | import Prelude (discard, class Eq, (<$>), map) 10 | import Elm.List (List(..), (:), range) 11 | import Elm.Maybe (Maybe(..)) 12 | import Data.Tuple (fst, snd) 13 | 14 | 15 | infixl 9 tuple as := 16 | 17 | tuple :: ∀ a b. a -> b -> Tuple a b 18 | tuple = Tuple 19 | 20 | 21 | assertEqual :: ∀ a e. (Eq a) => String -> a -> a -> Test e 22 | assertEqual name expected actual = 23 | assert name <| expected == actual 24 | 25 | 26 | animals :: Dict String String 27 | animals = 28 | Dict.fromList 29 | ( "Tom" := "cat" 30 | : "Jerry" := "mouse" 31 | : Nil 32 | ) 33 | 34 | animalsPlus :: Dict String String 35 | animalsPlus = 36 | Dict.fromList 37 | ( "Tom" := "Tom: cat" 38 | : "Jerry" := "Jerry: mouse" 39 | : Nil 40 | ) 41 | 42 | 43 | tests :: ∀ e. TestSuite e 44 | tests = suite "Dict" do 45 | test "build" do 46 | assertEqual "empty" (Dict.fromList (Nil :: List (Tuple String String))) (Dict.empty) 47 | assertEqual "singleton" (Dict.fromList ("k" := "v" : Nil)) (Dict.singleton "k" "v") 48 | assertEqual "insert" (Dict.fromList ("k" := "v" : Nil)) (Dict.insert "k" "v" Dict.empty) 49 | assertEqual "insert replace" (Dict.fromList ("k" := "vv" : Nil)) (Dict.insert "k" "vv" (Dict.singleton "k" "v")) 50 | assertEqual "update replace" (Dict.fromList ("k" := "vv" : Nil)) (Dict.update "k" (\v -> Just "vv") (Dict.singleton "k" "v")) 51 | assertEqual "update modify" (Dict.fromList ("k" := "vv" : Nil)) (Dict.update "k" ((<$>) ((++) "v")) (Dict.singleton "k" "v")) 52 | assertEqual "update new" (Dict.fromList ("k" := "v" : "y" := "vv" : Nil)) (Dict.update "y" (\v -> Just "vv") (Dict.singleton "k" "v")) 53 | assertEqual "update remove" Dict.empty (Dict.update "k" (\v -> Nothing) (Dict.singleton "k" "v")) 54 | assertEqual "remove" Dict.empty (Dict.remove "k" (Dict.singleton "k" "v")) 55 | assertEqual "remove not found" (Dict.singleton "k" "v") (Dict.remove "kk" (Dict.singleton "k" "v")) 56 | assertEqual "fromFoldable" (Dict.fromList ("k" := "v" : "k2" := "v2" : Nil)) (Dict.fromFoldable ["k" := "v", "k2" := "v2"]) 57 | assertEqual "toUnfoldable" (Dict.toUnfoldable animals) [Tuple "Jerry" "mouse", Tuple "Tom" "cat"] 58 | 59 | test "query" do 60 | assertEqual "member 1" true (Dict.member "Tom" animals) 61 | assertEqual "member 2" false (Dict.member "Spike" animals) 62 | assertEqual "get 1" (Just "cat") (Dict.get "Tom" animals) 63 | assertEqual "get 2" (Nothing :: Maybe String) (Dict.get "Spike" animals) 64 | assertEqual "size of empty dictionary" 0 (Dict.size Dict.empty) 65 | assertEqual "size of example dictionary" 2 (Dict.size animals) 66 | assertEqual "isEmpty true" true (Dict.isEmpty Dict.empty) 67 | assertEqual "isEmpty false" false (Dict.isEmpty animals) 68 | 69 | test "combine" do 70 | assertEqual "union" animals (Dict.union (Dict.singleton "Jerry" "mouse") (Dict.singleton "Tom" "cat")) 71 | assertEqual "union collison" (Dict.singleton "Tom" "cat") (Dict.union (Dict.singleton "Tom" "cat") (Dict.singleton "Tom" "mouse")) 72 | assertEqual "intersect" (Dict.singleton "Tom" "cat") (Dict.intersect animals (Dict.singleton "Tom" "cat")) 73 | assertEqual "diff" (Dict.singleton "Jerry" "mouse") (Dict.diff animals (Dict.singleton "Tom" "cat")) 74 | 75 | test "transform" do 76 | assertEqual "filter" (Dict.singleton "Tom" "cat") (Dict.filter (\k v -> k == "Tom") animals) 77 | 78 | let partitioned = Dict.partition (\k v -> k == "Tom") animals 79 | assertEqual "partition trues" (Dict.singleton "Tom" "cat") (fst partitioned) 80 | assertEqual "partition falses" (Dict.singleton "Jerry" "mouse") (snd partitioned) 81 | 82 | assertEqual "keys" ("Jerry" : "Tom" : Nil) (Dict.keys animals) 83 | assertEqual "values" ("mouse" : "cat" : Nil) (Dict.values animals) 84 | 85 | assertEqual "map" animalsPlus <| 86 | Dict.map (\k v -> k ++ ": " ++ v) animals 87 | 88 | assertEqual "foldl" ("Tom: cat" : "Jerry: mouse" : Nil) <| 89 | Dict.foldl (\k v b -> (k ++ ": " ++ v) : b) Nil animals 90 | 91 | assertEqual "foldr" ("Jerry: mouse" : "Tom: cat" : Nil) <| 92 | Dict.foldr (\k v b -> (k ++ ": " ++ v) : b) Nil animals 93 | 94 | test "merge" do 95 | assertEqual "merge empties" (Dict.empty) <| 96 | (Dict.merge Dict.insert insertBoth Dict.insert Dict.empty Dict.empty Dict.empty) 97 | 98 | assertEqual "merge singletons in order" [Tuple "u1" [1], Tuple "u2" [2]] <| 99 | ((Dict.merge Dict.insert insertBoth Dict.insert s1 s2 Dict.empty) |> Dict.toList) 100 | 101 | assertEqual "merge singletons out of order" [Tuple "u1" [1], Tuple "u2" [2]] <| 102 | ((Dict.merge Dict.insert insertBoth Dict.insert s2 s1 Dict.empty) |> Dict.toList) 103 | 104 | assertEqual "merge with duplicate key" [Tuple "u2" [2, 3]] <| 105 | ((Dict.merge Dict.insert insertBoth Dict.insert s2 s23 Dict.empty) |> Dict.toList) 106 | 107 | assertEqual "partially overlapping" bExpected <| 108 | ((Dict.merge Dict.insert insertBoth2 Dict.insert b1 b2 Dict.empty) |> Dict.toList) 109 | 110 | where 111 | insertBoth key leftVal rightVal dict = Dict.insert key (leftVal ++ rightVal) dict 112 | insertBoth2 key leftVal rightVal dict = Dict.insert key (leftVal ++ rightVal) dict 113 | 114 | s1 = Dict.empty |> Dict.insert "u1" [ 1 ] 115 | s2 = Dict.empty |> Dict.insert "u2" [ 2 ] 116 | s23 = Dict.empty |> Dict.insert "u2" [ 3 ] 117 | 118 | b1 = map (\i -> Tuple i [i]) (range 1 10) |> Dict.fromList 119 | b2 = map (\i -> Tuple i [i]) (range 5 15) |> Dict.fromList 120 | 121 | bExpected = [Tuple 1 [1], Tuple 2 [2], Tuple 3 [3], Tuple 4 [4], Tuple 5 [5,5], Tuple 6 [6,6], Tuple 7 [7,7], Tuple 8 [8,8], Tuple 9 [9,9], Tuple 10 [10,10], Tuple 11 [11], Tuple 12 [12], Tuple 13 [13], Tuple 14 [14], Tuple 15 [15]] 122 | -------------------------------------------------------------------------------- /test/Test/Elm/List.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.List (tests) where 2 | 3 | import Test.Unit (TestSuite, suite, test) 4 | import Test.Unit.Assert (assert) 5 | 6 | import Elm.List 7 | 8 | import Elm.Basics (sqrt, (+), compare, (<|), (==), not, (<), (&&)) 9 | import Elm.Maybe (Maybe(..)) 10 | import Data.Int (even) 11 | import Data.Int as Int 12 | import Data.Tuple (Tuple(..), fst, snd) 13 | import Data.String as String 14 | import Prelude (discard, Ordering(..)) 15 | 16 | 17 | tests :: ∀ e. TestSuite e 18 | tests = suite "List" do 19 | test "(:)" do 20 | assert "with rest" <| (1 : 2 : 3 : Nil) == (Cons 1 (Cons 2 (Cons 3 Nil))) 21 | assert "by itself" <| (1 : Nil) == (Cons 1 Nil) 22 | 23 | test "head" do 24 | assert "full" <| head (1 : 2 : 3 : Nil) == Just 1 25 | assert "empty" <| head Nil == (Nothing :: Maybe (List Int)) 26 | 27 | test "tail" do 28 | assert "full" <| tail (1 : 2 : 3 : Nil) == (Just (2 : 3 : Nil)) 29 | assert "empty" <| tail Nil == (Nothing :: Maybe (List Int)) 30 | 31 | test "isEmpty" do 32 | assert "full" <| not <| isEmpty (1 : Nil) 33 | assert "empty" <| isEmpty Nil 34 | 35 | test "member" do 36 | assert "absent" <| not <| member 9 (1 : 2 : 3 : 4 : Nil) 37 | assert "present" <| member 4 (1 : 2 : 3 : 4 : Nil) 38 | 39 | test "map" do 40 | assert "sqrt" <| map sqrt (1.0 : 4.0 : 9.0 : Nil) == (1.0 : 2.0 : 3.0 : Nil) 41 | assert "not" <| map not (true : false : true : Nil) == (false : true : false : Nil) 42 | 43 | test "foldl" do 44 | assert "foldl" <| foldl (:) Nil (1 : 2 : 3 : Nil) == (3 : 2 : 1 : Nil) 45 | assert "foldl sum" <| foldl (+) 0 (1 : 2 : 3 : Nil) == 6 46 | 47 | test "foldr" do 48 | assert "foldr" <| foldr (:) Nil (1 : 2 : 3 : Nil) == (1 : 2 : 3 : Nil) 49 | assert "foldr sum" <| foldl (+) 0 (1 : 2 : 3 : Nil) == 6 50 | 51 | test "filter" do 52 | assert "filter" <| filter even (1 : 2 : 3 : 4 : 5 : 6: Nil) == (2 : 4 : 6 : Nil) 53 | 54 | test "length" do 55 | assert "length" <| length (1 : 2 : 3 : Nil) == 3 56 | 57 | test "reverse" do 58 | assert "reverse" <| reverse (1 : 2 : 3 : 4 : Nil) == (4 : 3 : 2 : 1 : Nil) 59 | 60 | test "append" do 61 | assert "append" <| append (1 : 1 : 2 : Nil) (3 : 5 : 8 : Nil) == (1 : 1 : 2 : 3 : 5 : 8 : Nil) 62 | assert "append char" <| append ("a" : "b" : Nil) ("c" : Nil) == ("a" : "b" : "c" : Nil) 63 | 64 | test "concat" do 65 | assert "concat" <| concat ((1 : 2 : Nil) : (3 : Nil) : (4 : 5 : Nil) : Nil) == (1 : 2 : 3 : 4 : 5 : Nil) 66 | 67 | test "concatMap" do 68 | assert "concat" <| concatMap (\x -> (x : Nil)) (1 : 2 : Nil) == (1 : 2 : Nil) 69 | 70 | test "sum" do 71 | assert "sum" <| sum (1 : 2 : 3 : 4 : Nil) == 10 72 | 73 | test "all" do 74 | assert "allTrue" <| all even (2 : 4 : Nil) 75 | assert "allFalse" <| not <| all even (2 : 3 : Nil) 76 | assert "allEmpty" <| all even Nil 77 | 78 | test "any" do 79 | assert "anyTrue" <| any even (2 : 3 : Nil) 80 | assert "anyFalse" <| not <| any even (1 : 3 : Nil) 81 | assert "anyEmpty" <| not <| any even Nil 82 | 83 | test "maximum" do 84 | assert "something" <| maximum (1 : 4 : 2 : Nil) == Just 4 85 | assert "nothing" <| maximum (Nil :: List Int) == (Nothing :: Maybe Int) 86 | 87 | test "minimum" do 88 | assert "something" <| minimum (3 : 2 : 1 : Nil) == Just 1 89 | assert "nothing" <| minimum (Nil :: List Int) == (Nothing :: Maybe Int) 90 | 91 | test "product" do 92 | assert "product" <| product (1 : 2 : 3 : 4 : Nil) == 24 93 | 94 | test "scanl" do 95 | assert "scanl" <| scanl (+) 0 (1 : 2 : 3 : 4 : Nil) == (0 : 1 : 3 : 6 : 10 : Nil) 96 | 97 | test "indexedMap" do 98 | assert "indexedMap" <| indexedMap Tuple ("Tom" : "Sue" : "Bob" : Nil) == (Tuple 0 "Tom" : Tuple 1 "Sue" : Tuple 2 "Bob" : Nil) 99 | 100 | test "filterMap" do 101 | assert "filterMap" <| filterMap Int.fromString ("3" : "4.1" : "5" : "hats" : Nil) == (3 : 5 : Nil) 102 | 103 | test "map2" do 104 | assert "2nd longer" <| map2 (+) (1 .. 3) (1 .. 4) == (2 : 4 : 6 : Nil) 105 | assert "1st longer" <| map2 Tuple (1 .. 3) ('a' : 'b' : Nil) == (Tuple 1 'a' : Tuple 2 'b' : Nil) 106 | 107 | test "map3" do 108 | assert "map3" <| map3 func3 (1 .. 3) (1 .. 4) (1 .. 4) == (3 : 6 : 9 : Nil) 109 | 110 | test "map4" do 111 | assert "map4" <| map4 func4 (1 .. 3) (1 .. 4) (1 .. 4) (1 .. 4) == (4 : 8 : 12 : Nil) 112 | 113 | test "map5" do 114 | assert "map5" <| map5 func5 (1 .. 3) (1 .. 4) (1 .. 4) (1 .. 4) (1 .. 4) == (5 : 10 : 15 : Nil) 115 | 116 | test "partition" do 117 | let result = partition (\x -> x < 3) (0 .. 5) 118 | assert "partition" <| (fst result) == (0 : 1 : 2 : Nil) && (snd result) == (3 : 4 : 5 : Nil) 119 | 120 | test "unzip" do 121 | assert "unzip" <| unzip (Tuple 0 true : Tuple 17 false : Tuple 1337 true : Nil ) == Tuple (0 : 17 : 1337 : Nil) (true : false : true : Nil) 122 | 123 | test "intersperse" do 124 | assert "intersperse" <| intersperse "on" ("turtles1" : "turtles2" : "turtles3" : Nil) == ("turtles1" : "on" : "turtles2" : "on" : "turtles3" : Nil) 125 | 126 | test "take" do 127 | assert "take" <| take 2 (1 .. 4) == (1 .. 2) 128 | 129 | test "drop" do 130 | assert "drop" <| drop 2 (1 .. 4) == (3 .. 4) 131 | 132 | test "repeat" do 133 | assert "repeat" <| repeat 3 "repeat" == ("repeat" : "repeat" : "repeat" : Nil) 134 | 135 | test "sort" do 136 | assert "sort" <| sort (3 : 1 : 5 : Nil) == (1 : 3 : 5 : Nil) 137 | 138 | test "sortBy" do 139 | let 140 | alice = { name: "Alice", height: 1.62 } 141 | bob = { name: "Bob" , height: 1.85 } 142 | chuck = { name: "Chuck", height: 1.76 } 143 | 144 | assert "sortByName" <| map _.name (sortBy _.name (chuck : alice : bob : Nil)) == (alice.name : bob.name : chuck.name : Nil) 145 | assert "sortByHeight" <| map _.height (sortBy _.height (chuck : alice : bob : Nil)) == (alice.height : chuck.height : bob.height : Nil) 146 | assert "sortByLength" <| sortBy String.length ("mouse" : "cat" : Nil) == ("cat" : "mouse" : Nil) 147 | 148 | test "sortWith" do 149 | assert "sortWith" <| sortWith flippedComparison (1 .. 5) == (5 : 4 : 3 : 2 : 1 : Nil) 150 | 151 | test "(..)" do 152 | assert "ascending" <| (1 .. 5) == (1 : 2 : 3 : 4 : 5 : Nil) 153 | assert "descending" <| (5 .. 1) == (Nil :: List Int) 154 | 155 | where 156 | func3 a b c = 157 | a + b + c 158 | 159 | func4 a b c d = 160 | a + b + c + d 161 | 162 | func5 a b c d e = 163 | a + b + c + d + e 164 | 165 | flippedComparison a b = 166 | case compare a b of 167 | LT -> GT 168 | EQ -> EQ 169 | GT -> LT 170 | -------------------------------------------------------------------------------- /test/Test/Elm/ListElm.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.ListElm (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (assert) 5 | 6 | import Elm.List 7 | 8 | import Elm.Basics ((+), compare, (<|), (|>), (==), (%), (<), (>), (<=), (>=), toString, min, identity) 9 | import Elm.Maybe (Maybe(..)) 10 | import Data.Tuple (Tuple(..), fst, snd) 11 | import Prelude (discard, class Eq, negate, (*), (/), (<>), (-), flip, (&&)) 12 | 13 | 14 | assertEqual :: ∀ a e. (Eq a) => String -> a -> a -> Test e 15 | assertEqual name expected actual = 16 | assert name <| expected == actual 17 | 18 | 19 | tests :: ∀ e. TestSuite e 20 | tests = suite "ListElm" do 21 | testListOfN 0 22 | testListOfN 1 23 | testListOfN 2 24 | testListOfN 5000 25 | 26 | 27 | testListOfN :: ∀ e. Int -> TestSuite e 28 | testListOfN n = 29 | let 30 | xs = 31 | (1..n) 32 | 33 | xsOpp = 34 | ((-n)..(-1)) 35 | 36 | xsNeg = 37 | foldl (:) Nil xsOpp -- assume foldl and (::) work 38 | 39 | zs = 40 | (0..n) 41 | 42 | sumSeq k = 43 | k * (k + 1) / 2 44 | 45 | xsSum = 46 | sumSeq n 47 | 48 | mid = 49 | n / 2 50 | 51 | halve :: Int -> Maybe Int 52 | halve x = 53 | if x % 2 == 0 54 | then Just (x / 2) 55 | else Nothing 56 | 57 | in 58 | test (toString n <> " elements") do 59 | assertEqual "foldl order" (n) (foldl (\x acc -> x) 0 xs) 60 | assertEqual "foldl total" (xsSum) (foldl (+) 0 xs) 61 | 62 | assertEqual "foldlr order" (min 1 n) (foldr (\x acc -> x) 0 xs) 63 | assertEqual "foldlr total" (xsSum) (foldl (+) 0 xs) 64 | 65 | assertEqual "map identity" (xs) (map identity xs) 66 | assertEqual "map linear" (2..(n + 1)) (map ((+) 1) xs) 67 | 68 | assertEqual "isEmpty" (n == 0) (isEmpty xs) 69 | 70 | assertEqual "length" (n) (length xs) 71 | 72 | assertEqual "reverse" (xsOpp) (reverse xsNeg) 73 | 74 | assertEqual "member positive" (true) (member n zs) 75 | assertEqual "member negative" (false) (member (n + 1) xs) 76 | 77 | if n == 0 78 | then assertEqual "head Nothing" (Nothing :: Maybe Int) (head xs) 79 | else assertEqual "head Something" (Just 1) (head xs) 80 | 81 | assertEqual "filter none" (Nil :: List Int) (filter (\x -> x > n) xs) 82 | assertEqual "filter one" (n : Nil) (filter (\z -> z == n) zs) 83 | assertEqual "filter all" (xs) (filter (\x -> x <= n) xs) 84 | 85 | assertEqual "take none" (Nil :: List Int) (take 0 xs) 86 | assertEqual "take some" (0..(n - 1)) (take n zs) 87 | assertEqual "take all" (xs) (take n xs) 88 | assertEqual "take all+" (xs) (take (n + 1) xs) 89 | 90 | assertEqual "drop none" (xs) (drop 0 xs) 91 | assertEqual "drop some" (n : Nil) (drop n zs) 92 | assertEqual "drop all" (Nil :: List Int) (drop n xs) 93 | assertEqual "drop all+" (Nil :: List Int) (drop (n + 1) xs) 94 | 95 | assertEqual "repeat" (map (\x -> (-1)) xs) (repeat n (-1)) 96 | 97 | assertEqual "append" (xsSum * 2) (append xs xs |> foldl (+) 0) 98 | 99 | assertEqual "(::)" (append ((-1) : Nil) xs) ((-1) : xs) 100 | 101 | assertEqual "concat" (append xs (append zs xs)) (concat (xs : zs : xs : Nil)) 102 | 103 | assertEqual "intersperse" 104 | (Tuple (min (-(n - 1)) 0) xsSum) 105 | (intersperse (-1) xs |> foldl (\x (Tuple c1 c2) -> (Tuple c2 (c1 + x))) (Tuple 0 0)) 106 | 107 | let left = partition (\x -> x > 0) xs 108 | assert "partition left" <| (fst left) == xs && (snd left) == (Nil :: List Int) 109 | 110 | let right = partition (\x -> x < 0) xs 111 | assert "patition right" <| (fst right) == (Nil :: List Int) && (snd right) == xs 112 | 113 | let split = partition (\x -> x > mid) xs 114 | assert "partition split" <| (fst split) == ((mid + 1)..n) && (snd split) == (1..mid) 115 | 116 | assertEqual "map2 same length" (map ((*) 2) xs) (map2 (+) xs xs) 117 | assertEqual "map2 long first" (map (\x -> x * 2 - 1) xs) (map2 (+) zs xs) 118 | assertEqual "map2 short first" (map (\x -> x * 2 - 1) xs) (map2 (+) xs zs) 119 | 120 | assertEqual "unzip" (Tuple xsNeg xs) (map (\x -> Tuple (-x) x) xs |> unzip) 121 | 122 | assertEqual "filterMap none" (Nil :: List Int) (filterMap (\x -> Nothing :: Maybe Int) xs) 123 | assertEqual "filterMap all" (xsNeg) (filterMap (\x -> Just (-x)) xs) 124 | 125 | assertEqual "some" (1..mid) (filterMap halve xs) 126 | 127 | assertEqual "concatMap none" (Nil :: List Int) (concatMap (\x -> (Nil :: List Int)) xs) 128 | assertEqual "concatMap all" (xsNeg) (concatMap (\x -> ((-x) : Nil)) xs) 129 | 130 | assertEqual "indexedMap" (map2 Tuple zs xsNeg) (indexedMap (\i x -> (Tuple i (-x))) xs) 131 | 132 | assertEqual "sum" (xsSum) (sum xs) 133 | 134 | assertEqual "product" (0) (product zs) 135 | 136 | if n == 0 137 | then assertEqual "maximum nothing" (Nothing :: Maybe Int) (maximum xs) 138 | else assertEqual "maximum something" (Just n) (maximum xs) 139 | 140 | if n == 0 141 | then assertEqual "minimum something" (Nothing :: Maybe Int) (minimum xs) 142 | else assertEqual "minimum nothing" (Just 1) (minimum xs) 143 | 144 | assertEqual "all false" (false) (all (\z -> z < n) zs) 145 | assertEqual "all true" (true) (all (\x -> x <= n) xs) 146 | 147 | assertEqual "any false" (false) (any (\x -> x > n) xs) 148 | assertEqual "any true" (true) (any (\z -> z >= n) zs) 149 | 150 | assertEqual "sort sorted" (xs) (sort xs) 151 | assertEqual "sort unsorted" (xsOpp) (sort xsNeg) 152 | 153 | assertEqual "sortBy sorted" (xsNeg) (sortBy negate xsNeg) 154 | assertEqual "sortBy unsorted" (xsNeg) (sortBy negate xsOpp) 155 | 156 | assertEqual "sortWith sorted" (xsNeg) (sortWith (flip compare) xsNeg) 157 | assertEqual "sortWith unsorted" (xsNeg) (sortWith (flip compare) xsOpp) 158 | 159 | assertEqual "scanl" (0 : map sumSeq xs) (scanl (+) 0 xs) 160 | 161 | -------------------------------------------------------------------------------- /test/Test/Elm/Maybe.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Maybe (tests) where 2 | 3 | import Test.Unit (TestSuite, suite, test) 4 | import Test.Unit.Assert (assert) 5 | 6 | import Elm.Maybe 7 | import Elm.Basics ((+), (<|), (==), sqrt) 8 | import Elm.List (List(..), (:)) 9 | import Prelude (discard) 10 | 11 | 12 | tests :: ∀ e. TestSuite e 13 | tests = suite "Maybe" do 14 | test "withDefault" do 15 | assert "with Just" <| withDefault 100 (Just 42) == 42 16 | assert "with Nothing" <| withDefault 100 Nothing == 100 17 | 18 | test "map" do 19 | assert "with Just" <| map sqrt (Just 9.0) == Just 3.0 20 | assert "with Nothing" <| map sqrt Nothing == Nothing 21 | 22 | test "map2" do 23 | assert "both Just" <| map2 (+) (Just 3) (Just 4) == Just 7 24 | assert "second Nothing" <| map2 (+) (Just 3) Nothing == Nothing 25 | assert "first Nothing" <| map2 (+) Nothing (Just 4) == Nothing 26 | 27 | test "map3" do 28 | assert "all Just" <| map3 func3 (Just 3) (Just 4) (Just 5) == Just 12 29 | assert "first Nothing" <| map3 func3 Nothing (Just 4) (Just 5) == Nothing 30 | assert "second Nothing" <| map3 func3 (Just 3) Nothing (Just 5) == Nothing 31 | assert "third Nothing" <| map3 func3 (Just 3) (Just 4) Nothing == Nothing 32 | 33 | test "map4" do 34 | assert "all Just" <| map4 func4 (Just 3) (Just 4) (Just 5) (Just 6) == Just 18 35 | assert "first Nothing" <| map4 func4 Nothing (Just 4) (Just 5) (Just 6) == Nothing 36 | assert "second Nothing" <| map4 func4 (Just 3) Nothing (Just 5) (Just 6) == Nothing 37 | assert "third Nothing" <| map4 func4 (Just 3) (Just 4) Nothing (Just 6) == Nothing 38 | assert "fourth Nothing" <| map4 func4 (Just 3) (Just 4) (Just 5) Nothing == Nothing 39 | 40 | test "map5" do 41 | assert "all Just" <| map5 func5 (Just 3) (Just 4) (Just 5) (Just 6) (Just 7) == Just 25 42 | assert "first Nothing" <| map5 func5 Nothing (Just 4) (Just 5) (Just 6) (Just 7) == Nothing 43 | assert "second Nothing" <| map5 func5 (Just 3) Nothing (Just 5) (Just 6) (Just 7) == Nothing 44 | assert "third Nothing" <| map5 func5 (Just 3) (Just 4) Nothing (Just 6) (Just 7) == Nothing 45 | assert "fourth Nothing" <| map5 func5 (Just 3) (Just 4) (Just 5) Nothing (Just 7) == Nothing 46 | assert "fifth Nothing" <| map5 func5 (Just 3) (Just 4) (Just 5) (Just 7)Nothing == Nothing 47 | 48 | test "oneOf" do 49 | assert "first" <| oneOf ( Just 42 : Just 71 : Nothing : Nil ) == Just 42 50 | assert "second" <| oneOf ( Nothing : Just 42 : Just 71 : Nil ) == Just 42 51 | assert "third" <| oneOf ( Nothing : Nothing : Just 71 : Nil ) == Just 71 52 | assert "none" <| oneOf ( (Nothing :: Maybe Int) : Nothing : Nothing : Nil ) == (Nothing :: Maybe Int) 53 | assert "nil" <| oneOf (Nil :: List (Maybe Int)) == (Nothing :: Maybe Int) 54 | 55 | test "oneOf with array" do 56 | assert "first" <| oneOf [Just 42, Just 71, Nothing] == Just 42 57 | assert "second" <| oneOf [Nothing, Just 42, Just 71] == Just 42 58 | assert "third" <| oneOf [Nothing, Nothing, Just 71] == Just 71 59 | assert "none" <| oneOf [Nothing :: Maybe Int, Nothing, Nothing] == (Nothing :: Maybe Int) 60 | assert "nil" <| oneOf ([] :: Array (Maybe Int)) == (Nothing :: Maybe Int) 61 | 62 | test "andThen" do 63 | assert "just just" <| andThen (\x -> Just <| x + 1) (Just 42) == Just 43 64 | assert "nothing just" <| andThen (\x -> Just <| x + 1) Nothing == Nothing :: Maybe Int 65 | assert "just nothing" <| andThen (\x -> Nothing) (Just 42) == Nothing :: Maybe Int 66 | assert "nothing nothing" <| andThen (\x -> Nothing) Nothing == Nothing :: Maybe Int 67 | 68 | where 69 | func3 a b c = 70 | a + b + c 71 | 72 | func4 a b c d = 73 | a + b + c + d 74 | 75 | func5 a b c d e = 76 | a + b + c + d + e 77 | -------------------------------------------------------------------------------- /test/Test/Elm/Random.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Random (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test, success, failure) 4 | import Test.Unit.Assert (assert, equal) 5 | 6 | import Elm.Random 7 | import Prelude (bind, discard, (<), (-), (+), ($), (<>), show, negate, map) 8 | import Elm.Basics ((<|), (|>), (==), abs) 9 | import Data.Int53 (Int53, fromInt) 10 | import Data.List (fromFoldable) 11 | import Data.Tuple (Tuple(..)) 12 | 13 | 14 | close :: ∀ e. Number -> Number -> Test e 15 | close expected actual = 16 | if abs (expected - actual) < 0.00000001 17 | then success 18 | else failure $ "expected " <> show expected <> ", got " <> show actual 19 | 20 | 21 | infixl 9 close as ~= 22 | 23 | 24 | seed1 :: Seed 25 | seed1 = initialSeed 1283428 26 | 27 | 28 | seed2 :: Seed 29 | seed2 = initialSeed 8224729 30 | 31 | 32 | seed3 :: Seed 33 | seed3 = initialSeed 547283 34 | 35 | 36 | genInt53 :: Generator Int53 37 | genInt53 = int (fromInt 0) (fromInt 100) 38 | 39 | 40 | genInt :: Generator Int 41 | genInt = int 0 100 42 | 43 | 44 | genFloat :: Generator Number 45 | genFloat = float 0.0 100.0 46 | 47 | 48 | doer :: Generator Int 49 | doer = do 50 | y <- int 0 100 51 | int 0 y 52 | 53 | 54 | tests :: ∀ e. TestSuite e 55 | tests = suite "Random" do 56 | test "bool" do 57 | assert "seed1" <| false == (step bool seed1).value 58 | assert "seed2" <| false == (step bool seed2).value 59 | assert "seed3" <| true == (step bool seed3).value 60 | 61 | test "int53" do 62 | assert "seed1" <| fromInt 12 == (step genInt53 seed1).value 63 | assert "seed2" <| fromInt 31 == (step genInt53 seed2).value 64 | assert "seed3" <| fromInt 40 == (step genInt53 seed3).value 65 | 66 | test "int" do 67 | assert "seed1" <| 12 == (step genInt seed1).value 68 | assert "seed2" <| 31 == (step genInt seed2).value 69 | assert "seed3" <| 40 == (step genInt seed3).value 70 | 71 | suite "float" do 72 | test "seed1" <| 17.00685023 ~= (step genFloat seed1).value 73 | test "seed2" <| 63.96765709 ~= (step genFloat seed2).value 74 | test "seed3" <| 44.89097595 ~= (step genFloat seed3).value 75 | 76 | test "pair" do 77 | assert "seed1" <| Tuple false true == (step (pair bool bool) seed1).value 78 | assert "seed2" <| Tuple false false == (step (pair bool bool) seed2).value 79 | assert "seed3" <| Tuple true false == (step (pair bool bool) seed3).value 80 | 81 | test "list" do 82 | assert "seed1" <| (fromFoldable [12,46,21,81,68,39,0,78,73,69]) == (step (list 10 genInt) seed1).value 83 | assert "seed2" <| (fromFoldable [31,54,62,45,91,27,15,38,83,3]) == (step (list 10 genInt) seed2).value 84 | assert "seed3" <| (fromFoldable [40,52,34,44,69,14,2,28,48,29]) == (step (list 10 genInt) seed3).value 85 | 86 | test "array" do 87 | assert "seed1" <| [12,46,21,81,68,39,0,78,73,69] == (step (list 10 genInt) seed1).value 88 | assert "seed2" <| [31,54,62,45,91,27,15,38,83,3] == (step (list 10 genInt) seed2).value 89 | assert "seed3" <| [40,52,34,44,69,14,2,28,48,29] == (step (list 10 genInt) seed3).value 90 | 91 | test "Ramdom.map" do 92 | assert "map" <| 13 == (step (map ((+) 1) genInt) seed1).value 93 | assert "map2" <| (-34) == (step (map2 (-) genInt genInt) seed1).value 94 | assert "map3" <| 37 == (step (map3 (\a b c -> a + b - c ) genInt genInt genInt) seed1).value 95 | assert "map4" <| 68 == (step (map4 (\a b c d -> a - b + c + d) genInt genInt genInt genInt) seed1).value 96 | assert "map5" <| 186 == (step (map5 (\a b c d e -> a + b - c + d + e) genInt genInt genInt genInt genInt) seed1).value 97 | 98 | test "andThen" do 99 | let genAndThen = genInt |> andThen (int 0) 100 | assert "seed1" <| 12 == (step genAndThen seed1).value 101 | assert "seed2" <| 12 == (step genAndThen seed2).value 102 | assert "seed3" <| 40 == (step genAndThen seed3).value 103 | 104 | test "do notation" do 105 | assert "seed1" <| 12 == (step doer seed1).value 106 | assert "seed2" <| 12 == (step doer seed2).value 107 | assert "seed3" <| 40 == (step doer seed3).value 108 | 109 | test "minInt" $ 110 | equal "(Int53 -2147483648.0)" (show minInt) 111 | 112 | test "maxInt" $ 113 | equal "(Int53 2147483647.0)" (show maxInt) 114 | -------------------------------------------------------------------------------- /test/Test/Elm/Regex.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Regex (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (assert) 5 | 6 | import Elm.Regex 7 | import Prelude (discard, class Eq, (&&), not, show, map, (<>)) 8 | import Elm.Basics ((<|), (==)) 9 | import Data.List (List(..), (:), zipWith) 10 | import Data.Foldable (and) 11 | import Elm.String (join) 12 | import Data.Maybe (Maybe(..)) 13 | import Elm.Maybe (withDefault) 14 | 15 | 16 | assertEqual :: ∀ a e. (Eq a) => String -> a -> a -> Test e 17 | assertEqual name expected actual = 18 | assert name <| expected == actual 19 | 20 | 21 | matchEqual :: Match -> Match -> Boolean 22 | matchEqual m1 m2 = 23 | m1.match == m2.match && 24 | m1.submatches == m2.submatches && 25 | m1.index == m2.index && 26 | m1.number == m2.number 27 | 28 | 29 | match :: String -> List (Maybe String) -> Int -> Int -> Match 30 | match = 31 | { match: _ 32 | , submatches: _ 33 | , index: _ 34 | , number: _ 35 | } 36 | 37 | 38 | tests :: ∀ e. TestSuite e 39 | tests = suite "Regex" do 40 | test "contains" do 41 | let containsExp = regex("a") 42 | let containsTarget = "abcd" 43 | 44 | assert "contains twice" <| 45 | contains containsExp containsTarget 46 | && 47 | contains containsExp containsTarget 48 | 49 | test "split" do 50 | let findComma = regex "," 51 | 52 | assertEqual "split All" 53 | ("a" : "b" : Nil) 54 | (split All findComma "a,b") 55 | 56 | assertEqual "split AtMost 1" 57 | ("a" : "b,c" : Nil) 58 | (split (AtMost 1) findComma "a,b,c") 59 | 60 | assertEqual "split All twice" 61 | ("a" : "b" : Nil) 62 | (split All findComma "a,b") 63 | 64 | assertEqual "split AtMost 1 twice" 65 | ("a" : "b,c" : Nil) 66 | (split (AtMost 1) findComma "a,b,c") 67 | 68 | test "find" do 69 | let findAny = regex "." 70 | let ab = "ab" 71 | 72 | assert "find All" <| 73 | and <| 74 | zipWith matchEqual 75 | (match "a" Nil 0 1 : match "b" Nil 1 2 : Nil) 76 | (find All findAny ab) 77 | 78 | 79 | assert "find All twice" <| 80 | ( and <| 81 | zipWith matchEqual 82 | (match "a" Nil 0 1 : match "b" Nil 1 2 : Nil) 83 | (find All findAny ab) 84 | ) && 85 | ( and <| 86 | zipWith matchEqual 87 | (match "a" Nil 0 1 : match "b" Nil 1 2 : Nil) 88 | (find All findAny ab) 89 | ) 90 | 91 | assert "find AtMost 1" <| 92 | and <| 93 | zipWith matchEqual 94 | (match "a" Nil 0 1 : Nil) 95 | (find (AtMost 1) findAny ab) 96 | 97 | assert "find All empty" <| 98 | and <| 99 | zipWith matchEqual 100 | (match "" Nil 0 1 : Nil) 101 | (find All (regex ".*") "") 102 | 103 | 104 | let findTwoCommas = find (AtMost 2) (regex ",") 105 | assert "findTwoCommas true" <| map _.index (findTwoCommas "a,b,c,d,e") == (1 : 3 : Nil) 106 | assert "findTwoCommas false" <| map _.index (findTwoCommas "a b c d e") == (Nil :: List Int) 107 | assert "findTwoCommas twice true" <| map _.index (findTwoCommas "a,b,c,d,e") == (1 : 3 : Nil) 108 | assert "findTwoCommas twice false" <| map _.index (findTwoCommas "a b c d e") == (Nil :: List Int) 109 | 110 | 111 | let places = find All (regex "([oi]n) a (big )?(\\w+)") "I am on a boat in a lake." 112 | 113 | assertEqual "find.match" 114 | (map _.match places) 115 | ("on a boat" : "in a lake" : Nil) 116 | 117 | assertEqual "find.submatches" 118 | (map _.submatches places) 119 | ( (Just "on" : Nothing : Just "boat" : Nil) 120 | : (Just "in" : Nothing : Just "lake" : Nil) 121 | : Nil 122 | ) 123 | 124 | let bigPlaces = find All (regex "([oi]n) a (big )?(\\w+)") "I am on a big boat in a big lake." 125 | assertEqual "find.submatches with optionals" 126 | (map _.submatches bigPlaces) 127 | ( (Just "on" : Just "big " : Just "boat" : Nil) 128 | : (Just "in" : Just "big " : Just "lake" : Nil) 129 | : Nil 130 | ) 131 | 132 | test "replace" do 133 | let vowels = regex "[aeiou]" 134 | let submatcher = regex "(large )?(br[^ ]*)" 135 | let phrase = "The quick brown fox" 136 | 137 | assertEqual "replace AtMost 0" 138 | "The quick brown fox" 139 | (replace (AtMost 0) vowels (\_ -> "") phrase) 140 | 141 | assertEqual "replace AtMost 1" 142 | "Th quick brown fox" 143 | (replace (AtMost 1) vowels (\_ -> "") phrase) 144 | 145 | assertEqual "replace AtMost 2" 146 | "Th qick brown fox" 147 | (replace (AtMost 2) vowels (\_ -> "") phrase) 148 | 149 | assertEqual "replace All" 150 | "Th qck brwn fx" 151 | (replace All vowels (\_ -> "") phrase) 152 | 153 | assertEqual "replace match" 154 | "Thee quuiick broown foox" 155 | (replace All vowels (\m -> m.match <> m.match) phrase) 156 | 157 | assertEqual "replace submatches" 158 | "The quick missing brown fox" 159 | (replace All submatcher (\m -> join "" (map (withDefault "missing ") m.submatches)) phrase) 160 | 161 | assertEqual "replace index" 162 | "Th2 q56ck br12wn f17x" 163 | (replace All vowels (\m -> show m.index) phrase) 164 | 165 | assertEqual "replace index" 166 | "Th1 q23ck br4wn f5x" 167 | (replace All vowels (\m -> show m.number) phrase) 168 | 169 | 170 | test "escape" do 171 | let unescaped = regex ("^a+") 172 | let escaped = regex (escape ("^a+")) 173 | 174 | assert "escaped true" <| contains escaped "^a+" 175 | assert "unescaped false" <| not <| contains unescaped "^a+" 176 | assert "escaped false" <| not <| contains escaped "aaabbb" 177 | assert "unescaped true" <| contains unescaped "aaabbb" 178 | 179 | assertEqual "show" "/match/g" (show <| regex "match") 180 | assertEqual "show insensitive" "/match/gi" (show <| caseInsensitive <| regex "match") 181 | 182 | 183 | test "cast insensitive" do 184 | let sensitive = regex "a" 185 | let insensitive = caseInsensitive sensitive 186 | 187 | assert "caseInsensitve different case" <| contains insensitive "AAA" 188 | assert "sensitve different case" <| not <| contains sensitive "AAA" 189 | assert "caseInsensitve same case" <| contains insensitive "aaa" 190 | assert "sensitve same case" <| contains insensitive "aaa" 191 | -------------------------------------------------------------------------------- /test/Test/Elm/Set.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Set (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (assert) 5 | 6 | import Elm.Set as Set 7 | import Elm.Set (Set) 8 | import Data.Tuple (fst, snd) 9 | import Elm.Basics (Bool, (++), (+), (==), (<|), (<=)) 10 | import Prelude (discard, class Eq) 11 | import Elm.List (List(..), (:), (..)) 12 | 13 | 14 | assertEqual :: ∀ a e. (Eq a) => String -> a -> a -> Test e 15 | assertEqual name expected actual = 16 | assert name <| expected == actual 17 | 18 | 19 | set :: Set Int 20 | set = Set.fromList (1..100) 21 | 22 | 23 | setPart1 :: Set Int 24 | setPart1 = Set.fromList (1..50) 25 | 26 | 27 | setPart2 :: Set Int 28 | setPart2 = Set.fromList (51..100) 29 | 30 | 31 | pred :: Int -> Bool 32 | pred x = x <= 50 33 | 34 | 35 | tests :: ∀ e. TestSuite e 36 | tests = suite "Set" do 37 | test "build" do 38 | assertEqual "empty" (Set.fromList (Nil :: List Int)) (Set.empty) 39 | assertEqual "singleton" (Set.fromList (27 : Nil)) (Set.singleton 27) 40 | 41 | assertEqual "insert" (Set.fromList (27 : Nil)) (Set.insert 27 Set.empty) 42 | assertEqual "insert" (Set.fromList (27 : Nil)) (Set.insert 27 (Set.fromList (27 : Nil))) 43 | 44 | assertEqual "remove" Set.empty (Set.remove 27 (Set.singleton 27)) 45 | assertEqual "remove not found" (Set.singleton 27) (Set.remove 28 (Set.singleton 27)) 46 | 47 | test "query" do 48 | assert "size of set of 100 elements" <| 100 == (Set.size set) 49 | assert "size of empty Set" <| 0 == (Set.size Set.empty) 50 | 51 | assert "Simple filter" <| setPart1 == Set.filter pred set 52 | 53 | let partition = Set.partition pred set 54 | assert "Simple partition trues" <| (fst partition) == setPart1 55 | assert "Simple partition falses" <| (snd partition) == setPart2 56 | 57 | assertEqual "isEmpty true" true (Set.isEmpty Set.empty) 58 | assertEqual "isEmpty false" false (Set.isEmpty (Set.singleton 27)) 59 | 60 | assertEqual "member 1" true (Set.member 90 set) 61 | assertEqual "member 2" false (Set.member 234 set) 62 | 63 | test "transform" do 64 | assertEqual "map" (Set.singleton 3) (Set.map ((+) 1) (Set.singleton 2)) 65 | 66 | assertEqual "foldl" "cba" (Set.foldl (++) "" (Set.fromList ("b" : "a" : "c" : Nil))) 67 | assertEqual "foldr" "abc" (Set.foldr (++) "" (Set.fromList ("b" : "a" : "c" : Nil))) 68 | 69 | assertEqual "toList" (3 : Nil) (Set.toList (Set.singleton 3)) 70 | assertEqual "fromLlist" (Set.singleton 3) (Set.fromList (3 : Nil)) 71 | 72 | assertEqual "union" (Set.fromList (1 : 2 : 3 : Nil)) (Set.union (Set.fromList (1 : 2 : Nil)) (Set.fromList (2 : 3 : Nil))) 73 | assertEqual "intersect" (Set.singleton 2) (Set.intersect (Set.fromList (1 : 2 : Nil)) (Set.fromList (2 : 3 : Nil))) 74 | assertEqual "diff" (Set.singleton 1) (Set.diff (Set.fromList (1 : 2 : Nil)) (Set.fromList (2 : 3 : Nil))) 75 | -------------------------------------------------------------------------------- /test/Test/Elm/String.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.String (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (assert) 5 | import Test.Unit.QuickCheck (quickCheck) 6 | import Test.QuickCheck ((===)) 7 | import Test.QuickCheck as QC 8 | 9 | import Elm.String 10 | import Control.Monad.Eff.Random (RANDOM()) 11 | import Prelude (discard, class Eq, not, (&&), ($), (*), (>), (+)) 12 | import Elm.Basics ((<|), (==), (/=), negate) 13 | import Elm.Maybe (Maybe(..)) 14 | import Elm.Result (Result(..)) 15 | import Data.List (fromFoldable) as List 16 | 17 | 18 | assertEqual :: ∀ a e. (Eq a) => String -> a -> a -> Test e 19 | assertEqual name expected actual = 20 | assert name <| expected == actual 21 | 22 | 23 | assertResult :: ∀ a e. (Eq a) => String -> Result String a -> Result String a -> Test e 24 | assertResult name expected actual = 25 | assert name <| expected == actual 26 | 27 | 28 | tests :: ∀ e. TestSuite (random :: RANDOM | e) 29 | tests = suite "String" do 30 | test "Simple Stuff" do 31 | assert "is empty" (isEmpty "") 32 | assert "is not empty" (not (isEmpty ("the world"))) 33 | assertEqual "length" 11 (length "innumerable") 34 | assert "endsWith" (endsWith "ship" "spaceship") 35 | assertEqual "reverse" "desserts" (reverse "stressed") 36 | assertEqual "repeat" "hahaha" (repeat 3 "ha") 37 | assertEqual "indexes" [ 0, 2 ] (indexes "a" "aha") 38 | assertEqual "empty indexes" [] (indexes "" "aha") 39 | assertEqual "fromChar" "c" (fromChar 'c') 40 | assertEqual "trim" "hats" (trim " hats \n") 41 | 42 | test "Combining " do 43 | assertEqual "cons" "cab" (cons 'c' "ab") 44 | 45 | let result = uncons "abc" 46 | 47 | assert "uncons non-empty" <| 48 | case result of 49 | Just val -> val.head == 'a' && val.tail == "bc" 50 | Nothing -> false 51 | 52 | assert "uncons empty" <| 53 | case uncons "" of 54 | Just _ -> false 55 | Nothing -> true 56 | 57 | assertEqual "append 1" "butterfly" (append "butter" "fly") 58 | assertEqual "append 2" "butter" (append "butter" "") 59 | assertEqual "append 3" "butter" (append "" "butter") 60 | 61 | assertEqual "concat" "nevertheless" (concat <| List.fromFoldable ["never","the","less"]) 62 | assertEqual "concat (array)" "nevertheless" (concat <| ["never","the","less"]) 63 | 64 | assertEqual "split commas" (List.fromFoldable ["cat","dog","cow"]) (split "," "cat,dog,cow") 65 | assertEqual "split slashes" (List.fromFoldable ["home","steve","Desktop", ""]) (split "/" "home/steve/Desktop/") 66 | 67 | assertEqual "join spaces" "cat dog cow" (join " " <| List.fromFoldable ["cat","dog","cow"]) 68 | assertEqual "join slashes" "home/steve/Desktop" (join "/" <| List.fromFoldable ["home","steve","Desktop"]) 69 | 70 | assertEqual "slice 1" "c" (slice 2 3 "abcd") 71 | assertEqual "slice 2" "abc" (slice 0 3 "abcd") 72 | assertEqual "slice 3" "abc" (slice 0 (-1) "abcd") 73 | assertEqual "slice 4" "cd" (slice (-2) 4 "abcd") 74 | 75 | test "Mapping" do 76 | assertEqual "map" "a.b.c" (map (\c -> if c == '/' then '.' else c) "a/b/c") 77 | assertEqual "filter" "abc" (filter (\c -> c /= '.') "a.b.c") 78 | assertEqual "foldl" "emit" (foldl cons "" "time") 79 | assertEqual "foldr" "time" (foldr cons "" "time") 80 | 81 | test "left and right" do 82 | assertEqual "left" "go" (left 2 "go left") 83 | assertEqual "right" "left" (right 4 "go left") 84 | assertEqual "dropLeft" "left" (dropLeft 3 "go left") 85 | assertEqual "dropRight" "go" (dropRight 5 "go left") 86 | 87 | test "padding, trimming, splitting" do 88 | assert "pad 1" <| pad 5 ' ' "1" == " 1 " 89 | assert "pad 2" <| pad 5 ' ' "11" == " 11 " 90 | assert "pad 3" <| pad 5 ' ' "121" == " 121 " 91 | 92 | assert "padLeft 1" <| padLeft 5 '.' "1" == "....1" 93 | assert "padLeft 2" <| padLeft 5 '.' "11" == "...11" 94 | assert "padLeft 3" <| padLeft 5 '.' "121" == "..121" 95 | 96 | assert "padRight 1" <| padRight 5 '.' "1" == "1...." 97 | assert "padRight 2" <| padRight 5 '.' "11" == "11..." 98 | assert "padRight 3" <| padRight 5 '.' "121" == "121.." 99 | 100 | assert "trimLeft" <| trimLeft " hats \n" == "hats \n" 101 | assert "trimRight" <| trimRight " hats \n" == " hats" 102 | 103 | assert "words" <| words "How are \t you? \n Good?" == List.fromFoldable ["How","are","you?","Good?"] 104 | assert "lines" <| lines "How are you?\nGood?" == List.fromFoldable ["How are you?", "Good?"] 105 | 106 | test "case" do 107 | assertEqual "toUpper" "UPPER" <| toUpper "Upper" 108 | assertEqual "toLower" "upper" <| toLower "Upper" 109 | 110 | test "logic" do 111 | assert "any true" <| any (\c -> c == '.') "bob." 112 | assert "any false" <| not <| any (\c -> c == '.') "bob" 113 | 114 | assert "all true" <| all (\c -> c == '.') "..." 115 | assert "all false" <| not <| all (\c -> c == '.') "bob." 116 | 117 | assert "contains 1" <| contains "the" "theory" 118 | assert "contains 2" <| not <| contains "hat" "theory" 119 | assert "contains 3" <| not <| contains "THE" "theory" 120 | 121 | assert "startsWith true" <| startsWith "the" "theory" 122 | assert "startsWith false" <| not <| startsWith "ory" "theory" 123 | 124 | assert "endsWith false" <| not <| endsWith "the" "theory" 125 | assert "endsWith true" <| endsWith "ory" "theory" 126 | 127 | assert "indexes 1" <| indexes "i" "Mississippi" == List.fromFoldable [1,4,7,10] 128 | assert "indexes 2" <| indexes "ss" "Mississippi" == List.fromFoldable [2,5] 129 | assert "indexes 3" <| indexes "needle" "haystack" == List.fromFoldable [] 130 | 131 | assert "indices 1" <| indices "i" "Mississippi" == List.fromFoldable [1,4,7,10] 132 | assert "indices 2" <| indices "ss" "Mississippi" == List.fromFoldable [2,5] 133 | assert "indices 3" <| indices "needle" "haystack" == List.fromFoldable [] 134 | 135 | test "conversions" do 136 | assertResult "toInt 1" (toInt "123") (Ok 123) 137 | assertResult "toInt 2" (toInt "-42") (Ok (-42)) 138 | assertResult "toInt 3" (toInt "3.1") (Err "could not convert string '3.1' to an Int") 139 | assertResult "toInt 4" (toInt "31a") (Err "could not convert string '31a' to an Int") 140 | 141 | assertResult "toFloat 1" (toFloat "123") (Ok 123.0) 142 | assertResult "toFloat 2" (toFloat "-42") (Ok (-42.0)) 143 | assertResult "toFloat 3" (toFloat "3.1") (Ok 3.1) 144 | assertResult "toFloat 4" (toFloat "31a") (Err "could not convert string '31a' to a Float") 145 | 146 | assert "toList" <| toList "abc" == List.fromFoldable ['a','b','c'] 147 | assert "fromList" <| fromList (List.fromFoldable ['a','b','c']) == "abc" 148 | 149 | quick 150 | 151 | 152 | repeatLength :: Int -> String -> QC.Result 153 | repeatLength a b = 154 | length (repeat a b) === 155 | if a > 0 156 | then a * length b 157 | else 0 158 | 159 | 160 | isEmptyLength :: String -> QC.Result 161 | isEmptyLength a = 162 | (length a == 0) === isEmpty a 163 | 164 | 165 | checkConsLength :: Char -> String -> QC.Result 166 | checkConsLength a b = 167 | length (cons a b) === (length b) + 1 168 | 169 | 170 | quick :: ∀ e. TestSuite (random :: RANDOM | e) 171 | quick = suite "quick checks" do 172 | test "repeatLength" $ quickCheck repeatLength 173 | test "isEmpty" $ quickCheck isEmptyLength 174 | -------------------------------------------------------------------------------- /test/Test/Elm/Task.js: -------------------------------------------------------------------------------- 1 | /* global exports */ 2 | "use strict"; 3 | 4 | // module Test.Elm.Task 5 | 6 | exports._evenAfter50 = function (int) { 7 | return function (onException, onError, onSuccess) { 8 | setTimeout(function () { 9 | try { 10 | if (int % 2 === 0) { 11 | onSuccess(int); 12 | } else if (int % 3 === 0) { 13 | throw(new Error("Divisible by 3")); 14 | } else { 15 | onError("Not even or divisible by 3"); 16 | } 17 | } 18 | catch (ex) { 19 | onException(ex); 20 | } 21 | }, 50); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /test/Test/Elm/Time.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Time (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (assert) 5 | 6 | import Elm.Time as Time 7 | import Elm.Basics ((<|), (==), (*)) 8 | import Data.Time.Duration (Milliseconds(..), Hours(..), Seconds(..), Minutes(..)) 9 | import Prelude (discard, class Eq) 10 | 11 | 12 | assertEqual :: forall a e. (Eq a) => String -> a -> a -> Test e 13 | assertEqual name expected actual = 14 | assert name <| expected == actual 15 | 16 | 17 | tests :: forall e. TestSuite e 18 | tests = suite "Elm.Time" do 19 | test "Time.Conversion Factors" do 20 | assert "Time.millisecond -> second" <| 500.0 * Time.millisecond == 0.5 * Time.second 21 | assert "Time.minute -> hour" <| 30.0 * Time.minute == 0.5 * Time.hour 22 | assert "Time.inMilliseconds" <| Time.inMilliseconds 500.0 == 500.0 23 | assert "Time.inSeconds" <| Time.inSeconds 5000.0 == 5.0 24 | assert "Time.inMinutes" <| Time.inMinutes 360000.0 == 6.0 25 | assert "Time.inHours" <| Time.inHours 3600000.0 == 1.0 26 | 27 | test "Time.Conversion with Data.Time" do 28 | assert "to milliseconds" <| Time.fromTime 500.0 == Milliseconds 500.0 29 | assert "to seconds" <| Time.fromTime 500.0 == Seconds 0.5 30 | assert "to minutes" <| Time.fromTime 60000.0 == Minutes 1.0 31 | assert "to hours" <| Time.fromTime 3600000.0 == Hours 1.0 32 | assert "from milliseconds" <| Time.toTime (Milliseconds 500.0) == 500.0 33 | assert "from seconds" <| Time.toTime (Seconds 0.5) == 500.0 34 | assert "from minutes" <| Time.toTime (Minutes 1.0) == 60000.0 35 | assert "from hours" <| Time.toTime (Hours 1.0) == 3600000.0 36 | 37 | -------------------------------------------------------------------------------- /test/Test/Elm/Trampoline.purs: -------------------------------------------------------------------------------- 1 | module Test.Elm.Trampoline (tests) where 2 | 3 | import Test.Unit (TestSuite, Test, suite, test) 4 | import Test.Unit.Assert (equal) 5 | 6 | import Elm.Trampoline 7 | import Prelude (class Show, class Eq, map, ($), discard, (+), (-), flip, zero, one, (==)) 8 | import Data.Foldable (sequence_) 9 | import Elm.List ((..)) 10 | import Data.Int53 (Int53, truncate, fromInt) 11 | 12 | 13 | infixl 9 equals as === 14 | 15 | equals :: ∀ a e. Eq a => Show a => a -> a -> Test e 16 | equals = flip equal 17 | 18 | 19 | badSum :: Int53 -> Int53 20 | badSum n = 21 | let 22 | loop x acc = 23 | if x == zero 24 | then acc 25 | else loop (x - one) (acc + x) 26 | 27 | in 28 | loop n zero 29 | 30 | 31 | goodSum :: Int53 -> Int53 32 | goodSum n = 33 | let 34 | sumT x acc = 35 | if x == zero 36 | then done acc 37 | else jump (\_ -> sumT (x - one) (acc + x)) 38 | 39 | in 40 | evaluate $ sumT n zero 41 | 42 | 43 | mkLoopCheck :: ∀ e. Int -> Test e 44 | mkLoopCheck n = 45 | (badSum $ fromInt n) === (goodSum $ fromInt n) 46 | 47 | 48 | tests :: ∀ e. TestSuite e 49 | tests = suite "Trampoline" do 50 | test "noStackOverflow" do 51 | (goodSum $ truncate 1000000.0) === truncate 500000500000.0 52 | 53 | test "loopChecks" $ 54 | sequence_ $ 55 | map mkLoopCheck (0 .. 25) 56 | 57 | -------------------------------------------------------------------------------- /test/Test/Main.purs: -------------------------------------------------------------------------------- 1 | module Test.Main where 2 | 3 | import Control.Monad.Aff.AVar (AVAR) 4 | import Control.Monad.Eff (Eff) 5 | import Control.Monad.Eff.Console (CONSOLE) 6 | import Control.Monad.Eff.Exception (EXCEPTION) 7 | import Control.Monad.Eff.Random (RANDOM) 8 | import Control.Monad.IO (INFINITY) 9 | import Prelude (Unit, discard) 10 | import Test.Elm.Array as Array 11 | import Test.Elm.Basics as Basics 12 | import Test.Elm.BasicsElm as BasicsElm 13 | import Test.Elm.Bitwise as Bitwise 14 | import Test.Elm.Char as Char 15 | import Test.Elm.Color as Color 16 | import Test.Elm.Date as Date 17 | import Test.Elm.Dict as Dict 18 | import Test.Elm.Json as Json 19 | import Test.Elm.List as List 20 | import Test.Elm.ListElm as ListElm 21 | import Test.Elm.Maybe as Maybe 22 | import Test.Elm.Random as Random 23 | import Test.Elm.Regex as Regex 24 | import Test.Elm.Result as Result 25 | import Test.Elm.Set as Set 26 | import Test.Elm.String as String 27 | import Test.Elm.Task as Task 28 | import Test.Elm.Time as Time 29 | import Test.Elm.Trampoline as Trampoline 30 | import Test.Unit.Console (TESTOUTPUT) 31 | import Test.Unit.Main (runTest) 32 | 33 | 34 | main :: Eff 35 | ( console :: CONSOLE 36 | , testOutput :: TESTOUTPUT 37 | , avar :: AVAR 38 | , exception :: EXCEPTION 39 | , infinity :: INFINITY 40 | , random :: RANDOM 41 | ) Unit 42 | main = 43 | runTest do 44 | Array.tests 45 | Basics.tests 46 | BasicsElm.tests 47 | Bitwise.tests 48 | Char.tests 49 | Color.tests 50 | Date.tests 51 | Dict.tests 52 | Json.tests 53 | List.tests 54 | ListElm.tests 55 | Maybe.tests 56 | Random.tests 57 | Regex.tests 58 | Result.tests 59 | Set.tests 60 | String.tests 61 | Time.tests 62 | Task.tests 63 | Trampoline.tests 64 | --------------------------------------------------------------------------------