{"id":13686599,"url":"https://github.com/arturopala/elm-monocle","last_synced_at":"2025-04-13T08:18:25.837Z","repository":{"id":46892660,"uuid":"50673587","full_name":"arturopala/elm-monocle","owner":"arturopala","description":"Functional abstractions to manipulate complex records in Elm - Iso, Prism, Lens, Optional, Traversal.","archived":false,"fork":false,"pushed_at":"2021-09-21T23:00:25.000Z","size":92,"stargazers_count":154,"open_issues_count":0,"forks_count":9,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T00:30:12.891Z","etag":null,"topics":["elm","elm-lang","elm-monocle","lens","lenses","manipulate-complex-records","monocle","prism","traversal"],"latest_commit_sha":null,"homepage":"","language":"Elm","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arturopala.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-29T16:07:17.000Z","updated_at":"2025-03-25T07:12:17.000Z","dependencies_parsed_at":"2022-09-05T11:01:37.189Z","dependency_job_id":null,"html_url":"https://github.com/arturopala/elm-monocle","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturopala%2Felm-monocle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturopala%2Felm-monocle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturopala%2Felm-monocle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arturopala%2Felm-monocle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arturopala","download_url":"https://codeload.github.com/arturopala/elm-monocle/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248319877,"owners_count":21083917,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["elm","elm-lang","elm-monocle","lens","lenses","manipulate-complex-records","monocle","prism","traversal"],"created_at":"2024-08-02T15:00:35.899Z","updated_at":"2025-04-13T08:18:25.799Z","avatar_url":"https://github.com/arturopala.png","language":"Elm","funding_links":[],"categories":["Elm"],"sub_categories":[],"readme":"[![Build Status](https://semaphoreci.com/api/v1/arturopala/elm-monocle/branches/master/badge.svg)](https://semaphoreci.com/arturopala/elm-monocle)\n\nelm-monocle\n===========\n\nA [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.\n\nPublished as [**arturopala/elm-monocle**](http://package.elm-lang.org/packages/arturopala/elm-monocle/latest) library.\n\n\n# Long Example\n\n```elm\nimport Monocle.Optional exposing (Optional)\nimport Monocle.Lens exposing (Lens)\n\n\ntype StreetType\n    = Street\n    | Avenue\n\n\ntype Country\n    = US\n    | UK\n    | FI\n    | PL\n    | DE\n\n\ntype alias Address =\n    { streetName : String\n    , streetType : StreetType\n    , floor : Maybe Int\n    , town : String\n    , region : Maybe String\n    , postcode : String\n    , country : Country\n    }\n\n\ntype alias Place =\n    { name : String\n    , description : Maybe String\n    , address : Maybe Address\n    }\n\n\naddressOfPlace : Optional Place Address\naddressOfPlace =\n    Optional .address (\\b a -\u003e { a | address = Just b })\n\n\nregionOfAddress : Optional Address String\nregionOfAddress =\n    Optional .region (\\b a -\u003e { a | region = Just b })\n\n\nstreetNameOfAddress : Lens Address String\nstreetNameOfAddress =\n    Lens .streetName (\\b a -\u003e { a | streetName = b })\n\n\nregionOfPlace : Optional Place String\nregionOfPlace =\n    addressOfPlace |\u003e Monocle.Compose.optionalWithOptional regionOfAddress\n\n\nstreetNameOfPlace : Optional Place String\nstreetNameOfPlace =\n    addressOfPlace |\u003e Monocle.Compose.optionalWithLens streetNameOfAddress\n\n\nplace : Place\nplace =\n    { name = \"MyPlace\"\n    , description = Nothing\n    , address =\n        Just\n            { streetName = \"Union Road\"\n            , streetType = Street\n            , floor = Nothing\n            , town = \"Daisytown\"\n            , region = Nothing\n            , postcode = \"00100\"\n            , country = US\n            }\n    }\n\n\nupdatedPlace : Place\nupdatedPlace =\n    place\n        |\u003e regionOfPlace.set \"NorthEast\"\n        |\u003e streetNameOfPlace.set \"Union Avenue\"\n```\n\n# Abstractions\n\n## Iso\n\nAn Iso is a tool which converts elements of type A into elements of type B and back without loss.\n\n```elm\n    type alias Iso a b =\n        { get : a -\u003e b\n        , reverseGet : b -\u003e a\n        }\n```\n\n###### Example\n\n```elm\n    string2CharListIso : Iso String (List Char)\n    string2CharListIso =\n        Iso String.toList String.fromList\n\n    (string2CharListIso.get \"ABcdE\") == ['A','B','c','d','E']\n    (string2CharListIso.reverseGet ['A','B','c','d','E']) == \"ABcdE\"\n```\n\n## Prism\n\nA Prism is a tool which optionally converts elements of type A into elements of type B and back.\n\n```elm\n    type alias Prism a b =\n        { getOption : a -\u003e Maybe b\n        , reverseGet : b -\u003e a\n        }\n```\n\n###### Example\n\n```elm\n    string2IntPrism : Prism String Int\n    string2IntPrism =\n        Prism String.toInt String.fromInt\n\n    string2IntPrism.getOption \"17896\" == Just 17896\n    string2IntPrism.getOption \"1a896\" == Nothing\n    string2IntPrism.reverseGet 1626767 = \"1626767\"\n```\n\n## Lens\n\nA 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. \n\n```elm\n    type alias Lens a b =\n        { get : a -\u003e b\n        , set : b -\u003e a -\u003e a\n        }\n```\n\n###### Example\n\n```elm\n    type alias Address = \n        { streetName: String\n        , postcode: String\n        , town: String\n        }\n\n    type alias Place =\n        { name: String\n        , address: Address\n        }\n\n    addressStreetNameLens : Lens Address String\n    addressStreetNameLens =\n        Lens .streetName (\\b a -\u003e { a | streetName = b })\n\n    placeAddressLens : Lens Place Address\n    placeAddressLens =\n        Lens .address (\\b a -\u003e { a | address = b })\n\n    placeStreetName: Lens Place String\n    placeStreetName =\n        placeAddressLens |\u003e Monocle.Compose.lensWithLens addressStreetNameLens\n\n    myPlace = Place \"my\" (Address \"Elm\" \"00001\" \"Daisytown\")\n    placeStreetName.get myPlace == \"Elm\"\n    \n    myNewPlace = placeStreetName.set \"Oak\" myPlace\n\n    placeStreetName.get myNewPlace == \"Oak\"\n    myNewPlace == Place \"my\" (Address \"Oak\" \"00001\" \"Daisytown\")\n\n```\n\n## Optional\n\nA Optional is a weaker Lens and a weaker Prism.\n\n```elm\n    type alias Optional a b =\n        { getOption : a -\u003e Maybe b\n        , set : b -\u003e a -\u003e a\n        }\n```\n\n###### Example\n\n```elm\n    addressRegionOptional : Optional Address String\n    addressRegionOptional =\n        Optional .region (\\b a -\u003e { a | region = Just b })\n\n    string2IntPrism : Prism String Int\n    string2IntPrism = Prism String.toInt String.fromInt\n\n    addressRegionIntOptional: Optional Address Int\n    addressRegionIntOptional =\n        addressRegionOptional |\u003e Monocle.Compose.optionalWithPrism string2IntPrism\n\n    string2CharListIso : Iso String (List Char)\n    string2CharListIso = Iso String.toList String.fromList\n\n    addressRegionListCharOptional: Optional Address (List Char)\n    addressRegionListCharOptional =\n        addressRegionOptional |\u003e Monocle.Compose.optionalWithIso string2CharListIso\n\n    modifyRegion: String -\u003e String\n    modifyRegion region = String.reverse region\n\n    modifyAddressRegion: Address -\u003e Maybe Address\n    modifyAddressRegion address = Optional.modifyOption addressRegionOptional modifyRegion address\n\n    modifyRegion: String -\u003e String\n    modifyRegion region = String.reverse region\n\n    modifyAddressRegion: Address -\u003e Address\n    modifyAddressRegion address = Optional.modify addressRegionOptional modifyRegion address\n```\n\n## Traversal\n\nA Traversal allows you to modify many elements at once.\n\n```elm\n    type alias Traversal a b =\n        (b -\u003e b) -\u003e a -\u003e a\n```\n\n(`Traversal a b` is just an alias for a function that applies\na transformation over `b` elements of a larger `a` structure.)\n\n###### Example\n\n```elm\n    firstNameLens : Lens Friend String\n    firstNameLens =\n        Lens .firstName (\\b a -\u003e { a | firstName = b })\n\n    bestFriendsTraversal : Traversal (List Friend) Friend\n    bestFriendsTraversal =\n        Traversal.some\n            Traversal.list\n            (\\friend -\u003e friend.value == Best)\n\n    friendsLens : Lens Account (List Friend)\n    friendsLens =\n        Lens .friends (\\b a -\u003e { a | friends = b })\n\n    firstNamesOfBestFriends : Traversal Account String\n    firstNamesOfBestFriends =\n        friendsLens\n            |\u003e Compose.lensWithTraversal bestFriendsTraversal\n            |\u003e Compose.traversalWithLens firstNameLens\n\n    upcaseBestFriendsFirstNames : Account -\u003e Account\n    upcaseBestFriendsFirstNames account =\n        Traversal.modify firstNamesOfBestFriends String.toUpper\n```\n\n## Common\nCommon lenses/prisms/optionals that most projects will use.\n\n####  Step into a `Maybe` value.\n```elm\n    maybe.set 5 Nothing\n    \u003e Just 5\n```\n####  Step into an `Array` at the given index.\n```elm\n    .getOption (array 2) (Array.fromList [ 10, 11, 12, 13 ])\n    \u003e Just 12\n\n    .getOption (array 8) (Array.fromList [ 10, 11, 12, 13 ])\n    \u003e Nothing\n```\n####  Step into a `Dict` with the given key.\n```elm\n    .getOption (dict \"Tom\") (Dict.fromList [ ( \"Tom\", \"Cat\" ) ])\n    \u003e Just \"Cat\"\n\n    .getOption (dict \"Jerry\") (Dict.fromList [ ( \"Tom\", \"Cat\" ) ])\n    \u003e Nothing\n```\n####  Step into the success value of a `Result`.\n```elm    \n    result.getOption (Ok 5)\n    \u003e Just 5\n\n    result.getOption (Err \"500\")\n    \u003e Nothing\n```\n####  Step into a record with an `id` key.\nSince records with an `id` field are incredible common, this is\nincluded for convenience. It also serves as a simple recipe for\ncreating record lenses.\n```elm   \n    id.get { id = 1000, name = ... }\n    \u003e 1000\n```\n####  Step into the first element of a pair.\n```elm\n    first.get ( 'a', 'b' )\n    \u003e 'a'\n```\n####  Step into the second element of a pair.\n```elm    \n    second.get ( 'a', 'b' )\n    \u003e 'b'\n```\n\n# Build\n\n## Prerequisites\n\n-   Node.js\n-   Yarn\n-   Run `yarn install-with-elm`\n\n## Compile\n\nRun `yarn compile`\n\n## Test\n\nRun `elm-test`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farturopala%2Felm-monocle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farturopala%2Felm-monocle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farturopala%2Felm-monocle/lists"}