Full Code of arturopala/elm-monocle for AI

master 7d8be090c9b7 cached
22 files
100.7 KB
26.0k tokens
1 requests
Download .txt
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
================================================
[![Build Status](https://semaphoreci.com/api/v1/arturopala/elm-monocle/branches/master/badge.svg)](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
Download .txt
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": "[![Build Status](https://semaphoreci.com/api/v1/arturopala/elm-monocle/branches/master/badge.svg)](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.

Copied to clipboard!