Repository: arturopala/elm-monocle
Branch: master
Commit: 7d8be090c9b7
Files: 22
Total size: 100.7 KB
Directory structure:
gitextract_bil9_ung/
├── .gitignore
├── LICENSE
├── README.md
├── elm.json
├── example/
│ └── OptionalExample.elm
├── package.json
├── src/
│ └── Monocle/
│ ├── Common.elm
│ ├── Compose.elm
│ ├── Iso.elm
│ ├── Lens.elm
│ ├── Optional.elm
│ ├── Prism.elm
│ └── Traversal.elm
└── tests/
├── .gitignore
├── CommonSpec.elm
├── ComposeSpec.elm
├── IsoSpec.elm
├── LensSpec.elm
├── OptionalSpec.elm
├── PrismSpec.elm
├── Tests.elm
└── TraversalSpec.elm
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# added by GitSavvy
/elm-stuff/
# added by GitSavvy
node_modules
# added by GitSavvy
/documentation.json
# added by GitSavvy
/monocle.js
# added by GitSavvy
/documentation.md
/package-lock.json
/yarn-error.log
/yarn.lock
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2016 Artur Opala
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
[](https://semaphoreci.com/arturopala/elm-monocle)
elm-monocle
===========
A [Monocle](http://optics-dev.github.io/Monocle/)-inspired library providing purely functional abstractions to manipulate complex records in the [elm](http://www.elm-lang.org/) language.
Published as [**arturopala/elm-monocle**](http://package.elm-lang.org/packages/arturopala/elm-monocle/latest) library.
# Long Example
```elm
import Monocle.Optional exposing (Optional)
import Monocle.Lens exposing (Lens)
type StreetType
= Street
| Avenue
type Country
= US
| UK
| FI
| PL
| DE
type alias Address =
{ streetName : String
, streetType : StreetType
, floor : Maybe Int
, town : String
, region : Maybe String
, postcode : String
, country : Country
}
type alias Place =
{ name : String
, description : Maybe String
, address : Maybe Address
}
addressOfPlace : Optional Place Address
addressOfPlace =
Optional .address (\b a -> { a | address = Just b })
regionOfAddress : Optional Address String
regionOfAddress =
Optional .region (\b a -> { a | region = Just b })
streetNameOfAddress : Lens Address String
streetNameOfAddress =
Lens .streetName (\b a -> { a | streetName = b })
regionOfPlace : Optional Place String
regionOfPlace =
addressOfPlace |> Monocle.Compose.optionalWithOptional regionOfAddress
streetNameOfPlace : Optional Place String
streetNameOfPlace =
addressOfPlace |> Monocle.Compose.optionalWithLens streetNameOfAddress
place : Place
place =
{ name = "MyPlace"
, description = Nothing
, address =
Just
{ streetName = "Union Road"
, streetType = Street
, floor = Nothing
, town = "Daisytown"
, region = Nothing
, postcode = "00100"
, country = US
}
}
updatedPlace : Place
updatedPlace =
place
|> regionOfPlace.set "NorthEast"
|> streetNameOfPlace.set "Union Avenue"
```
# Abstractions
## Iso
An Iso is a tool which converts elements of type A into elements of type B and back without loss.
```elm
type alias Iso a b =
{ get : a -> b
, reverseGet : b -> a
}
```
###### Example
```elm
string2CharListIso : Iso String (List Char)
string2CharListIso =
Iso String.toList String.fromList
(string2CharListIso.get "ABcdE") == ['A','B','c','d','E']
(string2CharListIso.reverseGet ['A','B','c','d','E']) == "ABcdE"
```
## Prism
A Prism is a tool which optionally converts elements of type A into elements of type B and back.
```elm
type alias Prism a b =
{ getOption : a -> Maybe b
, reverseGet : b -> a
}
```
###### Example
```elm
string2IntPrism : Prism String Int
string2IntPrism =
Prism String.toInt String.fromInt
string2IntPrism.getOption "17896" == Just 17896
string2IntPrism.getOption "1a896" == Nothing
string2IntPrism.reverseGet 1626767 = "1626767"
```
## Lens
A Lens is a functional concept which solves a very common problem: how to easily update a complex immutable structure, for this purpose Lens acts as a zoom into a record.
```elm
type alias Lens a b =
{ get : a -> b
, set : b -> a -> a
}
```
###### Example
```elm
type alias Address =
{ streetName: String
, postcode: String
, town: String
}
type alias Place =
{ name: String
, address: Address
}
addressStreetNameLens : Lens Address String
addressStreetNameLens =
Lens .streetName (\b a -> { a | streetName = b })
placeAddressLens : Lens Place Address
placeAddressLens =
Lens .address (\b a -> { a | address = b })
placeStreetName: Lens Place String
placeStreetName =
placeAddressLens |> Monocle.Compose.lensWithLens addressStreetNameLens
myPlace = Place "my" (Address "Elm" "00001" "Daisytown")
placeStreetName.get myPlace == "Elm"
myNewPlace = placeStreetName.set "Oak" myPlace
placeStreetName.get myNewPlace == "Oak"
myNewPlace == Place "my" (Address "Oak" "00001" "Daisytown")
```
## Optional
A Optional is a weaker Lens and a weaker Prism.
```elm
type alias Optional a b =
{ getOption : a -> Maybe b
, set : b -> a -> a
}
```
###### Example
```elm
addressRegionOptional : Optional Address String
addressRegionOptional =
Optional .region (\b a -> { a | region = Just b })
string2IntPrism : Prism String Int
string2IntPrism = Prism String.toInt String.fromInt
addressRegionIntOptional: Optional Address Int
addressRegionIntOptional =
addressRegionOptional |> Monocle.Compose.optionalWithPrism string2IntPrism
string2CharListIso : Iso String (List Char)
string2CharListIso = Iso String.toList String.fromList
addressRegionListCharOptional: Optional Address (List Char)
addressRegionListCharOptional =
addressRegionOptional |> Monocle.Compose.optionalWithIso string2CharListIso
modifyRegion: String -> String
modifyRegion region = String.reverse region
modifyAddressRegion: Address -> Maybe Address
modifyAddressRegion address = Optional.modifyOption addressRegionOptional modifyRegion address
modifyRegion: String -> String
modifyRegion region = String.reverse region
modifyAddressRegion: Address -> Address
modifyAddressRegion address = Optional.modify addressRegionOptional modifyRegion address
```
## Traversal
A Traversal allows you to modify many elements at once.
```elm
type alias Traversal a b =
(b -> b) -> a -> a
```
(`Traversal a b` is just an alias for a function that applies
a transformation over `b` elements of a larger `a` structure.)
###### Example
```elm
firstNameLens : Lens Friend String
firstNameLens =
Lens .firstName (\b a -> { a | firstName = b })
bestFriendsTraversal : Traversal (List Friend) Friend
bestFriendsTraversal =
Traversal.some
Traversal.list
(\friend -> friend.value == Best)
friendsLens : Lens Account (List Friend)
friendsLens =
Lens .friends (\b a -> { a | friends = b })
firstNamesOfBestFriends : Traversal Account String
firstNamesOfBestFriends =
friendsLens
|> Compose.lensWithTraversal bestFriendsTraversal
|> Compose.traversalWithLens firstNameLens
upcaseBestFriendsFirstNames : Account -> Account
upcaseBestFriendsFirstNames account =
Traversal.modify firstNamesOfBestFriends String.toUpper
```
## Common
Common lenses/prisms/optionals that most projects will use.
#### Step into a `Maybe` value.
```elm
maybe.set 5 Nothing
> Just 5
```
#### Step into an `Array` at the given index.
```elm
.getOption (array 2) (Array.fromList [ 10, 11, 12, 13 ])
> Just 12
.getOption (array 8) (Array.fromList [ 10, 11, 12, 13 ])
> Nothing
```
#### Step into a `Dict` with the given key.
```elm
.getOption (dict "Tom") (Dict.fromList [ ( "Tom", "Cat" ) ])
> Just "Cat"
.getOption (dict "Jerry") (Dict.fromList [ ( "Tom", "Cat" ) ])
> Nothing
```
#### Step into the success value of a `Result`.
```elm
result.getOption (Ok 5)
> Just 5
result.getOption (Err "500")
> Nothing
```
#### Step into a record with an `id` key.
Since records with an `id` field are incredible common, this is
included for convenience. It also serves as a simple recipe for
creating record lenses.
```elm
id.get { id = 1000, name = ... }
> 1000
```
#### Step into the first element of a pair.
```elm
first.get ( 'a', 'b' )
> 'a'
```
#### Step into the second element of a pair.
```elm
second.get ( 'a', 'b' )
> 'b'
```
# Build
## Prerequisites
- Node.js
- Yarn
- Run `yarn install-with-elm`
## Compile
Run `yarn compile`
## Test
Run `elm-test`
================================================
FILE: elm.json
================================================
{
"type": "package",
"name": "arturopala/elm-monocle",
"summary": "Library providing functional tools to manipulate complex records",
"license": "MIT",
"version": "2.2.0",
"exposed-modules": [
"Monocle.Iso",
"Monocle.Prism",
"Monocle.Lens",
"Monocle.Optional",
"Monocle.Traversal",
"Monocle.Common",
"Monocle.Compose"
],
"elm-version": "0.19.0 <= v < 0.20.0",
"dependencies": {
"elm/core": "1.0.0 <= v < 2.0.0"
},
"test-dependencies": {
"elm-explorations/test": "1.1.0 <= v < 1.1.1"
}
}
================================================
FILE: example/OptionalExample.elm
================================================
module OptionalExample exposing (Address, Country(..), Place, StreetType(..), addressOfPlace, place, regionOfAddress, regionOfPlace, streetNameOfAddress, streetNameOfPlace, updatedPlace)
import Monocle.Lens exposing (Lens)
import Monocle.Optional exposing (Optional)
type StreetType
= Street
| Avenue
type Country
= US
| UK
| FI
| PL
| DE
type alias Address =
{ streetName : String
, streetType : StreetType
, floor : Maybe Int
, town : String
, region : Maybe String
, postcode : String
, country : Country
}
type alias Place =
{ name : String
, description : Maybe String
, address : Maybe Address
}
addressOfPlace : Optional Place Address
addressOfPlace =
let
getOption p =
p.address
set a p =
{ p | address = Just a }
in
Optional getOption set
regionOfAddress : Optional Address String
regionOfAddress =
let
getOption a =
a.region
set r a =
{ a | region = Just r }
in
Optional getOption set
streetNameOfAddress : Lens Address String
streetNameOfAddress =
let
get a =
a.streetName
set sn a =
{ a | streetName = sn }
in
Lens get set
regionOfPlace : Optional Place String
regionOfPlace =
Monocle.Optional.compose addressOfPlace regionOfAddress
streetNameOfPlace : Optional Place String
streetNameOfPlace =
Monocle.Optional.composeLens addressOfPlace streetNameOfAddress
place : Place
place =
{ name = "MyPlace"
, description = Nothing
, address =
Just
{ streetName = "Union Road"
, streetType = Street
, floor = Nothing
, town = "Daisytown"
, region = Nothing
, postcode = "00100"
, country = US
}
}
updatedPlace : Place
updatedPlace =
place |> regionOfPlace.set "NorthEast" |> streetNameOfPlace.set "Union Avenue"
================================================
FILE: package.json
================================================
{
"name": "elm-monocle",
"version": "1.6.0",
"description": "Library providing purely functional abstractions to manipulate records",
"scripts": {
"compile": "elm make ./src/**/*.elm --output monocle.js",
"install-with-elm": "yarn install && elm make",
"test": "elm-test",
"test-and-watch": "elm-test --watch",
"bump": "elm bump",
"publish": "elm publish"
},
"repository": {
"type": "git",
"url": "git+https://github.com/arturopala/elm-monocle.git"
},
"keywords": [
"monocle",
"lens",
"iso",
"prism",
"optional",
"record"
],
"author": "Artur Opala",
"license": "MIT",
"bugs": {
"url": "https://github.com/arturopala/elm-monocle/issues"
},
"homepage": "https://github.com/arturopala/elm-monocle#readme",
"devDependencies": {
"elm": "^0.19.0",
"elm-test": "0.19.0-beta9"
}
}
================================================
FILE: src/Monocle/Common.elm
================================================
module Monocle.Common exposing
( maybe
, array
, list
, listToArray
, dict
, result
, id
, first
, second
)
{-| Common lenses/prisms/optionals that most projects will use.
@docs maybe
@docs array
@docs list
@docs listToArray
@docs dict
@docs result
@docs id
@docs first
@docs second
-}
import Array exposing (Array)
import Dict exposing (Dict)
import Monocle.Iso exposing (Iso)
import Monocle.Lens as Lens exposing (Lens)
import Monocle.Optional as Optional exposing (Optional)
{-| Step into a `Maybe` value.
maybe.set 5 Nothing
> Just 5
-}
maybe : Optional (Maybe a) a
maybe =
{ getOption = identity
, set = always << Just
}
{-| Step into an `Array` at the given index.
.getOption (array 2) (Array.fromList [ 10, 11, 12, 13 ])
> Just 12
.getOption (array 8) (Array.fromList [ 10, 11, 12, 13 ])
> Nothing
-}
array : Int -> Optional (Array a) a
array index =
{ getOption = Array.get index
, set = Array.set index
}
{-| Step into an `List` at the given index.
(shortcut to avoid converting a `List` to an `Array` ; if it is too slow,
consider using `array` and an `Array` instead of a `List` in your data)
.getOption (list 2) [ 10, 11, 12, 13 ]
> Just 12
.getOption (list 8) [ 10, 11, 12, 13 ]
> Nothing
-}
list : Int -> Optional (List a) a
list index =
Optional.compose (Optional.fromLens (Lens.fromIso listToArray)) (array index)
{-| Iso that converts a list to an array.
.get listToArray [ 1, 2, 3, 4 ]
== Array.fromList [ 1, 2, 3, 4 ]
> True
.reverseGet listToArray (Array.fromList [ 9, 8, 7, 6 ])
== [ 9, 8, 7, 6 ]
> True
-}
listToArray : Iso (List a) (Array a)
listToArray =
Iso Array.fromList Array.toList
{-| Step into a `Dict` with the given key.
.getOption (dict "Tom") (Dict.fromList [ ( "Tom", "Cat" ) ])
> Just "Cat"
.getOption (dict "Jerry") (Dict.fromList [ ( "Tom", "Cat" ) ])
> Nothing
-}
dict : comparable -> Optional (Dict comparable v) v
dict key =
{ getOption = Dict.get key
, set = Dict.insert key
}
{-| Step into the success value of a `Result`.
result.getOption (Ok 5)
> Just 5
result.getOption (Err "500")
> Nothing
-}
result : Optional (Result e a) a
result =
{ getOption = Result.toMaybe
, set = always << Ok
}
{-| Step into a record with an `id` key.
id.get { id = 1000, name = ... }
> 1000
Since records with an `id` field are incredible common, this is
included for convenience. It also serves as a simple recipe for
creating record lenses.
-}
id : Lens { a | id : b } b
id =
{ get = .id
, set = \a record -> { record | id = a }
}
{-| Step into the first element of a pair.
first.get ( 'a', 'b' )
> 'a'
-}
first : Lens ( a, b ) a
first =
{ get = Tuple.first
, set = \a ( _, b ) -> ( a, b )
}
{-| Step into the second element of a pair.
second.get ( 'a', 'b' )
> 'b'
-}
second : Lens ( a, b ) b
second =
{ get = Tuple.second
, set = \b ( a, _ ) -> ( a, b )
}
================================================
FILE: src/Monocle/Compose.elm
================================================
module Monocle.Compose exposing
( isoWithIso, isoWithPrism, isoWithLens, isoWithOptional, isoWithTraversal
, prismWithIso, prismWithPrism, prismWithLens, prismWithOptional, prismWithTraversal
, lensWithIso, lensWithPrism, lensWithLens, lensWithOptional, lensWithTraversal
, optionalWithIso, optionalWithPrism, optionalWithLens, optionalWithOptional, optionalWithTraversal
, traversalWithIso, traversalWithPrism, traversalWithLens, traversalWithOptional, traversalWithTraversal
)
{-| Pipeline-friendly composition helpers
Using these allow to compose an "outer" optic with an "inner" other optic.
Optics in functional programming languages that support typeclasses can be
expressed as functions that compose through the composition operator (just like
any other functions) ; in Elm (plus typeclasses), it would look like this:
lensAtoB >> lensBtoC >> lensCtoD == lensAtoD
lensAtoB >> optionalBtoC >> prismCtoD == optionalAtoC
But Elm doesn't support typeclasses, so we're stuck with defining composition
functions that look similar like this:
import Monocle.Compose as Compose
lensAtoB
|> Compose.lensWithLens lensBtoC
|> Compose.lensWithLens lensCtoD
== lensAtoD
lensAtoB
|> Compose.lensWithOptional optionalBtoC
|> Compose.optionalWithPrism prismCtoD
== optionalAtoC
This is arguably more "discoverable" and maybe more readable, if more verbose.
# From an Iso
@docs isoWithIso, isoWithPrism, isoWithLens, isoWithOptional, isoWithTraversal
# From a Prism
@docs prismWithIso, prismWithPrism, prismWithLens, prismWithOptional, prismWithTraversal
# From a Lens
@docs lensWithIso, lensWithPrism, lensWithLens, lensWithOptional, lensWithTraversal
# From an Optional
@docs optionalWithIso, optionalWithPrism, optionalWithLens, optionalWithOptional, optionalWithTraversal
# From a Traversal
@docs traversalWithIso, traversalWithPrism, traversalWithLens, traversalWithOptional, traversalWithTraversal
-}
import Monocle.Iso as Iso exposing (Iso)
import Monocle.Lens as Lens exposing (Lens)
import Monocle.Optional as Optional exposing (Optional)
import Monocle.Prism as Prism exposing (Prism)
import Monocle.Traversal as Traversal exposing (Traversal)
{-| pipeline-friendly composition between two Iso
ab : Iso A B
ab = ..
bc : Iso B C
bc = ..
ac : Iso A C
ac =
ab
|> ComposeIso.isoWithIso bc
-}
isoWithIso : Iso b c -> Iso a b -> Iso a c
isoWithIso inner outer =
Iso.compose outer inner
{-| pipeline-friendly composition between an outer Iso and an inner Prism
(the result is a Prism)
ab : Iso A B
ab = ..
bc : Prism B C
bc = ..
ac : Prism A C
ac =
ab
|> ComposeIso.isoWithPrism bc
-}
isoWithPrism : Prism b c -> Iso a b -> Prism a c
isoWithPrism inner outer =
let
getOption =
outer.get >> inner.getOption
reverseGet =
inner.reverseGet >> outer.reverseGet
in
Prism getOption reverseGet
{-| pipeline-friendly composition between an outer Iso and an inner Traversal
(the result is a Traversal)
ab : Iso A B
ab = ..
bc : Traversal B C
bc = ..
ac : Traversal A C
ac =
ab
|> ComposeIso.isoWithTraversal bc
-}
isoWithTraversal : Traversal b c -> Iso a b -> Traversal a c
isoWithTraversal inner outer transformation =
Iso.modify outer (Traversal.modify inner transformation)
{-| pipeline-friendly composition between an outer Iso and an inner Lens
(the result is a Lens)
ab : Iso A B
ab = ..
bc : Lens B C
bc = ..
ac : Lens A C
ac =
ab
|> ComposeIso.isoWithLens bc
-}
isoWithLens : Lens b c -> Iso a b -> Lens a c
isoWithLens inner outer =
let
get =
outer.get >> inner.get
set c =
Iso.modify outer (inner.set c)
in
Lens get set
{-| pipeline-friendly composition between an outer Iso and an inner Optional
(the result is an Optional)
ab : Iso A B
ab = ..
bc : Optional B C
bc = ..
ac : Optional A C
ac =
ab
|> ComposeIso.isoWithOptional bc
-}
isoWithOptional : Optional b c -> Iso a b -> Optional a c
isoWithOptional inner outer =
let
getOption =
outer.get >> inner.getOption
set c =
Iso.modify outer (inner.set c)
in
Optional getOption set
{-| pipeline-friendly composition between an outer Prism and an inner Iso
(the result is a Prism)
ab : Prism A B
ab = ..
bc : Iso B C
bc = ..
ac : Prism A C
ac =
ab
|> ComposePrism.prismWithIso bc
-}
prismWithIso : Iso b c -> Prism a b -> Prism a c
prismWithIso inner outer =
let
getOption =
outer.getOption >> Maybe.map inner.get
reverseGet =
inner.reverseGet >> outer.reverseGet
in
Prism getOption reverseGet
{-| pipeline-friendly composition between two Prisms
ab : Prism A B
ab = ..
bc : Prism B C
bc = ..
ac : Prism A C
ac =
ab
|> ComposePrism.prismWithPrism bc
-}
prismWithPrism : Prism b c -> Prism a b -> Prism a c
prismWithPrism inner outer =
Prism.compose outer inner
{-| pipeline-friendly composition between an outer Prism and an inner Lens
(the result is an Optional)
ab : Prism A B
ab = ..
bc : Lens B C
bc = ..
ac : Optional A C
ac =
ab
|> ComposePrism.prismWithLens bc
-}
prismWithLens : Lens b c -> Prism a b -> Optional a c
prismWithLens inner outer =
let
getOption =
outer.getOption >> Maybe.map inner.get
set c =
Prism.modify outer (inner.set c)
in
Optional getOption set
{-| pipeline-friendly composition between an outer Prism and an inner Optional
(the result is an Optional)
ab : Prism A B
ab = ..
bc : Optional B C
bc = ..
ac : Optional A C
ac =
ab
|> ComposePrism.prismWithOptional bc
-}
prismWithOptional : Optional b c -> Prism a b -> Optional a c
prismWithOptional inner outer =
let
getOption =
outer.getOption >> Maybe.andThen inner.getOption
set c =
Prism.modify outer (inner.set c)
in
Optional getOption set
{-| pipeline-friendly composition between an outer Prism and an inner Traversal
(the result is a Traversal)
ab : Prism A B
ab = ..
bc : Traversal B C
bc = ..
ac : Traversal A C
ac =
ab
|> ComposePrism.prismWithTraversal bc
-}
prismWithTraversal : Traversal b c -> Prism a b -> Traversal a c
prismWithTraversal inner outer transformation =
Prism.modify outer (Traversal.modify inner transformation)
{-| pipeline-friendly composition between an outer Lens and an inner Iso
(the result is a Lens)
ab : Lens A B
ab = ..
bc : Iso B C
bc = ..
ac : Lens A C
ac =
ab
|> Compose.lensWithIso bc
-}
lensWithIso : Iso b c -> Lens a b -> Lens a c
lensWithIso inner outer =
let
get =
outer.get >> inner.get
set c =
outer.set (inner.reverseGet c)
in
Lens get set
{-| pipeline-friendly composition between an outer Lens and an inner Prism
(the result is an Optional)
ab : Lens A B
ab = ..
bc : Prism B C
bc = ..
ac : Optional A C
ac =
ab
|> Compose.lensWithPrism bc
-}
lensWithPrism : Prism b c -> Lens a b -> Optional a c
lensWithPrism inner outer =
let
getOption =
outer.get >> inner.getOption
set c =
outer.set (inner.reverseGet c)
in
Optional getOption set
{-| pipeline-friendly composition between two Lenses
ab : Lens A B
ab = ..
bc : Lens B C
bc = ..
ac : Lens A C
ac =
ab
|> Compose.lensWithLens bc
-}
lensWithLens : Lens b c -> Lens a b -> Lens a c
lensWithLens inner outer =
Lens.compose outer inner
{-| pipeline-friendly composition between an outer Lens and an inner Optional
(the result is an Optional)
ab : Lens A B
ab = ..
bc : Optional B C
bc = ..
ac : Optional A C
ac =
ab
|> Compose.lensWithOptional bc
-}
lensWithOptional : Optional b c -> Lens a b -> Optional a c
lensWithOptional inner outer =
let
getOption =
outer.get >> inner.getOption
set c =
Lens.modify outer (inner.set c)
in
Optional getOption set
{-| pipeline-friendly composition between an outer Lens and an inner Traversal
(the result is an Traversal)
ab : Lens A B
ab = ..
bc : Traversal B C
bc = ..
ac : Traversal A C
ac =
ab
|> Compose.lensWithTraversal bc
-}
lensWithTraversal : Traversal b c -> Lens a b -> Traversal a c
lensWithTraversal inner outer transformation =
Lens.modify outer (Traversal.modify inner transformation)
{-| pipeline-friendly composition between an outer Optional and an inner Iso
(the result is an Optional)
ab : Optional A B
ab = ..
bc : Iso B C
bc = ..
ac : Optional A C
ac =
ab
|> ComposeOptional.optionalWithIso bc
-}
optionalWithIso : Iso b c -> Optional a b -> Optional a c
optionalWithIso inner outer =
let
getOption =
outer.getOption >> Maybe.map inner.get
set c =
outer.set (inner.reverseGet c)
in
Optional getOption set
{-| pipeline-friendly composition between an outer Optional and an inner Prism
(the result is an Optional)
ab : Optional A B
ab = ..
bc : Prism B C
bc = ..
ac : Optional A C
ac =
ab
|> ComposeOptional.withPrism bc
-}
optionalWithPrism : Prism b c -> Optional a b -> Optional a c
optionalWithPrism inner outer =
let
getOption =
outer.getOption >> Maybe.andThen inner.getOption
set c =
outer.set (inner.reverseGet c)
in
Optional getOption set
{-| pipeline-friendly composition between an outer Optional and an inner Lens
(the result is an Optional)
ab : Optional A B
ab = ..
bc : Lens B C
bc = ..
ac : Optional A C
ac =
ab
|> ComposeOptional.optionalWithLens bc
-}
optionalWithLens : Lens b c -> Optional a b -> Optional a c
optionalWithLens inner outer =
let
getOption =
outer.getOption >> Maybe.map inner.get
set c =
Optional.modify outer (inner.set c)
in
Optional getOption set
{-| pipeline-friendly composition between two Optionals
ab : Optional A B
ab = ..
bc : Optional B C
bc = ..
ac : Optional A C
ac =
ab
|> ComposeOptional.optionalWithOptional bc
-}
optionalWithOptional : Optional b c -> Optional a b -> Optional a c
optionalWithOptional inner outer =
Optional.compose outer inner
{-| pipeline-friendly composition between an outer Optional and an inner Traversal
(the result is a Optional)
ab : Optional A B
ab = ..
bc : Traversal B C
bc = ..
ac : Optional A C
ac =
ab
|> ComposeOptional.optionalWithTraversal bc
-}
optionalWithTraversal : Traversal b c -> Optional a b -> Traversal a c
optionalWithTraversal inner outer transformation =
Optional.modify outer (Traversal.modify inner transformation)
{-| pipeline-friendly composition between an outer Traversal and an inner Iso
(the result is a Traversal)
ab : Traversal A B
ab = ..
bc : Iso B C
bc = ..
ac : Traversal A C
ac =
ab
|> ComposeTraversal.traversalWithIso bc
-}
traversalWithIso : Iso b c -> Traversal a b -> Traversal a c
traversalWithIso inner outer transformation =
Traversal.modify outer (Iso.modify inner transformation)
{-| pipeline-friendly composition between an outer Traversal and an inner Lens
(the result is a Traversal)
ab : Traversal A B
ab = ..
bc : Lens B C
bc = ..
ac : Traversal A C
ac =
ab
|> ComposeTraversal.traversalWithLens bc
-}
traversalWithLens : Lens b c -> Traversal a b -> Traversal a c
traversalWithLens inner outer transformation =
Traversal.modify outer (Lens.modify inner transformation)
{-| pipeline-friendly composition between an outer Traversal and an inner Optional
(the result is a Traversal)
ab : Traversal A B
ab = ..
bc : Optional B C
bc = ..
ac : Traversal A C
ac =
ab
|> ComposeTraversal.traversalWithOptional bc
-}
traversalWithOptional : Optional b c -> Traversal a b -> Traversal a c
traversalWithOptional inner outer transformation =
Traversal.modify outer (Optional.modify inner transformation)
{-| pipeline-friendly composition between an outer Traversal and an inner Prism
(the result is a Traversal)
ab : Traversal A B
ab = ..
bc : Prism B C
bc = ..
ac : Traversal A C
ac =
ab
|> ComposeTraversal.traversalWithPrism bc
-}
traversalWithPrism : Prism b c -> Traversal a b -> Traversal a c
traversalWithPrism inner outer transformation =
Traversal.modify outer (Prism.modify inner transformation)
{-| pipeline-friendly composition between two Traversals
(the result is a Traversal)
ab : Traversal A B
ab = ..
bc : Traversal B C
bc = ..
ac : Traversal A C
ac =
ab
|> ComposeTraversal.traversalWithTraversal bc
-}
traversalWithTraversal : Traversal b c -> Traversal a b -> Traversal a c
traversalWithTraversal inner outer transformation =
Traversal.modify outer (Traversal.modify inner transformation)
================================================
FILE: src/Monocle/Iso.elm
================================================
module Monocle.Iso exposing
( Iso
, reverse, modify, compose
)
{-| An Iso is a tool which converts elements of type A into elements of type B and back without loss.
# Definition
@docs Iso
# Laws
Identity: \x -> iso.get(iso.reverseGet x) == x
Reversed: \x -> iso.reverseGet(iso.get x) == x
# Example
string2CharListIso : Iso String (List Char)
string2CharListIso =
Iso String.toList String.fromList
(string2CharListIso.get "ABcdE") == ['A','B','c','d','E']
(string2CharListIso.reverseGet ['A','B','c','d','E']) == "ABcdE"
# Derived methods
@docs reverse, modify, compose
-}
{-| In order to create an `Iso` we need to supply two total functions: `get` and `reverseGet`
-}
type alias Iso a b =
{ get : a -> b
, reverseGet : b -> a
}
{-| Creates reversed `Iso b a`, exchanges functions `get` and `reverseGet`
.get (Iso.reversed someiso) == someiso.reverseGet
.reverseGet (Iso.reversed someiso) == someiso.get
Iso.compose someiso (Iso.reversed someiso) == Iso identity identity
-}
reverse : Iso a b -> Iso b a
reverse iso =
Iso iso.reverseGet iso.get
{-| Modifies given function `(b -> b)` to be `(a -> a)` using `Iso a b`
someiso = Iso String.toList String.fromList
somefx xs = '@' :: xs
modified = Iso.modify someiso somefx
(modified "artur") == "@artur"
-}
modify : Iso a b -> (b -> b) -> a -> a
modify iso f =
iso.get >> f >> iso.reverseGet
{-| Composes `Iso a b` with `Iso b c` and returns `Iso a c`
-}
compose : Iso a b -> Iso b c -> Iso a c
compose outer inner =
Iso (outer.get >> inner.get) (inner.reverseGet >> outer.reverseGet)
================================================
FILE: src/Monocle/Lens.elm
================================================
module Monocle.Lens exposing
( Lens
, compose, modify, modify2, modify3, modifyAndMerge, zip, tuple, tuple3
, fromIso
)
{-| A Lens is a functional concept which solves a very common problem:
how to easily update a complex immutable structure,
for this purpose Lens acts as a zoom into a record.
# Definition
@docs Lens
# Example
addressStreetNameLens : Lens Address String
addressStreetNameLens =
let
get a =
a.streetName
set sn a =
{ a | streetName = sn }
in
Lens get set
placeAddressLens : Lens Place Address
placeAddressLens =
let
get p =
p.address
set a p =
{ p | address = a }
in
Lens get set
placeStreetName : Lens Place String
placeStreetName =
compose placeAddressLens addressStreetNameLens
# Derived methods
@docs compose, modify, modify2, modify3, modifyAndMerge, zip, tuple, tuple3
# Conversion
@docs fromIso
-}
import Dict exposing (Dict)
import Monocle.Iso exposing (Iso)
{-| In order to create Lens we need to supply 2 functions: set and get
-}
type alias Lens a b =
{ get : a -> b
, set : b -> a -> a
}
{-| Composes `Lens a b` with `Lens b c` and returns `Lens a c`
-}
compose : Lens a b -> Lens b c -> Lens a c
compose outer inner =
let
set c a =
outer.get a |> inner.set c |> (\b -> outer.set b a)
in
Lens (outer.get >> inner.get) set
{-| Modifies given function `(b -> b)` to be `(a -> a)` using `Lens a b`
addressStreetNameLens = Lens Address String
fx streetName = String.reverse streetName
fx2 = Lens.modify addressStreetNameLens fx
fx2 {streetName="abcdef"} == {streetName="fedcba"}
-}
modify : Lens a b -> (b -> b) -> a -> a
modify lens f =
let
mf a =
lens.get a |> f |> (\b -> lens.set b a)
in
mf
{-| Modifies given function `(b,d) -> (b,d)` to be `(a,c) -> (a,c)` using `Lens a b` and `Lens c d`
-}
modify2 : Lens a b -> Lens c d -> (( b, d ) -> ( b, d )) -> ( a, c ) -> ( a, c )
modify2 lens1 lens2 fx =
let
mf ( a, c ) =
( lens1.get a, lens2.get c ) |> fx |> (\( b, d ) -> ( lens1.set b a, lens2.set d c ))
in
mf
{-| Modifies given function `(b,d,f) -> (b,d,f)` to be `(a,c,e) -> (a,c,e)` using `Lens a b` and `Lens c d` and `Lens e f`
-}
modify3 : Lens a b -> Lens c d -> Lens e f -> (( b, d, f ) -> ( b, d, f )) -> ( a, c, e ) -> ( a, c, e )
modify3 lens1 lens2 lens3 fx =
let
mf ( a, c, e ) =
( lens1.get a, lens2.get c, lens3.get e ) |> fx |> (\( b, d, f ) -> ( lens1.set b a, lens2.set d c, lens3.set f e ))
in
mf
{-| Casts `Iso a b` to `Lens a b`
-}
fromIso : Iso a b -> Lens a b
fromIso iso =
let
set b _ =
iso.reverseGet b
in
Lens iso.get set
{-| Zips `Lens a c` with `Lens b d` to form Lens ( a, b ) ( c, d )
-}
zip : Lens a c -> Lens b d -> Lens ( a, b ) ( c, d )
zip left right =
let
get ( a, b ) =
( left.get a, right.get b )
set ( c, d ) ( a, b ) =
( left.set c a, right.set d b )
in
Lens get set
{-| Modifies given function `(b -> (b,c))` to be `(a,c) -> (a,c)` using `Lens a b` and `merge` function
-}
modifyAndMerge : Lens a b -> (b -> ( b, c )) -> (c -> c -> c) -> ( a, c ) -> ( a, c )
modifyAndMerge lens fx merge =
let
mf ( a, c ) =
lens.get a
|> fx
|> (\( b, c1 ) -> ( lens.set b a, merge c c1 ))
in
mf
{-| Tuple `Lens a b` with `Lens a c` and returns `Lens a (b,c)`
-}
tuple : Lens a b -> Lens a c -> Lens a ( b, c )
tuple left right =
let
get a =
( left.get a, right.get a )
set ( b, c ) a =
right.set c (left.set b a)
in
Lens get set
{-| Tuple `Lens a b` with `Lens a c` with `Lens a d` and returns `Lens a (b,c,d)`
-}
tuple3 : Lens a b -> Lens a c -> Lens a d -> Lens a ( b, c, d )
tuple3 first second third =
let
get a =
( first.get a, second.get a, third.get a )
set ( b, c, d ) a =
third.set d (second.set c (first.set b a))
in
Lens get set
================================================
FILE: src/Monocle/Optional.elm
================================================
module Monocle.Optional exposing
( Optional
, compose, composeLens, modifyOption, modify, modify2, modify3, zip, tuple, tuple3
, fromPrism, fromLens
)
{-| A Optional is a weaker Lens and a weaker Prism
# Definition
@docs Optional
# Derived methods
@docs compose, composeLens, modifyOption, modify, modify2, modify3, zip, tuple, tuple3
# Conversion
@docs fromPrism, fromLens
# Example
addressRegionOptional : Optional Address String
addressRegionOptional =
let
getOption a =
a.region
set r a =
{ a | region = Just r }
in
Optional getOption set
-}
import Monocle.Lens exposing (Lens)
import Monocle.Prism exposing (Prism)
flip : (a -> b -> c) -> b -> a -> c
flip f b a =
f a b
{-| In order to create Optional we need to supply 2 functions: set and getOption
-}
type alias Optional a b =
{ getOption : a -> Maybe b
, set : b -> a -> a
}
{-| Composes `Optional a b` with `Optional b c` and returns `Optional a c`
string2IntPrism : Prism String Int
string2IntPrism =
Prism String.toInt String.fromInt
addressRegionIntOptional : Optional Address Int
addressRegionIntOptional =
compose addressRegionOptional (fromPrism string2IntPrism)
-}
compose : Optional a b -> Optional b c -> Optional a c
compose outer inner =
let
set c a =
outer.getOption a
|> Maybe.map (inner.set c >> flip outer.set a)
|> Maybe.withDefault a
getOption a =
case outer.getOption a of
Just x ->
x |> inner.getOption
Nothing ->
Nothing
in
Optional getOption set
{-| Composes `Optional a b` with `Lens b c` and returns `Optional a c`
string2CharListIso : Iso String (List Char)
string2CharListIso =
Iso String.toList String.fromList
addressRegionListCharOptional : Optional Address (List Char)
addressRegionListCharOptional =
composeLens addressRegionOptional (fromIso string2CharListIso)
-}
composeLens : Optional a b -> Lens b c -> Optional a c
composeLens opt lens =
let
set c a =
opt.getOption a
|> Maybe.map (lens.set c >> flip opt.set a)
|> Maybe.withDefault a
getOption a =
case opt.getOption a of
Just b ->
b |> lens.get |> Just
Nothing ->
Nothing
in
Optional getOption set
{-| Modifies given function `(b -> b)` to be `(a -> Maybe a)` using `Optional a b`
modifyRegion: String -> String
modifyRegion region = String.reverse region
modifyAddressRegion: Address -> Maybe Address
modifyAddressRegion address = Optional.modifyOption addressRegionOptional modifyRegion address
-}
modifyOption : Optional a b -> (b -> b) -> a -> Maybe a
modifyOption opt fx =
let
mf a =
opt.getOption a |> Maybe.map (fx >> flip opt.set a)
in
mf
{-| Modifies given function `(b -> b)` to be `(a -> a)` using `Optional a b`
modifyRegion: String -> String
modifyRegion region = String.reverse region
modifyAddressRegion: Address -> Address
modifyAddressRegion address = Optional.modify addressRegionOptional modifyRegion address
-}
modify : Optional a b -> (b -> b) -> a -> a
modify opt fx =
let
mf a =
modifyOption opt fx a |> Maybe.withDefault a
in
mf
{-| Modifies given function `(b,d) -> (b,d)` to be `(a,c) -> (a,c)` using `Optional a b` and `Optional c d`
Function will be invoked ONLY when for ALL arguments `a` and `c` method `Optional.getOption` returns some value.
-}
modify2 : Optional a b -> Optional c d -> (( b, d ) -> ( b, d )) -> ( a, c ) -> ( a, c )
modify2 opt1 opt2 fx =
let
mf ( a, c ) =
case ( opt1.getOption a, opt2.getOption c ) of
( Just b, Just d ) ->
( b, d ) |> fx |> (\( b1, d1 ) -> ( opt1.set b1 a, opt2.set d1 c ))
_ ->
( a, c )
in
mf
{-| Modifies given function `( b, d, f ) -> ( b, d, f )` to be `( a, c, e ) -> ( a, c, e )` using `Optional a b` and `Optional c d` and `Optional e f`
Function will be invoked ONLY when for ALL arguments `a`,`c`,`f` method `Optional.getOption` returns some value.
-}
modify3 : Optional a b -> Optional c d -> Optional e f -> (( b, d, f ) -> ( b, d, f )) -> ( a, c, e ) -> ( a, c, e )
modify3 opt1 opt2 opt3 fx =
let
mf ( a, c, e ) =
case ( opt1.getOption a, opt2.getOption c, opt3.getOption e ) of
( Just b, Just d, Just f ) ->
( b, d, f ) |> fx |> (\( b1, d1, f1 ) -> ( opt1.set b1 a, opt2.set d1 c, opt3.set f1 e ))
_ ->
( a, c, e )
in
mf
{-| Casts `Prism a b` to `Optional a b`
string2IntPrism : Prism String Int
string2IntPrism =
Prism String.toInt String.fromInt
stringIntOptional : Optional String Int
stringIntOptional =
fromPrism string2IntPrism
-}
fromPrism : Prism a b -> Optional a b
fromPrism prism =
let
set b _ =
prism.reverseGet b
in
Optional prism.getOption set
{-| Casts `Lens a b` to `Optional a b` where `getOption` will return always `Just`
-}
fromLens : Lens a b -> Optional a b
fromLens lens =
let
getOption a =
Just (lens.get a)
in
Optional getOption lens.set
{-| Zip `Optional a c` with `Optional b d` to form Optional for the pairs ( a, b ) ( c, d )
-}
zip : Optional a c -> Optional b d -> Optional ( a, b ) ( c, d )
zip left right =
let
getOption ( a, b ) =
left.getOption a
|> Maybe.andThen
(\c ->
right.getOption b
|> Maybe.map (\d -> ( c, d ))
)
set ( c, d ) ( a, b ) =
( left.set c a, right.set d b )
in
Optional getOption set
{-| Tuple `Optional a b` with `Optional a c` and returns `Optional a (b,c)`
Method `Optional.getOption` returns pair of values only when both given optionals return some value.
-}
tuple : Optional a b -> Optional a c -> Optional a ( b, c )
tuple left right =
let
getOption a =
case ( left.getOption a, right.getOption a ) of
( Just b, Just d ) ->
Just ( b, d )
_ ->
Nothing
set ( b, c ) a =
right.set c (left.set b a)
in
Optional getOption set
{-| Tuple `Optional a b` with `Optional a c` with `Optional a d` and returns `Optional a (b,c,d)`
Method `Optional.getOption` returns triple of values only when all given optionals return some value.
-}
tuple3 : Optional a b -> Optional a c -> Optional a d -> Optional a ( b, c, d )
tuple3 first second third =
let
getOption a =
case ( first.getOption a, second.getOption a, third.getOption a ) of
( Just b, Just d, Just f ) ->
Just ( b, d, f )
_ ->
Nothing
set ( b, c, d ) a =
first.set b a |> second.set c |> third.set d
in
Optional getOption set
================================================
FILE: src/Monocle/Prism.elm
================================================
module Monocle.Prism exposing
( Prism
, isMatching, modify, modifyOption, compose, composeIso
, fromIso
)
{-| A Prism is a tool which optionally converts elements of type A into elements of type B and back.
# Definition
@docs Prism
# Example
string2IntPrism : Prism String Int
string2IntPrism =
Prism String.toInt String.fromInt
string2IntPrism.getOption "17896" == Just 17896
string2IntPrism.getOption "1a896" == Nothing
string2IntPrism.reverseGet 1626767 = "1626767"
# Derived methods
@docs isMatching, modify, modifyOption, compose, composeIso
# Conversion
@docs fromIso
-}
import Maybe
import Monocle.Iso exposing (Iso)
{-| In order to create a `Prism` we need to supply two functions: `getOption` and `reverseGet`
-}
type alias Prism a b =
{ getOption : a -> Maybe b
, reverseGet : b -> a
}
{-| Checks if value of type `A` has matching element of type 'B'
Monocle.Prism.isMatching string2IntPrism "abc" == False
Monocle.Prism.isMatching string2IntPrism "123" == True
-}
isMatching : Prism a b -> a -> Bool
isMatching prism a =
case prism.getOption a of
Just c ->
True
Nothing ->
False
{-| Modifies given function `(b -> b)` to be `(a -> Maybe a)` using `Prism a b`
fx i = i * 2
modified = Monocle.Prism.modify string2IntPrism fx
modified "22" == Just "44"
modified "abc" == Nothing
-}
modifyOption : Prism a b -> (b -> b) -> a -> Maybe a
modifyOption prism f =
prism.getOption >> Maybe.map (f >> prism.reverseGet)
{-| Modifies given function `(b -> b)` to be `(a -> a)` using `Prism a b`
fx i = i * 2
modified = Monocle.Prism.modify string2IntPrism fx
modified "22" == "44"
modified "abc" == "abc"
-}
modify : Prism a b -> (b -> b) -> a -> a
modify prism f =
let
m x =
modifyOption prism f x |> Maybe.withDefault x
in
m
{-| Composes `Prism a b` with `Prism b c` and returns `Prism a c`
prism = Monocle.Prism.compose string2FloatPrism float2IntPrism
prism.getOption "22" == Just 22
prism.getOption "22.2" == Nothing
prism.getOption "22a" == Nothing
prism.getOption "abc" == Nothing
-}
compose : Prism a b -> Prism b c -> Prism a c
compose outer inner =
let
getOption x =
case outer.getOption x of
Just y ->
y |> inner.getOption
Nothing ->
Nothing
in
Prism getOption (inner.reverseGet >> outer.reverseGet)
{-| Composes `Prism a b` with `Iso b c` and returns `Prism a c`
iso = Iso ((*) 10) ((//) 10)
prism = Monocle.Prism.composeIso string2IntPrism iso
prism.getOption "22" == Just 220
prism.getOption "22.2" == Nothing
prism.getOption "22a" == Nothing
prism.getOption "abc" == Nothing
-}
composeIso : Prism a b -> Iso b c -> Prism a c
composeIso outer inner =
let
getOption x =
case outer.getOption x of
Just y ->
y |> inner.get |> Just
Nothing ->
Nothing
in
Prism getOption (inner.reverseGet >> outer.reverseGet)
{-| Casts `Iso a b` to `Prism a b`
-}
fromIso : Iso a b -> Prism a b
fromIso iso =
Prism (iso.get >> Just) iso.reverseGet
================================================
FILE: src/Monocle/Traversal.elm
================================================
module Monocle.Traversal exposing
( Traversal
, list, array, some, modify
)
{-| A Traversal is like an Optional that may modify multiple sub-elements, keeping the overlaying structure as is.
# Definition
@docs Traversal
# Example
personsAge : Lens Person Int
personsAge =
let
get a =
a.age
set b a =
{ a | age = b }
in
Lens get set
jeffs : Traversal (List Person) Person
jeffs =
Traversal.some Traversal.list (\p -> p.name == "Jeff")
jeffsAges : Traversal (List Person) Int
jeffsAges =
jeffs
|> Compose.traversalWithLens personsAge
# Derived methods
@docs list, array, some, modify
-}
import Array exposing (Array)
{-| To create a Traversal, you just need to provide a function
that applies a transformation function to some or all elements
in the parent structure.
-}
type alias Traversal a b =
(b -> b) -> a -> a
{-| A basic traversal that affects all elements in a list
-}
list : Traversal (List a) a
list =
List.map
{-| A basic traversal that affects all elements in an array
-}
array : Traversal (Array a) a
array =
Array.map
{-| A traversal that, given another traversal as base, only affects
those traversed elements that satisfy a condition.
numbers : Traversal (List number) number
numbers =
Traversal.list
oddNumbers : Traversal (List number) number
oddNumbers =
Traversal.some numbers (\number -> remainderBy 2 number == 1)
evenNumbers : Traversal (List number) number
evenNumbers =
Traversal.some numbers (\number -> remainderBy 2 number == 0)
-}
some : Traversal a b -> (b -> Bool) -> Traversal a b
some traversal condition transformation =
let
conditionedTransformation value =
if condition value then
transformation value
else
value
in
traversal conditionedTransformation
{-| Modifies all elements traversed by `Traversal a b` using function
`(b -> b)` in structure `a`
personsHairColor : Lens Person String
personsHairColor =
Lens .hairColor (\b a-> { a | hairColor = b })
pauls : Traversal (List Person) Person
pauls =
Traversal.some Traversal.list (\person -> person.firstName == 'Paul' )
paulsHairColor : Traversal (List Person) String
paulsHairColor =
pauls
|> Compose.traversalWithLens personsHairColor
lighten : String -> String
lighten hairColor =
"light " ++ hairColor
lightenPauls : List Person -> List Person
lightenPauls =
Traversal.modify pauls
lightenPauls [
{ firstName = "Paul"
, hairColor = "brown"
},
{ firstName = "Jake"
, hairColor = "blond"
}
] == [
{ firstName = "Paul"
, hairColor = "light brown"
},
{ firstName = "Jake"
, hairColor = "blond"
}
]
-}
modify : Traversal a b -> (b -> b) -> a -> a
modify traversal =
traversal
================================================
FILE: tests/.gitignore
================================================
/elm-stuff/
================================================
FILE: tests/CommonSpec.elm
================================================
module CommonSpec exposing (..)
import Test exposing (..)
import Expect
import Fuzz exposing (int, tuple, string, char)
import Dict
import Maybe
import Array
import Monocle.Common exposing (dict, maybe, array, list, listToArray, id)
all : Test
all =
describe "A Common specification"
[ test_maybe
, test_array_just
, test_array_nothing
, test_list_just
, test_list_nothing
, test_list_to_array_get
, test_list_to_array_reverse_get
, test_dict_empty
, test_dict_list
]
test_maybe : Test
test_maybe =
let
test s =
maybe.set s Nothing |> Expect.equal (Just s)
in
fuzz string "Common.maybe should step into Maybe" test
test_array_just : Test
test_array_just =
let
test i =
.getOption (array 2) (Array.fromList [ 10, 11, i, 13 ]) |> Expect.equal (Just i)
in
fuzz int "Common.array should get some value at position 2" test
test_array_nothing : Test
test_array_nothing =
let
test i =
.getOption (array 8) (Array.fromList [ i, i, i, i, i, i, i, i ]) |> Expect.equal Nothing
in
fuzz int "Common.array should return nothing if index out of bound" test
test_list_just : Test
test_list_just =
let
test i =
.getOption (list 2) [ 10, 11, i, 13 ] |> Expect.equal (Just i)
in
fuzz int "Common.list should get some value at position 2" test
test_list_nothing : Test
test_list_nothing =
let
test i =
.getOption (list 8) [ i, i, i, i, i, i, i, i ] |> Expect.equal Nothing
in
fuzz int "Common.list should return nothing if index out of bound" test
test_list_to_array_get : Test
test_list_to_array_get =
let
test l =
.get listToArray l |> Expect.equal (l |> Array.fromList)
in
fuzz (Fuzz.list int) "Common.listToArray.get should convert a list to an array" test
test_list_to_array_reverse_get : Test
test_list_to_array_reverse_get =
let
test a =
.reverseGet listToArray a |> Expect.equal (Array.toList a)
in
fuzz (Fuzz.array int) "Common.listToArray.reverseGet should convert an array to a list" test
test_dict_empty : Test
test_dict_empty =
let
opt =
dict "mykey"
test s =
opt.getOption (opt.set s Dict.empty) |> Expect.equal (Just s)
in
fuzz string "Common.dict should set and get value by key (empty dict)" test
test_dict_list : Test
test_dict_list =
let
opt =
(dict "Tom")
test s =
.getOption opt (Dict.fromList [ ( "Tom", s ), ( "Alice", "Rabbit" ) ]) |> Expect.equal (Just s)
in
fuzz string "Common.dict should set and get value by key (preloaded dict)" test
================================================
FILE: tests/ComposeSpec.elm
================================================
module ComposeSpec exposing (..)
import Array
import Expect
import Fuzz exposing (constant, float, int, intRange, list, maybe, oneOf, string, tuple, tuple3)
import Monocle.Compose as Compose
import Monocle.Iso exposing (Iso)
import Monocle.Lens exposing (Lens)
import Monocle.Optional exposing (Optional)
import Monocle.Prism exposing (Prism)
import Monocle.Traversal as Traversal
import Test exposing (..)
all : Test
all =
describe "Monocle.Compose"
[ test_isoWithIso
, test_isoWithLens
, test_isoWithOptional
, test_isoWithPrism
, test_isoWithTraversal
, test_lensWithIso
, test_lensWithLens
, test_lensWithOptional
, test_lensWithPrism
, test_lensWithTraversal
, test_prismWithIso
, test_prismWithLens
, test_prismWithOptional
, test_prismWithPrism
, test_prismWithTraversal
, test_optionalWithIso
, test_optionalWithLens
, test_optionalWithOptional
, test_optionalWithPrism
, test_optionalWithTraversal
, test_traversalWithIso
, test_traversalWithLens
, test_traversalWithOptional
, test_traversalWithPrism
, test_traversalWithTraversal
]
test_isoWithIso : Test
test_isoWithIso =
let
isoString2CharList =
Iso String.toList String.fromList
isoCharList2CharArray =
Iso Array.fromList Array.toList
isoComposedString2CharArray =
isoString2CharList
|> Compose.isoWithIso isoCharList2CharArray
string2CharArray =
String.toList >> Array.fromList
test_get s =
s
|> .get isoComposedString2CharArray
|> Expect.equal (s |> string2CharArray)
test_reverseGet s =
(s |> string2CharArray)
|> .reverseGet isoComposedString2CharArray
|> Expect.equal s
in
describe "Compose.isoWithIso"
[ test_get |> fuzz string ".get"
, test_reverseGet |> fuzz string ".reverseGet"
]
type Admin name
= Admin name
type User name
= User name
test_isoWithLens : Test
test_isoWithLens =
let
isoUser2Admin =
Iso (\(User name) -> Admin name) (\(Admin name) -> User name)
lensAdminName =
Lens (\(Admin name) -> name) (\name admin -> Admin name)
lensComposedUser2AdminName =
isoUser2Admin
|> Compose.isoWithLens lensAdminName
test_get name =
User name
|> .get lensComposedUser2AdminName
|> Expect.equal name
test_set ( oldName, newName ) =
User oldName
|> .set lensComposedUser2AdminName newName
|> Expect.equal (User newName)
in
describe "Compose.isoWithLens"
[ test_get |> fuzz string ".get"
, test_set |> fuzz (tuple ( string, string )) ".set"
]
test_isoWithOptional : Test
test_isoWithOptional =
let
isoUser2Admin =
Iso (\(User name) -> Admin name) (\(Admin name) -> User name)
optionalAdminName =
Optional (\(Admin name) -> name) (\name admin -> Admin (Just name))
optionalComposedUser2AdminName =
isoUser2Admin
|> Compose.isoWithOptional optionalAdminName
test_getOption name =
User (Just name)
|> .getOption optionalComposedUser2AdminName
|> Expect.equal (Just name)
test_set ( oldName, newName ) =
User (Just oldName)
|> .set optionalComposedUser2AdminName newName
|> Expect.equal (User (Just newName))
in
describe "Compose.isoWithOptional"
[ test_getOption |> fuzz string ".getOption"
, test_set |> fuzz (tuple ( string, string )) ".set"
]
test_isoWithPrism : Test
test_isoWithPrism =
let
isoCharList2String =
Iso String.fromList String.toList
prismString2Int =
Prism String.toInt String.fromInt
int2CharList =
String.fromInt >> String.toList
prismComposedCharList2Int =
isoCharList2String
|> Compose.isoWithPrism prismString2Int
test_getOption int =
(int |> int2CharList)
|> .getOption prismComposedCharList2Int
|> Expect.equal (Just int)
test_reverseGet int =
int
|> .reverseGet prismComposedCharList2Int
|> Expect.equal (int |> int2CharList)
in
describe "Compose.isoWithPrism"
[ test_getOption |> fuzz int ".getOption"
, test_reverseGet |> fuzz int ".reverseGet"
]
test_isoWithTraversal : Test
test_isoWithTraversal =
let
isoString2CharList =
Iso String.toList String.fromList
traversalStringChars =
isoString2CharList
|> Compose.isoWithTraversal Traversal.list
shift =
Char.toCode >> (+) 1 >> Char.fromCode
test_modify string =
let
modified =
string
|> Traversal.modify traversalStringChars shift
expected =
string
|> String.toList
|> List.map shift
|> String.fromList
in
Expect.equal modified expected
in
describe "Compose.isoWithTraversal"
[ test_modify |> fuzz string "modify"
]
test_lensWithIso : Test
test_lensWithIso =
let
lensUser2Name =
Lens .name (\name user -> { user | name = name })
isoReverse =
Iso String.reverse String.reverse
lensUser2NameReverse =
lensUser2Name
|> Compose.lensWithIso isoReverse
test_get name =
{ name = name }
|> .get lensUser2NameReverse
|> Expect.equal (name |> String.reverse)
test_set ( oldName, newName ) =
{ name = oldName }
|> .set lensUser2NameReverse newName
|> Expect.equal { name = newName |> String.reverse }
in
describe "Compose.lensWithIso"
[ test_get |> fuzz string ".get"
, test_set |> fuzz (tuple ( string, string )) ".set"
]
test_lensWithLens : Test
test_lensWithLens =
let
lensPerson2StreetAddress =
Lens .streetAddress (\streetAddress person -> { person | streetAddress = streetAddress })
lensStreetAddress2City =
Lens .city (\city streetAddress -> { streetAddress | city = city })
lensPerson2StreetAddressCity =
lensPerson2StreetAddress
|> Compose.lensWithLens lensStreetAddress2City
personify ( name, street, city ) =
{ name = name
, streetAddress =
{ street = street
, city = city
}
}
test_get ( name, street, city ) =
personify ( name, street, city )
|> .get lensPerson2StreetAddressCity
|> Expect.equal city
test_set ( ( name, street, city ), newCity ) =
personify ( name, street, city )
|> .set lensPerson2StreetAddressCity newCity
|> Expect.equal (personify ( name, street, newCity ))
in
describe "Compose.lensWithLens"
[ test_get |> fuzz (tuple3 ( string, string, string )) ".get"
, test_set |> fuzz (tuple ( tuple3 ( string, string, string ), string )) ".set"
]
test_lensWithOptional : Test
test_lensWithOptional =
let
lensDriver2Vehicle =
Lens .vehicle (\vehicle driver -> { driver | vehicle = vehicle })
optionalVehicle2LicenseNumber =
Optional .licenseNumber (\licenseNumber vehicle -> { vehicle | licenseNumber = Just licenseNumber })
optionalDriver2LicenseNumber =
lensDriver2Vehicle
|> Compose.lensWithOptional optionalVehicle2LicenseNumber
vehiclify ( name, serie, licenseNumber ) =
{ name = name
, vehicle =
{ serie = serie
, licenseNumber = Just licenseNumber
}
}
test_getOption ( name, serie, licenseNumber ) =
vehiclify ( name, serie, licenseNumber )
|> .getOption optionalDriver2LicenseNumber
|> Expect.equal (Just licenseNumber)
test_set ( ( name, serie, licenseNumber ), newLicenseNumber ) =
vehiclify ( name, serie, licenseNumber )
|> .set optionalDriver2LicenseNumber newLicenseNumber
|> Expect.equal (vehiclify ( name, serie, newLicenseNumber ))
in
describe "Compose.lensWithOptional"
[ test_getOption |> fuzz (tuple3 ( string, string, string )) ".getOption"
, test_set |> fuzz (tuple ( tuple3 ( string, string, string ), string )) ".set"
]
test_lensWithPrism : Test
test_lensWithPrism =
let
lensPerson2FirstName =
Lens .firstName (\firstName person -> { person | firstName = firstName })
prismName2Number =
Prism String.toInt String.fromInt
optionalPerson2Number =
lensPerson2FirstName
|> Compose.lensWithPrism prismName2Number
personify ( firstName, lastName ) =
{ firstName = firstName
, lastName = lastName
}
test_getOption ( firstName, lastName ) =
personify ( firstName |> String.fromInt, lastName )
|> .getOption optionalPerson2Number
|> Expect.equal (Just firstName)
test_set ( ( firstName, lastName ), newFirstName ) =
personify ( firstName, lastName )
|> .set optionalPerson2Number newFirstName
|> Expect.equal (personify ( newFirstName |> String.fromInt, lastName ))
in
describe "Compose.lensWithPrism"
[ test_getOption |> fuzz (tuple ( int, string )) ".getOption"
, test_set |> fuzz (tuple ( tuple ( string, string ), int )) ".set"
]
test_lensWithTraversal : Test
test_lensWithTraversal =
let
lensPerson2Friends =
Lens .friends (\friends person -> { person | friends = friends })
traversalPersonFriends =
lensPerson2Friends
|> Compose.lensWithTraversal Traversal.list
personify name friends =
{ name = name
, friends = friends
}
test_modify ( name, friends ) =
personify name friends
|> Traversal.modify traversalPersonFriends String.reverse
|> Expect.equal (personify name (List.map String.reverse friends))
in
describe "Compose.lensWithTraversal"
[ test_modify |> fuzz (tuple ( int, list string )) ".modify"
]
test_prismWithIso : Test
test_prismWithIso =
let
prismString2Int =
Prism String.toInt String.fromInt
isoPlusOne =
Iso (\n -> n + 1) (\n -> n - 1)
prismIntPlusOne =
prismString2Int
|> Compose.prismWithIso isoPlusOne
test_getOption quantity =
(quantity |> String.fromInt)
|> .getOption prismIntPlusOne
|> Expect.equal (Just (quantity + 1))
in
describe "Compose.prismWithIso"
[ test_getOption |> fuzz int ".getOption" ]
type alias Address =
{ city : String
, street : Maybe String
}
type alias Coordinates =
{ lng : Float
, lat : Float
}
type Location
= ByAddress Address
| ByCoordinates Coordinates
test_prismWithLens : Test
test_prismWithLens =
let
coordinates location =
case location of
ByCoordinates c ->
Just c
_ ->
Nothing
prismLocationToCoordinates =
Prism coordinates ByCoordinates
lensLng =
Lens .lng (\lng c -> { c | lng = lng })
optionalLocationLng =
prismLocationToCoordinates
|> Compose.prismWithLens lensLng
test_getOption ( lng, lat ) =
ByCoordinates { lng = lng, lat = lat }
|> .getOption optionalLocationLng
|> Expect.equal (Just lng)
test_set ( ( lng, lat ), newLng ) =
ByCoordinates { lng = lng, lat = lat }
|> .set optionalLocationLng newLng
|> Expect.equal (ByCoordinates { lng = newLng, lat = lat })
in
describe "Compose.prismWithLens"
[ test_getOption |> fuzz (tuple ( float, float )) ".getOption"
, test_set |> fuzz (tuple ( tuple ( float, float ), float )) ".set"
]
test_prismWithOptional : Test
test_prismWithOptional =
let
address location =
case location of
ByAddress a ->
Just a
_ ->
Nothing
prismLocationToAddress =
Prism address ByAddress
optionalStreet =
Optional .street (\street a -> { a | street = Just street })
optionalLocationStreet =
prismLocationToAddress
|> Compose.prismWithOptional optionalStreet
test_getOption ( street, city ) =
ByAddress { street = Just street, city = city }
|> .getOption optionalLocationStreet
|> Expect.equal (Just street)
test_set ( ( street, city ), newStreet ) =
ByAddress { street = Just street, city = city }
|> .set optionalLocationStreet newStreet
|> Expect.equal (ByAddress { street = Just newStreet, city = city })
in
describe "Compose.prismWithOptional"
[ test_getOption |> fuzz (tuple ( string, string )) ".getOption"
, test_set |> fuzz (tuple ( tuple ( string, string ), string )) ".set"
]
type Option
= OptionOne
| OptionTwo
| OptionThree
test_prismWithPrism : Test
test_prismWithPrism =
let
toOption n =
case n of
1 ->
Just OptionOne
2 ->
Just OptionTwo
3 ->
Just OptionThree
_ ->
Nothing
fromOption option =
case option of
OptionOne ->
1
OptionTwo ->
2
OptionThree ->
3
anyOption =
[ OptionOne
, OptionTwo
, OptionThree
]
|> List.map constant
prismString2Int =
Prism String.toInt String.fromInt
prismInt2Option =
Prism toOption fromOption
prismString2Option =
prismString2Int
|> Compose.prismWithPrism prismInt2Option
test_getOption n =
(n |> String.fromInt)
|> .getOption prismString2Option
|> Expect.equal (n |> toOption)
test_reverseGet option =
option
|> .reverseGet prismString2Option
|> Expect.equal (option |> fromOption |> String.fromInt)
in
describe "Compose.prismWithPrism"
[ test_getOption |> fuzz (intRange 1 3) ".getOption"
, test_reverseGet |> fuzz (oneOf anyOption) ".reverseGet"
]
type PseudoList a
= None
| One a
| Two a a
test_prismWithTraversal : Test
test_prismWithTraversal =
let
toShortList items =
case items of
[] ->
Just []
[ x ] ->
Just [ x ]
[ x, y ] ->
Just [ x, y ]
_ ->
Nothing
fromShortList items =
items
prismShortList =
Prism toShortList fromShortList
traverseShortList =
prismShortList
|> Compose.prismWithTraversal Traversal.list
test_modify_succeeds items =
items
|> Traversal.modify traverseShortList ((+) 1)
|> Expect.equal (items |> List.map ((+) 1))
test_modify_fails items =
items
|> Traversal.modify traverseShortList ((+) 1)
|> Expect.equal items
listOfUpToTwoInts =
Fuzz.map2
(\maybeX maybeY -> List.filterMap identity [ maybeX, maybeY ])
(maybe int)
(maybe int)
listOfThreeOrMoreInts =
Fuzz.map4
(\x y z more -> x :: y :: z :: more)
int
int
int
(list int)
in
describe "Compose.prismWithTraversal"
[ test_modify_succeeds |> fuzz listOfUpToTwoInts "modify succeeds"
, test_modify_fails |> fuzz listOfThreeOrMoreInts "modify fails"
]
test_optionalWithIso : Test
test_optionalWithIso =
let
optionalCity =
Optional .city (\city address -> { address | city = Just city })
isoReverse =
Iso String.reverse String.reverse
optionalCityReverse =
optionalCity
|> Compose.optionalWithIso isoReverse
test_getOption city =
{ city = Just city }
|> .getOption optionalCityReverse
|> Expect.equal (Just (city |> String.reverse))
test_set ( city, newCity ) =
{ city = Just city }
|> .set optionalCityReverse (newCity |> String.reverse)
|> Expect.equal { city = Just newCity }
in
describe "Compose.optionalWithIso"
[ test_getOption |> fuzz string ".getOption"
, test_set |> fuzz (tuple ( string, string )) ".set"
]
test_optionalWithLens : Test
test_optionalWithLens =
let
optionalAddress =
Optional .address (\address person -> { person | address = Just address })
lensStreet =
Lens .street (\street address -> { address | street = street })
optionalAddressStreet =
optionalAddress
|> Compose.optionalWithLens lensStreet
personify ( name, city, street ) =
{ name = name
, address =
Just
{ city = city
, street = street
}
}
test_getOption ( name, city, street ) =
personify ( name, city, street )
|> .getOption optionalAddressStreet
|> Expect.equal (Just street)
test_set ( ( name, city, street ), newStreet ) =
personify ( name, city, street )
|> .set optionalAddressStreet newStreet
|> Expect.equal (personify ( name, city, newStreet ))
in
describe "Compose.optionalWithLens"
[ test_getOption |> fuzz (tuple3 ( string, string, string )) ".getOption"
, test_set |> fuzz (tuple ( tuple3 ( string, string, string ), string )) ".set"
]
test_optionalWithOptional : Test
test_optionalWithOptional =
let
optionalAddress =
Optional .address (\address person -> { person | address = Just address })
optionalStreet =
Optional .street (\street address -> { address | street = Just street })
optionalAddressStreet =
optionalAddress
|> Compose.optionalWithOptional optionalStreet
personify ( name, city, street ) =
{ name = name
, address =
Just
{ city = city
, street = Just street
}
}
test_getOption ( name, city, street ) =
personify ( name, city, street )
|> .getOption optionalAddressStreet
|> Expect.equal (Just street)
test_set ( ( name, city, street ), newStreet ) =
personify ( name, city, street )
|> .set optionalAddressStreet newStreet
|> Expect.equal (personify ( name, city, newStreet ))
in
describe "Compose.optionalWithOptional"
[ test_getOption |> fuzz (tuple3 ( string, string, string )) ".getOption"
, test_set |> fuzz (tuple ( tuple3 ( string, string, string ), string )) ".set"
]
test_optionalWithPrism : Test
test_optionalWithPrism =
let
optionalZipCode =
Optional .zipcode (\zipcode address -> { address | zipcode = Just zipcode })
prismString2Int =
Prism String.toInt String.fromInt
optionalZipCodeString2Int =
optionalZipCode
|> Compose.optionalWithPrism prismString2Int
test_getOption zipcode =
{ zipcode = Just (zipcode |> String.fromInt) }
|> .getOption optionalZipCodeString2Int
|> Expect.equal (Just zipcode)
test_set ( zipcode, newZipCode ) =
{ zipcode = Just (zipcode |> String.fromInt) }
|> .set optionalZipCodeString2Int newZipCode
|> Expect.equal { zipcode = Just (newZipCode |> String.fromInt) }
in
describe "Compose.optionalWithPrism"
[ test_getOption |> fuzz int ".getOption"
, test_set |> fuzz (tuple ( int, int )) ".set"
]
test_optionalWithTraversal : Test
test_optionalWithTraversal =
let
optionalFriends =
Optional .friends (\friends person -> { person | friends = Just friends })
traversalFriends =
optionalFriends
|> Compose.optionalWithTraversal Traversal.list
test_modify_succeeds friends =
{ friends = Just friends }
|> Traversal.modify traversalFriends String.reverse
|> Expect.equal { friends = Just (List.map String.reverse friends) }
test_modify_fails _ =
{ friends = Nothing }
|> Traversal.modify traversalFriends String.reverse
|> Expect.equal { friends = Nothing }
in
describe "Compose.optionalWithTraversal"
[ test_modify_succeeds |> fuzz (list string) "modify succeeds"
, test_modify_fails |> test "modify fails"
]
test_traversalWithIso : Test
test_traversalWithIso =
let
isoString2Chars =
Iso String.toList String.fromList
traverseStringsChars =
Traversal.list
|> Compose.traversalWithIso isoString2Chars
test_modify_all words =
words
|> Traversal.modify traverseStringsChars List.reverse
|> Expect.equal (List.map String.reverse words)
in
describe "Compose.traversalWithIso"
[ test_modify_all |> fuzz (list string) "modify"
]
test_traversalWithLens : Test
test_traversalWithLens =
let
lensPersonFirstName =
Lens .firstName (\firstName person -> { person | firstName = firstName })
traversePeopleFirstNames =
Traversal.list
|> Compose.traversalWithLens lensPersonFirstName
test_modify_all people =
people
|> Traversal.modify traversePeopleFirstNames String.reverse
|> Expect.equal (List.map (\person -> { person | firstName = String.reverse person.firstName }) people)
randomPerson =
Fuzz.map2
(\firstName lastName -> { firstName = firstName, lastName = lastName })
string
string
in
describe "Compose.traversalWithLens"
[ test_modify_all |> fuzz (list randomPerson) "modify"
]
test_traversalWithOptional : Test
test_traversalWithOptional =
let
optionalPersonAddress =
Optional .address (\address person -> { person | address = Just address })
traversePeopleAddresses =
Traversal.list
|> Compose.traversalWithOptional optionalPersonAddress
test_modify_all people =
people
|> Traversal.modify traversePeopleAddresses String.reverse
|> Expect.equal (List.map (\person -> { person | address = Maybe.map String.reverse person.address }) people)
randomPerson =
Fuzz.map2
(\name address -> { name = name, address = address })
string
(maybe string)
in
describe "Compose.traversalWithOptional"
[ test_modify_all |> fuzz (list randomPerson) "modify"
]
test_traversalWithPrism : Test
test_traversalWithPrism =
let
prismString2Int =
Prism String.toInt String.fromInt
traverseStringInts =
Traversal.list
|> Compose.traversalWithPrism prismString2Int
test_modify_all ints =
ints
|> List.map String.fromInt
|> Traversal.modify traverseStringInts ((+) 1)
|> Expect.equal (List.map ((+) 1 >> String.fromInt) ints)
test_modify_some intValue =
[ "NaN", String.fromInt intValue ]
|> Traversal.modify traverseStringInts ((+) 1)
|> Expect.equal [ "NaN", String.fromInt (intValue + 1) ]
in
describe "Compose.traversalWithPrism"
[ test_modify_all |> fuzz (list int) "modify all"
, test_modify_some |> fuzz int "modify some"
]
test_traversalWithTraversal : Test
test_traversalWithTraversal =
let
traverseListOfList =
Traversal.list
|> Compose.traversalWithTraversal Traversal.list
test_modify_all listOfLists =
listOfLists
|> Traversal.modify traverseListOfList ((+) 1)
|> Expect.equal (List.map (List.map ((+) 1)) listOfLists)
in
describe "Compose.traversalWithTraversal"
[ test_modify_all |> fuzz (list (list int)) "modify"
]
================================================
FILE: tests/IsoSpec.elm
================================================
module IsoSpec exposing (..)
import Test exposing (..)
import Expect
import Fuzz exposing (list, int, tuple, string, char)
import String
import Monocle.Iso exposing (Iso)
all : Test
all =
describe "An Iso specification"
[ test_iso_function_get
, test_iso_function_reverse_get
, test_iso_property_identity
, test_iso_property_identity_reversed
, test_iso_method_reverse
, test_iso_method_modify
, test_iso_method_compose
]
string2CharListIso : Iso String (List Char)
string2CharListIso =
Iso String.toList String.fromList
charList2StringIso : Iso (List Char) String
charList2StringIso =
Iso String.fromList String.toList
test_iso_function_get : Test
test_iso_function_get =
let
iso =
string2CharListIso
test s =
s |> iso.get |> Expect.equal (String.toList s)
in
fuzz string "test get function" test
test_iso_function_reverse_get : Test
test_iso_function_reverse_get =
let
iso =
string2CharListIso
test s =
(String.toList s) |> iso.reverseGet |> Expect.equal s
in
fuzz string "test reverseGet function" test
test_iso_property_identity : Test
test_iso_property_identity =
let
iso =
string2CharListIso
test s =
s |> iso.get >> iso.reverseGet |> Expect.equal s
in
fuzz string "test identity property: reverseGet(get(x)) == x" test
test_iso_property_identity_reversed : Test
test_iso_property_identity_reversed =
let
iso =
charList2StringIso
test s =
s |> iso.reverseGet >> iso.get |> Expect.equal s
in
fuzz string "test identity property reversed: get(reverseGet(x)) == x" test
test_iso_method_reverse : Test
test_iso_method_reverse =
let
iso =
string2CharListIso
isor =
Monocle.Iso.reverse iso
test s =
Expect.equal (iso.get s) (isor.reverseGet s)
in
fuzz string "test reverse method" test
test_iso_method_modify : Test
test_iso_method_modify =
let
iso =
string2CharListIso
test s ch =
let
fx xs =
ch :: xs
modified =
Monocle.Iso.modify iso fx
in
modified s |> Expect.equal (String.cons ch s)
in
fuzz2 string char "test modify method" test
test_iso_method_compose : Test
test_iso_method_compose =
let
iso =
Monocle.Iso.compose string2CharListIso charList2StringIso
test s =
s |> iso.get |> Expect.equal s
in
fuzz string "test compose method" test
================================================
FILE: tests/LensSpec.elm
================================================
module LensSpec exposing (..)
import Test exposing (..)
import Expect
import Fuzz exposing (Fuzzer, list, int, string, char)
import String
import Monocle.Iso exposing (Iso)
import Monocle.Prism exposing (Prism)
import Monocle.Lens exposing (Lens, compose, modify, modify2, modify3, zip, modifyAndMerge, tuple, tuple3)
import Maybe exposing (Maybe)
all : Test
all =
describe
"A Lens specification"
[ test_lens_property_identity
, test_lens_property_identity_reverse
, test_lens_method_compose
, test_lens_method_modify
, test_lens_method_modify2
, test_lens_method_modify3
, test_lens_method_zip
, test_lens_method_modifyAndMerge
, test_lens_method_tuple
, test_lens_method_tuple3
]
type StreetType
= Street
| Avenue
type Country
= US
| UK
| FI
| PL
| DE
type alias Address =
{ streetName : String
, streetType : StreetType
, floor : Maybe Int
, town : String
, region : Maybe String
, postcode : String
, country : Country
}
type alias Place =
{ name : String
, description : String
, address : Address
}
addressStreetNameLens : Lens Address String
addressStreetNameLens =
let
get a =
a.streetName
set sn a =
{ a | streetName = sn }
in
Lens get set
addressPostcodeLens : Lens Address String
addressPostcodeLens =
let
get a =
a.postcode
set p a =
{ a | postcode = p }
in
Lens get set
addressTownLens : Lens Address String
addressTownLens =
let
get a =
a.town
set t a =
{ a | town = t }
in
Lens get set
placeAddressLens : Lens Place Address
placeAddressLens =
let
get p =
p.address
set a p =
{ p | address = a }
in
Lens get set
addresses : Fuzzer Address
addresses =
let
address name town postcode =
{ streetName = name, streetType = Street, floor = Nothing, town = town, region = Nothing, postcode = postcode, country = US }
in
Fuzz.map3 address string string string
places : Fuzzer Place
places =
Fuzz.map3 Place string string addresses
test_lens_property_identity : Test
test_lens_property_identity =
let
lens =
addressStreetNameLens
test address =
lens.set (lens.get address) address |> Expect.equal address
in
fuzz addresses "For all a: A, (set (get a) a) == a" test
test_lens_property_identity_reverse : Test
test_lens_property_identity_reverse =
let
lens =
addressStreetNameLens
test ( street, address ) =
lens.get (lens.set street address) |> Expect.equal street
in
fuzz (Fuzz.tuple ( string, addresses )) "For all a: A, get (set a a) == a" test
test_lens_method_compose : Test
test_lens_method_compose =
let
lens =
compose placeAddressLens addressStreetNameLens
test ( street, place ) =
lens.get (lens.set street place) |> Expect.equal street
in
fuzz (Fuzz.tuple ( string, places )) "Lens compose method" test
test_lens_method_modify : Test
test_lens_method_modify =
let
fx street =
String.reverse street
lens =
compose placeAddressLens addressStreetNameLens
expected place =
lens.set (String.reverse (lens.get place)) place
test place =
place |> (modify lens fx) |> Expect.equal (expected place)
in
fuzz places "Lens modify method" test
test_lens_method_modify2 : Test
test_lens_method_modify2 =
let
fx ( street, postcode ) =
( String.reverse street, String.append "_" postcode )
lens1 =
compose placeAddressLens addressStreetNameLens
lens2 =
addressPostcodeLens
lens3 =
addressPostcodeLens
expected ( place, address ) =
( place |> lens1.set (String.reverse (lens1.get place))
, address |> lens2.set (String.append "_" (lens2.get address))
)
test x =
x |> (modify2 lens1 lens2 fx) |> Expect.equal (expected x)
in
fuzz (Fuzz.tuple ( places, addresses )) "Lens modify2 method" test
test_lens_method_modify3 : Test
test_lens_method_modify3 =
let
fx ( street1, street2, street3 ) =
( street3, street1, street2 )
lens =
compose placeAddressLens addressStreetNameLens
expected ( place1, place2, place3 ) =
( place1 |> lens.set (lens.get place3)
, place2 |> lens.set (lens.get place1)
, place3 |> lens.set (lens.get place2)
)
test x =
x |> (modify3 lens lens lens fx) |> Expect.equal (expected x)
in
fuzz (Fuzz.tuple3 ( places, places, places )) "Lens modify3 method" test
test_lens_method_zip : Test
test_lens_method_zip =
let
address =
Address "test" Street Nothing "test" Nothing "test" US
place =
Place "test" "test" address
lens =
zip placeAddressLens addressStreetNameLens
test x =
lens.get (lens.set x ( place, address )) |> Expect.equal x
in
fuzz (Fuzz.tuple ( addresses, string )) "Lens zip method" test
test_lens_method_modifyAndMerge : Test
test_lens_method_modifyAndMerge =
let
lens =
compose placeAddressLens addressStreetNameLens
fx a =
( String.reverse a, String.length a )
merge a b =
a + b
modifiedFx =
modifyAndMerge lens fx merge
expected ( place, n ) =
( (lens.set (String.reverse (lens.get place)) place), n + (String.length (lens.get place)) )
test p =
modifiedFx p |> Expect.equal (expected p)
in
fuzz (Fuzz.tuple ( places, int )) "Lens modifyAndMerge method" test
test_lens_method_tuple : Test
test_lens_method_tuple =
let
lens =
tuple addressStreetNameLens addressPostcodeLens
test ( address, street, postcode ) =
lens.get (lens.set ( street, postcode ) address) |> Expect.equal ( street, postcode )
in
fuzz (Fuzz.tuple3 ( addresses, string, string )) "Lens tuple method" test
test_lens_method_tuple3 : Test
test_lens_method_tuple3 =
let
lens =
tuple3 addressStreetNameLens addressPostcodeLens addressTownLens
test ( address, ( street, postcode, town ) ) =
lens.get (lens.set ( street, postcode, town ) address) |> Expect.equal ( street, postcode, town )
in
fuzz (Fuzz.tuple ( addresses, Fuzz.tuple3 ( string, string, string ) )) "Lens tuple3 method" test
================================================
FILE: tests/OptionalSpec.elm
================================================
module OptionalSpec exposing (..)
import Test exposing (..)
import Expect
import Fuzz exposing (Fuzzer, list, int, tuple, string, char)
import String
import Monocle.Iso exposing (Iso)
import Monocle.Prism exposing (Prism)
import Monocle.Lens exposing (Lens, fromIso)
import Monocle.Optional exposing (Optional, fromPrism, fromLens, compose, composeLens, modifyOption, modify, zip)
import Maybe exposing (Maybe)
all : Test
all =
describe
"An Optional specification"
[ test_optional_property_identity_when_just
, test_optional_property_identity_when_nothing
, test_optional_property_reverse_identity
, test_optional_method_fromPrism_getOption
, test_optional_method_fromPrism_set
, test_optional_method_compose
, test_optional_method_composeLens
, test_lens_method_modifyOption_just
, test_lens_method_modify_just
, test_lens_method_modifyOption_nothing
, test_optional_method_zip
, test_optional_method_fromLens
]
type StreetType
= Street
| Avenue
type Country
= US
| UK
| FI
| PL
| DE
type alias Address =
{ streetName : String
, streetType : StreetType
, floor : Maybe Int
, town : String
, region : Maybe String
, postcode : String
, country : Country
}
type alias Place =
{ name : String
, description : String
, address : Maybe Address
}
addressRegionOptional : Optional Address String
addressRegionOptional =
let
getOption a =
a.region
set r a =
{ a | region = Just r }
in
Optional getOption set
addressStreetNameLens : Lens Address String
addressStreetNameLens =
let
get a =
a.streetName
set sn a =
{ a | streetName = sn }
in
Lens get set
placeAddressOptional : Optional Place Address
placeAddressOptional =
let
getOption p =
p.address
set a p =
{ p | address = Just a }
in
Optional getOption set
string2IntPrism : Prism String Int
string2IntPrism =
Prism String.toInt String.fromInt
string2CharListIso : Iso String (List Char)
string2CharListIso =
Iso String.toList String.fromList
addressesWithRegion : Fuzzer Address
addressesWithRegion =
let
address name town postcode region =
{ streetName = name, streetType = Street, floor = Nothing, town = town, region = Just region, postcode = postcode, country = US }
in
Fuzz.map4 address string string string string
addressesWithoutRegion : Fuzzer Address
addressesWithoutRegion =
let
address name town postcode =
{ streetName = name, streetType = Street, floor = Nothing, town = town, region = Nothing, postcode = postcode, country = US }
in
Fuzz.map3 address string string string
places : Fuzzer Place
places =
Fuzz.map3 Place string string (Fuzz.maybe addressesWithRegion)
numbers : Fuzzer String
numbers =
Fuzz.map String.fromInt int
test_optional_property_identity_when_just =
let
opt =
addressRegionOptional
test a =
opt.getOption a |> Maybe.map (\r -> opt.set r a) |> Expect.equal (Just a)
in
fuzz addressesWithRegion "For some a: A, getOption a |> Maybe.map (r -> set r a) == Just a" test
test_optional_property_identity_when_nothing =
let
opt =
addressRegionOptional
test a =
opt.getOption a |> Maybe.map (\r -> opt.set r a) |> Expect.equal Nothing
in
fuzz addressesWithoutRegion "For some a: A, getOption a |> Maybe.map (r -> set r a) == Nothing" test
test_optional_property_reverse_identity =
let
opt =
addressRegionOptional
test ( a, r ) =
opt.set r a |> opt.getOption |> Expect.equal (Just r)
in
fuzz (Fuzz.tuple ( addressesWithoutRegion, string )) "For all a: A, set a r |> getOption == Just a" test
test_optional_method_fromPrism_getOption =
let
opt =
fromPrism string2IntPrism
expected s =
Just (String.toInt s |> Maybe.withDefault 0)
test s =
opt.getOption s |> Expect.equal (expected s)
in
fuzz numbers "Optional.fromPrism.getOption" test
test_optional_method_fromPrism_set =
let
opt =
fromPrism string2IntPrism
test i =
opt.set i "" |> Expect.equal (String.fromInt i)
in
fuzz int "Optional.fromPrism.set" test
test_optional_method_compose =
let
opt =
compose addressRegionOptional (fromPrism string2IntPrism)
computed ( a, i ) =
opt.set i a
expected ( a, i ) =
{ a | region = Just (String.fromInt i) }
in
fuzz (Fuzz.tuple ( addressesWithRegion, int )) "Optional.compose" (\s -> Expect.equal (computed s) (expected s))
test_optional_method_composeLens =
let
opt =
composeLens addressRegionOptional (fromIso string2CharListIso)
computed ( a, cl ) =
opt.set cl a
expected ( a, cl ) =
{ a | region = Just (String.fromList cl) }
in
fuzz (Fuzz.tuple ( addressesWithRegion, list char )) "Optional.composeLens" (\s -> Expect.equal (computed s) (expected s))
test_lens_method_modifyOption_just =
let
f sn =
String.reverse sn
opt =
addressRegionOptional
computed a =
modifyOption opt f a
expected a =
opt.getOption a |> Maybe.map String.reverse |> Maybe.map (\b -> opt.set b a)
test s =
Expect.equal (computed s) (expected s)
in
fuzz addressesWithRegion "Optional.modifyOption for Just a" test
test_lens_method_modifyOption_nothing =
let
f sn =
String.reverse sn
opt =
addressRegionOptional
computed a =
modifyOption opt f a
expected a =
opt.getOption a |> Maybe.map String.reverse |> Maybe.map (\b -> opt.set b a)
test s =
Expect.equal (computed s) (expected s)
in
fuzz addressesWithoutRegion "Optional.modifyOption for Nothing" test
test_lens_method_modify_just =
let
f sn =
String.reverse sn
opt =
addressRegionOptional
computed a =
modify opt f a
expected a =
opt.getOption a |> Maybe.map String.reverse |> Maybe.map (\b -> opt.set b a) |> Maybe.withDefault a
test s =
Expect.equal (computed s) (expected s)
in
fuzz addressesWithRegion "Optional.modify for Just a" test
test_optional_method_zip =
let
address1 =
Address "test" Street Nothing "test" Nothing "test" US
address2 =
Address "test" Street Nothing "test" (Just "test") "test" US
opt =
zip addressRegionOptional addressRegionOptional
computed x =
opt.getOption (opt.set x ( address1, address2 ))
expected x =
Just x
test s =
Expect.equal (computed s) (expected s)
in
fuzz (Fuzz.tuple ( string, string )) "Optional.zip" test
test_optional_method_fromLens =
let
opt =
fromLens addressStreetNameLens
computed ( a, s ) =
opt.set s a
expected ( a, s ) =
{ a | streetName = s }
test s =
Expect.equal (computed s) (expected s)
in
fuzz (Fuzz.tuple ( addressesWithRegion, string )) "Optional.fromLens" test
================================================
FILE: tests/PrismSpec.elm
================================================
module PrismSpec exposing (..)
import Test exposing (..)
import Expect
import Fuzz exposing (Fuzzer, list, int, tuple, string, char)
import String
import Monocle.Iso exposing (Iso)
import Monocle.Prism exposing (Prism)
all : Test
all =
describe
"A Prism specification"
[ test_prism_property_partial_round_trip_one_way
, test_prism_property_no_round_trip_when_not_matching
, test_prism_property_round_trip_other_way
, test_prism_method_modify
, test_prism_method_modify_option
, test_prism_method_compose
, test_prism_method_composeIso
, test_prism_method_fromIso
, test_prism_method_fromIso_reverseGet
]
string2IntPrism : Prism String Int
string2IntPrism =
Prism String.toInt String.fromInt
string2FloatPrism : Prism String Float
string2FloatPrism =
Prism String.toFloat String.fromFloat
float2IntPrism : Prism Float Int
float2IntPrism =
let
getOption float =
let
int =
truncate float
back =
toFloat int
in
if (float == back) then
Just int
else
Nothing
in
Prism getOption toFloat
numbers : Fuzzer String
numbers =
Fuzz.map String.fromInt int
notnumbers : Fuzzer String
notnumbers =
Fuzz.map (\s -> String.append "_" s) string
numbersAndNotNumbers : Fuzzer String
numbersAndNotNumbers =
Fuzz.frequency [ ( 0.5, numbers ), ( 0.5, notnumbers ) ]
test_prism_property_partial_round_trip_one_way : Test
test_prism_property_partial_round_trip_one_way =
let
prism =
string2IntPrism
test s =
s
|> prism.getOption
|> Maybe.map prism.reverseGet
|> Expect.equal (Just s)
in
fuzz numbers "For some a: A, getOption a |> Maybe.map reverseGet == Just a" test
test_prism_property_no_round_trip_when_not_matching : Test
test_prism_property_no_round_trip_when_not_matching =
let
prism =
string2IntPrism
test s =
s
|> prism.getOption
|> Maybe.map prism.reverseGet
|> Expect.equal Nothing
in
fuzz notnumbers "For some a: A, getOption a |> Maybe.map reverseGet == Nothing " test
test_prism_property_round_trip_other_way : Test
test_prism_property_round_trip_other_way =
let
prism =
string2IntPrism
test i =
i
|> prism.reverseGet
>> prism.getOption
|> Expect.equal (Just i)
in
fuzz int "For all a: A, getOption (reverseGet a) == Just a " test
test_prism_method_modify : Test
test_prism_method_modify =
let
prism =
string2IntPrism
computed s =
let
fx i =
i * 2
modified =
Monocle.Prism.modify prism fx
in
modified s
expected s =
s |> String.toInt >> Maybe.map ((*) 2 >> String.fromInt) |> Maybe.withDefault s
test s =
Expect.equal (computed s) (expected s)
in
fuzz string "Prism method modify" test
test_prism_method_modify_option : Test
test_prism_method_modify_option =
let
prism =
string2IntPrism
computed s =
let
fx i =
i * 2
modified =
Monocle.Prism.modifyOption prism fx
in
modified s
expected s =
s |> String.toInt >> Maybe.map ((*) 2 >> String.fromInt)
test s =
Expect.equal (computed s) (expected s)
in
fuzz numbersAndNotNumbers "Prism method modifyOption" test
test_prism_method_compose : Test
test_prism_method_compose =
let
iso =
Iso ((*) 10) ((//) 10)
prism =
Monocle.Prism.composeIso string2IntPrism iso
computed s =
prism.getOption s
expected s =
s |> String.toInt >> Maybe.map ((*) 10)
test s =
Expect.equal (computed s) (expected s)
in
fuzz numbersAndNotNumbers "Prism method compose" test
test_prism_method_composeIso : Test
test_prism_method_composeIso =
let
iso =
Iso ((*) 10) ((//) 10)
prism =
Monocle.Prism.composeIso string2IntPrism iso
computed s =
prism.getOption s
expected s =
s |> String.toInt >> Maybe.map ((*) 10)
test s =
Expect.equal (computed s) (expected s)
in
fuzz numbersAndNotNumbers "Prism method composeIso" test
test_prism_method_fromIso : Test
test_prism_method_fromIso =
let
iso =
Iso String.toList String.fromList
prism =
Monocle.Prism.fromIso iso
computed s =
prism.getOption s
expected s =
iso.get s |> Just
test s =
Expect.equal (computed s) (expected s)
in
fuzz string "Prism method fromIso" test
test_prism_method_fromIso_reverseGet : Test
test_prism_method_fromIso_reverseGet =
let
iso =
Iso String.fromList String.toList
prism =
Monocle.Prism.fromIso iso
computed s =
prism.reverseGet s
expected s =
iso.reverseGet s
test s =
Expect.equal (computed s) (expected s)
in
fuzz string "Prism method fromIso when reverseGet" test
================================================
FILE: tests/Tests.elm
================================================
module Tests exposing (..)
import Test exposing (..)
import Expect
import Fuzz exposing (list, int, tuple, string)
import String
import IsoSpec
import PrismSpec
import LensSpec
import OptionalSpec
import CommonSpec
all : Test
all =
describe "Elm Monocle specification"
[ IsoSpec.all
, PrismSpec.all
, LensSpec.all
, OptionalSpec.all
, CommonSpec.all
]
================================================
FILE: tests/TraversalSpec.elm
================================================
module TraversalSpec exposing (all)
import Array
import Expect
import Fuzz exposing (array, int, list)
import Monocle.Traversal as Traversal
import Test exposing (..)
all : Test
all =
describe
"A Traversal specification"
[ test_list_traversal
, test_array_traversal
, test_some_traversal
]
test_list_traversal : Test
test_list_traversal =
let
test s =
s
|> Traversal.modify Traversal.list ((*) 2)
|> Expect.equal (List.map ((*) 2) s)
in
fuzz (list int) "Traversal modify on a list" test
test_array_traversal : Test
test_array_traversal =
let
test s =
s
|> Traversal.modify Traversal.array ((*) 2)
|> Expect.equal (Array.map ((*) 2) s)
in
fuzz (array int) "Traversal modify on an array" test
test_some_traversal : Test
test_some_traversal =
let
odds =
Traversal.some Traversal.list (\n -> remainderBy 2 n == 1)
test _ =
[ 1, 2, 3, 4, 5 ]
|> Traversal.modify odds ((+) 3)
|> Expect.equal [ 4, 2, 6, 4, 8 ]
in
Test.test "Traversal modify some elements in an array" test
gitextract_bil9_ung/
├── .gitignore
├── LICENSE
├── README.md
├── elm.json
├── example/
│ └── OptionalExample.elm
├── package.json
├── src/
│ └── Monocle/
│ ├── Common.elm
│ ├── Compose.elm
│ ├── Iso.elm
│ ├── Lens.elm
│ ├── Optional.elm
│ ├── Prism.elm
│ └── Traversal.elm
└── tests/
├── .gitignore
├── CommonSpec.elm
├── ComposeSpec.elm
├── IsoSpec.elm
├── LensSpec.elm
├── OptionalSpec.elm
├── PrismSpec.elm
├── Tests.elm
└── TraversalSpec.elm
Condensed preview — 22 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (109K chars).
[
{
"path": ".gitignore",
"chars": 228,
"preview": "# added by GitSavvy\n/elm-stuff/\n\n# added by GitSavvy\nnode_modules\n\n# added by GitSavvy\n/documentation.json\n\n# added by G"
},
{
"path": "LICENSE",
"chars": 1076,
"preview": "The MIT License (MIT)\nCopyright (c) 2016 Artur Opala\n\nPermission is hereby granted, free of charge, to any person obtain"
},
{
"path": "README.md",
"chars": 8064,
"preview": "[](https://semaphoreci.c"
},
{
"path": "elm.json",
"chars": 607,
"preview": "{\n \"type\": \"package\",\n \"name\": \"arturopala/elm-monocle\",\n \"summary\": \"Library providing functional tools to man"
},
{
"path": "example/OptionalExample.elm",
"chars": 2006,
"preview": "module OptionalExample exposing (Address, Country(..), Place, StreetType(..), addressOfPlace, place, regionOfAddress, re"
},
{
"path": "package.json",
"chars": 873,
"preview": "{\n \"name\": \"elm-monocle\",\n \"version\": \"1.6.0\",\n \"description\": \"Library providing purely functional abstractions to m"
},
{
"path": "src/Monocle/Common.elm",
"chars": 3144,
"preview": "module Monocle.Common exposing\n ( maybe\n , array\n , list\n , listToArray\n , dict\n , result\n , id\n "
},
{
"path": "src/Monocle/Compose.elm",
"chars": 13604,
"preview": "module Monocle.Compose exposing\n ( isoWithIso, isoWithPrism, isoWithLens, isoWithOptional, isoWithTraversal\n , pri"
},
{
"path": "src/Monocle/Iso.elm",
"chars": 1687,
"preview": "module Monocle.Iso exposing\n ( Iso\n , reverse, modify, compose\n )\n\n{-| An Iso is a tool which converts elements"
},
{
"path": "src/Monocle/Lens.elm",
"chars": 4255,
"preview": "module Monocle.Lens exposing\n ( Lens\n , compose, modify, modify2, modify3, modifyAndMerge, zip, tuple, tuple3\n "
},
{
"path": "src/Monocle/Optional.elm",
"chars": 7391,
"preview": "module Monocle.Optional exposing\n ( Optional\n , compose, composeLens, modifyOption, modify, modify2, modify3, zip,"
},
{
"path": "src/Monocle/Prism.elm",
"chars": 3398,
"preview": "module Monocle.Prism exposing\n ( Prism\n , isMatching, modify, modifyOption, compose, composeIso\n , fromIso\n "
},
{
"path": "src/Monocle/Traversal.elm",
"chars": 3083,
"preview": "module Monocle.Traversal exposing\n ( Traversal\n , list, array, some, modify\n )\n\n{-| A Traversal is like an Opti"
},
{
"path": "tests/.gitignore",
"chars": 12,
"preview": "/elm-stuff/\n"
},
{
"path": "tests/CommonSpec.elm",
"chars": 2816,
"preview": "module CommonSpec exposing (..)\n\nimport Test exposing (..)\nimport Expect\nimport Fuzz exposing (int, tuple, string, char)"
},
{
"path": "tests/ComposeSpec.elm",
"chars": 26245,
"preview": "module ComposeSpec exposing (..)\n\nimport Array\nimport Expect\nimport Fuzz exposing (constant, float, int, intRange, list,"
},
{
"path": "tests/IsoSpec.elm",
"chars": 2761,
"preview": "module IsoSpec exposing (..)\n\nimport Test exposing (..)\nimport Expect\nimport Fuzz exposing (list, int, tuple, string, ch"
},
{
"path": "tests/LensSpec.elm",
"chars": 6893,
"preview": "module LensSpec exposing (..)\n\nimport Test exposing (..)\nimport Expect\nimport Fuzz exposing (Fuzzer, list, int, string, "
},
{
"path": "tests/OptionalSpec.elm",
"chars": 7689,
"preview": "module OptionalSpec exposing (..)\n\nimport Test exposing (..)\nimport Expect\nimport Fuzz exposing (Fuzzer, list, int, tupl"
},
{
"path": "tests/PrismSpec.elm",
"chars": 5683,
"preview": "module PrismSpec exposing (..)\n\nimport Test exposing (..)\nimport Expect\nimport Fuzz exposing (Fuzzer, list, int, tuple, "
},
{
"path": "tests/Tests.elm",
"chars": 407,
"preview": "module Tests exposing (..)\n\nimport Test exposing (..)\nimport Expect\nimport Fuzz exposing (list, int, tuple, string)\nimpo"
},
{
"path": "tests/TraversalSpec.elm",
"chars": 1233,
"preview": "module TraversalSpec exposing (all)\n\nimport Array\nimport Expect\nimport Fuzz exposing (array, int, list)\nimport Monocle.T"
}
]
About this extraction
This page contains the full source code of the arturopala/elm-monocle GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 22 files (100.7 KB), approximately 26.0k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.