This is an alternative site for discovering Elm packages. You may be looking for the official Elm package site instead.
Library providing functional tools to manipulate complex records
version 1.7.0
license MIT
native-modules False
elm-version 0.18.0 <= v < 0.19.0
Tag 1.7.0
Committed At 2018-07-18 22:04:16 UTC
elm-lang/core 5.0.0 <= v < 6.0.0 5.1.1

README

Build Status

elm-monocle

A Monocle-inspired library providing purely functional abstractions to manipulate complex records in the elm language.

Published as arturopala/elm-monocle library.

Long Example

import Monocle.Optional exposing (Optional)
import Monocle.Lens exposing (Lens)
import Monocle.Common exposing ((<|>), (=>))


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 => 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"

Abstractions

Iso

An Iso is a tool which converts elements of type A into elements of type B and back without loss.

    type alias Iso a b =
        { get : a -> b
        , reverseGet : b -> a
        }
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"

Prism

A Prism is a tool which optionally converts elements of type A into elements of type B and back.

    type alias Prism a b =
        { getOption : a -> Maybe b
        , reverseGet : b -> a
        }
Example
    string2IntPrism : Prism String Int
    string2IntPrism =
        Prism (String.toInt >> Result.toMaybe) toString

    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.

    type alias Lens a b =
        { get : a -> b
        , set : b -> a -> a
        }
Example

    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 <|> 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.

    type alias Optional a b =
        { getOption : a -> Maybe b
        , set : b -> a -> a
        }
Example
    addressRegionOptional : Optional Address String
    addressRegionOptional =
        Optional .region (\b a -> { a | region = Just b })

    string2IntPrism : Prism String Int
    string2IntPrism = Prism (String.toInt >> Result.toMaybe) toString

    addressRegionIntOptional: Optional Address Int
    addressRegionIntOptional = addressRegionOptional => (fromPrism string2IntPrism)

    string2CharListIso : Iso String (List Char)
    string2CharListIso = Iso String.toList String.fromList

    addressRegionListCharOptional: Optional Address (List Char)
    addressRegionListCharOptional = composeLens addressRegionOptional (fromIso 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

Common

Common lenses/prisms/optionals that most projects will use.

Convenient infix operator for composing lenses.

Allows to chain lens composition for deeply nested structures:

    fromAtoB : Lens A B
    fromAtoB = Lens .b (\b a -> { a | b = b })
    fromBtoC : Lens B C
    fromBtoC = Lens .c (\c b -> { b | c = c })
    fromCtoD : Lens C D
    fromCtoD = Lens .d (\d c -> { c | d = d })
    fromDtoE : Lens D E
    fromDtoE = Lens .e (\e d -> { d | e = e })
    fromAtoE : Lens A E
    fromAtoE = fromAtoB <|> fromBtoC <|> fromCtoD <|> fromDtoE

    a : A
    a = { b: { c: { d: { e: "Whatever we want to get" } } } }

    fromAtoE.get a
    => "Whatever we want to get"

    fromAtoE.set a "What we want to set"
    => { b: { c: { d: { e: "What we want to set" } } } }

Convenient infix operator for composing optionals.

    .getOption (maybe => array 2) (Just <| Array.fromList [ 10, 11, 12, 13 ])
    > 12

Convenient infix operator for composing optional with lens.

    .getOption (maybe =|> id) (Just { id = 12 })
    > 12

Step into a Maybe value.

    maybe.set 5 Nothing
    > Just 5

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

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

Step into the success value of a Result.

    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.

    id.get { id = 1000, name = ... }
    > Just 1000

Step into the first element of a pair.

    first.get ( 'a', 'b' )
    > Just 'a'

Step into the second element of a pair.

    second.get ( 'a', 'b' )
    > Just 'b'

Build

Prerequisites

  • Node.js
  • Yarn
  • Run yarn install-with-elm

Compile

Run yarn compile

Test

Run elm-test