arturopala / elm-monocle Goto Github PK
View Code? Open in Web Editor NEWFunctional abstractions to manipulate complex records in Elm - Iso, Prism, Lens, Optional, Traversal.
License: MIT License
Functional abstractions to manipulate complex records in Elm - Iso, Prism, Lens, Optional, Traversal.
License: MIT License
Hi @arturopala :)
I've been toying with the idea of adding Traversal here for quite some time, and I've just bumped into a case where it'd be useful. So here's me asking whether you'd like a PR that'd add the a new Monocle.Traversal module (and composition functions in Compose) :) (I haven't started on it yet, and since I'm going to prepare this from my use case I'm open to your thoughts on what should be in it and how).
So, what do you say?
Here's the Dict example:
Here's what happens when I run the example:
850 $ elm-repl
---- elm-repl 0.17.1 -----------------------------------------------------------
:help for help, :exit to exit, more at <https://github.com/elm-lang/elm-repl>
--------------------------------------------------------------------------------
> import Monocle.Common exposing (..)
> import Dict
> dict.getOption "Tom" (Dict.fromList [("Tom","Cat")])
-- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm
`Monocle.Common.dict` is being used in an unexpected way.
5| dict.getOption "Tom" (Dict.fromList [("Tom","Cat")])
^^^^
Based on its definition, `Monocle.Common.dict` has this type:
comparable -> Monocle.Optional.Optional (Dict.Dict comparable c) c
But you are trying to use it as:
{ b | getOption : a }
(I'm using 1.3.0, but the example is the same in that version and in 1.4.)
> elm package install arturopala/elm-monocle
To install arturopala/elm-monocle I would like to add the following
dependency to elm-package.json:
"arturopala/elm-monocle": "1.2.0 <= v < 2.0.0"
May I add that to elm-package.json for you? [Y/n] y
Error: I cannot find a set of packages that works with your constraints.
--> There are no versions of arturopala/elm-monocle that work with Elm 0.17.1.
Maybe the maintainer has not updated it yet.
This is more a question than an issue or request, but why is there an "array" to access an item at some place in an array and not the equivalent list? Is this an optimization thing or just an edge case that wasn't as urgent as others?
Since I feel it can be interesting to have, I'd be willing to add it to the codebase in a PR, unless there is a good reason for it not to exist :)
I really love monocle and the ability to use lenses to get and set values easily.
But since lenses are especially interesting when you can compose them, and since composition can be deep for deeply nested structures, it's a bit annoying and counter-intuitive to have to do this:
lens1 : Lens a b
lens2 : Lens b c
lens3 : Lens c d
lens13_1 : Lens a d
lens13_1 =
lens3
|> compose lens2
|> compose lens1
-- OR
lens13_2 : Lens a d
lens13_2 =
compose (compose lens1 lens2) lens3
-- OR
lens13_3 : Lens a d
lens13_3 =
let
lens12 = compose lens1 lens2
in
compose lens12 lens3
-- OR EVEN
lens13_4 : Lens a d
lens13_4 =
compose lens1 <| compose lens2 lens3
All these patterns are grating to read. We usually solved it making "half-way" lenses like:
lens12 = compose lens1 lens2
lens13 = compose lens12 lens3
But I can't help thinking we might benefit from an infix Lens.compose alias allowing to do things like:
(<|>) = Lens.compose
lens13 = lens1 <|> lens2 <|> lens3
(I've actually done it in projects of my own that use lenses)
So, what do you think?
This library is brilliant - thanks for creating it!
I find myself using a lot of common optionals again & again - things like:
dict : comparable -> Optional (Dict comparable v) v
dict key =
{ getOption = Dict.get key
, set = Dict.insert key
}
So far I have a fistful for things like Array/Maybe/Dict/Result
& first/second/.id
.
I'd like to publish them somewhere so I can reuse them. This might be the right home. Would you like to add them here? If so, I'll PR. :-)
Thanks again!
Hey :) my mistaken proposal to help might give something interesting after all, a crazy idea, but it might just work :p
So, composing with operators was cool because it was terse and readable (once you knew what the operator did) and it was almost as cool as "real" lens composition with the function composition operator (a la haskell).
And now we can't have nice toys. Thanks Elm 0.19!
But, what if we used the pipeline operator (|>) with an appropriately named function to chain composition?
So, here's the style we could be using:
-- with :
-- lab => Lens A B
-- lbc => Lens B C
-- ...
-- oab => Optional A B
-- obc => Optional B C
-- ...
lad : Lens A D
lad =
lab
|> Lens.andLens lbc
|> Lens.andLens lcd
oad : Optional A D
oad =
lab
|> Lens.andOptional obc
|> Optional.andOptional lcd
So, each composition method could be found in their "starting" optic's module (more precisely, in the module of the type of optic of their second argument) and would be named after the type of the optic used in the composition (the type of optic in the first argument).
-- Lens
andLens : Lens B C -> Lens A B -> Lens A C
...
andOptional : Optional B C -> Lens A B -> Optional A C
...
-- Optional
andLens : Optional B C -> Lens A B -> Optional A C
...
andOptional : Optional B C -> Optional A B -> Optional A C
...
I think you get the idea (in fact, you probably have gotten it just by reading the title, but I'm writing my thoughts as they come here mostly :p). I think this is as good (and readable, and intuitive) as we could make it without typeclasses, and it'd work quite well with the ideology of discoverability and clarity Elm is pushing with the restriction of defining operators now.
So, what do you think?
If you're game, I'm going to prepare a pull request implementing it at least for Lens & Optionals as a proof of concept (well, I think I'm going to do it anyways ;p but I'd still like your input about that idea and its ramifications ; maybe there's some roadblock ahead I'm not seeing right now).
Here's the example:
string2IntPrism.getOption "17896" == Just 17896
string2IntPrism.getOption "1a896" == Nothing
string2IntPrism.reverseGet 1626767 = "1626767"
My reading of both the Scala Monocle prism laws and the Haskell prism laws suggest that doesn't work.
Here's the Scala description of the second law:
def partialRoundTripOneWay[S, A](p: Prism[S, A], a: A): Boolean =
p.getOption(p.reverseGet(a)) == Some(a)
That suggests to me that getOption (reverseGet "1626767") == Just 1626767
, but it will actually return Nothing
.
The Haskell doc defines the equivalent as its first law:
First, if I `re` or `review` a value with a Prism and then `preview` or use (^?), I will get it back:
preview l (review l b) ≡ Just b
Your implementation is arguably more useful, since it seems the law restricts you to a sum type.
I'm probably confused.
I'm failing to see the benefit from isolation of those two abstractions. Both serve the same purpose and Prisms end up being Optional, once composed any way. Also there's no such concept as Optional in the classical lens libraries in Haskell, so it's a source of confusion for people with such background (I know it was for me).
So I suggest not to breed concepts unless you have a good reason and remove the current implementation of Prism
and rename Optional
to Prism
.
Hi @arturopala thanks you for such a nice library!
Can you, please, tell me why you chose to use records with functions as properties instead of using opaque type and functions like Monocle.get
, Monocle.set
, like for example, in Focus library?
I am trying to understand if it was just a style preference or there was more to it :)
The following example in README doesn't work. I also tried changing =>
to >>
in case it was just a typo, but it still doesn't compile, just gives a lof of type errors.
regionOfPlace : Optional Place String
regionOfPlace =
addressOfPlace => regionOfAddress
With the removal of operators, I guess we're going to need some cleanup.
Would you like some help? If so, how do you think we should proceed? :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.