Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The ^= operator seems backwards, and I'm not sure about the ^% operator #47

Open
rmunn opened this issue Sep 24, 2016 · 5 comments
Open

Comments

@rmunn
Copy link

rmunn commented Sep 24, 2016

With Optic.set, the parameters are in the order I would expect. But the ^= operator has the parameters backwards from Optic.set, which is not what I would expect. As for Optic.map and the ^% operator, I'm not 100% sure which way around I'd expect the parameters to be, but I feel like they should at least be consistent between ^% and Optic.map. Let me use an example to show you what I mean:

type Data = { items: int list; code: string }
let items_ : Lens<_,_> = (fun d -> d.items), (fun l d -> { d with items = l })
let data = { items = [1;2;3]; code = "foo" }
data |> Optic.get items_  // This feels "natural"
data ^. items_  // As does this
data |> Optic.set items_ [4;5;6]  // As does this
data |> ([4;5;6] ^= items_ ) // But this feels wrong
data |> (items_ ^= [4;5;6])  // This would feel more natural
data |> Optic.map items_ (List.map (*2)) // Whereas this feels "backwards"...
data |> (List.map (*2) ^% items_) // ... and this feels "natural"

It's probably too late to change this for Aether 8.x, but 9.x isn't released yet, right? At least I don't see a NuGet package for 9.0. I'd love to see the ^= operator feel a bit more natural to use (even if it won't ever be really natural -- it "wants" to be a custom ternary operator, and F# makes it hard to define those).

@kolektiv
Copy link
Member

Yes, I do want to revisit these, because they do feel a bit off. For 9.0 I'm definitely open to them being re-ordered. I think what I'll do is a advertise the possibility in the Gitter channel as well and see if there's any strong objections, but otherwise pencil it in for a 9.0 release, possibly some time soon.

@WozSoftware
Copy link

Deleted past comment. Me being dumb while learning the library and F# at the same time. I agree with the OP, would feel more natural with them reversed

@varon
Copy link
Contributor

varon commented Sep 11, 2017

Edit: Useless suggestion removed.

@WozSoftware
Copy link

varon, you might have missed that there are some operators

So you can do

data ^. items_

The issue was the order of set ^=

If you look at the original post you will see in action

@varon
Copy link
Contributor

varon commented Sep 12, 2017

@WozSoftware - Yeah, I actually use those extensively, but apparently I was completely mistaken about the actual source of the braces requirements. The elimination of braces is still something I want to do, but that post literally has nothing to do with it, so I've removed it.


At the moment, we have mandatory braces required due to the lower precedence of the lens and prism composition operators >-> and >?> than the 'usage' operators ^=, ^. and ^% .

type BarRecord = { StringField: string }
type FooRecord = { Bar: BarRecord }

let bar_:Lens<_,_> = (fun x -> x.Bar), (fun v x -> { x with Bar = v } )
let stringField_:Lens<_,_> =(fun x -> x.StringField), (fun v x -> { x with StringField = v } )

let data = { Bar = { StringField = "test" } } 

//Given the current operators, this line requires braces around the lens composition.
let wontCompile = data |> "some string" ^= bar_ >-> stringField_
let willCompile = data |> "some string" ^= (bar_ >-> stringField_)

Whereas if we defined the composition operator starting with the + symbol, it'll work fine without the braces.

let inline (+>>) l o = Compose.lens l o
let noBracesNeeded = data |> "some string" ^= bar_ +>> stringField_

I went with +>>, because the >> implies composition. The + is mostly just to set the predecence higher. For the prism, we could go with +?>>.

I do think that if we remove the braces around the compose lenses, then flipping the operator order for ^= and ^% makes things read significantly better.

let simplest = data |> bar_ +>> stringField_ ^= "some string"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants