Skip to content

Commit

Permalink
add infix operator (=|>) to compose Optional with Lens
Browse files Browse the repository at this point in the history
  • Loading branch information
arturopala committed Mar 15, 2018
1 parent bbca89e commit e28f772
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 7 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ Allows to chain lens composition for deeply nested structures:
.getOption (maybe => array 2) (Just <| Array.fromList [ 10, 11, 12, 13 ])
> 12
```
#### Convenient infix operator for composing optional with lens.
```elm
.getOption (maybe =|> id) (Just { id = 12 })
> 12
```
#### Step into a `Maybe` value.
```elm
maybe.set 5 Nothing
Expand Down
2 changes: 1 addition & 1 deletion elm-package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "1.5.1",
"version": "1.6.0",
"summary": "Library providing functional tools to manipulate complex records",
"repository": "https://github.com/arturopala/elm-monocle.git",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "elm-monocle",
"version": "1.5.2",
"version": "1.6.0",
"description": "Library providing purely functional abstractions to manipulate records",
"scripts": {
"compile": "elm-make ./src/**/*.elm --output monocle.js",
Expand Down
29 changes: 26 additions & 3 deletions src/Monocle/Common.elm
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ module Monocle.Common exposing (..)
@docs (<|>)
@docs (=>)
@docs (=|>)
@docs maybe
@docs array
@docs dict
@docs result
@docs id
@docs first
@docs second
-}

import Array exposing (Array)
Expand All @@ -20,7 +22,7 @@ import Monocle.Optional as Optional exposing (Optional)


{-| Convenient Infix operator for composing lenses.
Allows to chain lens composition for deeply nested structures:
Allows to chain lens composition for deeply nested structures:
fromAtoB : Lens A B
fromAtoB = Lense .b (\a b -> { a | b = b })
Expand All @@ -45,6 +47,7 @@ import Monocle.Optional as Optional exposing (Optional)
fromAtoE.set a "What we want to set"
=> { b: { c: { d: { e: "What we want to set" } } } }
-}
(<|>) : Lens a b -> Lens b c -> Lens a c
(<|>) =
Expand All @@ -53,19 +56,33 @@ import Monocle.Optional as Optional exposing (Optional)

{-| Convenient infix operator for composing optionals.
.getOption (maybe => array 2) (Just <| Array.fromList [ 10, 11, 12, 13 ])
> 12
.getOption (maybe => array 2) (Just <| Array.fromList [ 10, 11, 12, 13 ])
> 12
-}
(=>) : Optional a b -> Optional b c -> Optional a c
(=>) =
Optional.compose


{-| Convenient infix operator for composing optional with lens.
.getOption (maybe =|> id) (Just { id = 12 })
> 12
-}
(=|>) : Optional a b -> Lens b c -> Optional a c
(=|>) a b =
Optional.compose a (Optional.fromLens b)


{-| Step into a `Maybe` value.
maybe.set 5 Nothing
> Just 5
-}
maybe : Optional (Maybe a) a
maybe =
Expand All @@ -81,6 +98,7 @@ maybe =
.getOption (array 8) (Array.fromList [ 10, 11, 12, 13 ])
> Nothing
-}
array : Int -> Optional (Array a) a
array index =
Expand All @@ -96,6 +114,7 @@ array index =
.getOption (dict "Jerry") (Dict.fromList [ ( "Tom", "Cat" ) ])
> Nothing
-}
dict : comparable -> Optional (Dict comparable v) v
dict key =
Expand All @@ -111,6 +130,7 @@ dict key =
result.getOption (Err "500")
> Nothing
-}
result : Optional (Result e a) a
result =
Expand All @@ -127,6 +147,7 @@ result =
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 =
Expand All @@ -139,6 +160,7 @@ id =
first.get ( 'a', 'b' )
> Just 'a'
-}
first : Lens ( a, b ) a
first =
Expand All @@ -151,6 +173,7 @@ first =
second.get ( 'a', 'b' )
> Just 'b'
-}
second : Lens ( a, b ) b
second =
Expand Down
55 changes: 53 additions & 2 deletions tests/CommonSpec.elm
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,50 @@ import Fuzz exposing (list, int, tuple, string, char)
import String
import Dict
import Maybe
import Monocle.Common exposing (dict)
import Array
import Monocle.Common exposing (dict, (=>), (=|>), maybe, array, id)


all : Test
all =
describe "A Common specification"
[ test_dict_empty
[ test_maybe
, test_array_just
, test_array_nothing
, test_dict_empty
, test_dict_list
, test_infix_compose_optionals
, test_infix_compose_optional_with_lens
]


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_dict_empty : Test
test_dict_empty =
let
Expand All @@ -39,3 +72,21 @@ test_dict_list =
.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


test_infix_compose_optionals : Test
test_infix_compose_optionals =
let
test i =
.getOption (maybe => array 2) (Just <| Array.fromList [ 10, 11, i, 13 ]) |> Expect.equal (Just i)
in
fuzz int "Common.=> should compose 2 Optionals" test


test_infix_compose_optional_with_lens : Test
test_infix_compose_optional_with_lens =
let
test i =
.getOption (maybe =|> id) (Just { id = i }) |> Expect.equal (Just i)
in
fuzz int "Common.=|> should compose Optional with Lens" test

0 comments on commit e28f772

Please sign in to comment.