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

F# C# lens library #1

Open
wallymathieu opened this issue Apr 25, 2020 · 6 comments
Open

F# C# lens library #1

wallymathieu opened this issue Apr 25, 2020 · 6 comments

Comments

@wallymathieu
Copy link

Hi! I've found the need for for a lens library usable from both c# and f#.

Fshapx extras has one implementation I've duplicated for c# usable lenses in with but with a different focus.

Could we cooperate on some approach? Would it make sense to write an RFC for f#+ to include c# compatible lenses?

@polytypic
Copy link
Owner

polytypic commented Apr 25, 2020

Hi!

Like is mentioned in the README, I've written a C# version — for reasons we are using C# 7.3 and .NET Framework 4.7.2 — of the same technique, but it is part of a proprietary code base. I notice now that the wording in the README might be slightly misleading when it says "can also be implemented and used in C#". What I mean is that one can implement the same approach in C# and have a usable optics implementation in C#. The C# version is written with only C# usage in mind, so it uses a delegate type for optics:

delegate OpticPipe<S> Optic<S, A>(OpticPipe<A> pipe)

Ideally that should be just a type alias for a Func, but there are no parameterized type aliases in C# 7.3 and using a Func one would have to write the type open:

Func<OpticPipe<A>, OpticPipe<S>> // Too verbose.
Func<O<A>, O<S>>                 // If OpticPipe is renamed to O.  Still ugly, IMO.
Optic<S, A>                      // Oh well.

You could also use the same delegate type for optics in F#, but then you'd lose the ability to use the standard << operator for composing optics. OTOH, using the F# function type from C# would be verbose (lack of parameterized type aliases). Perhaps there is some way to get a compromise that is usable from both C# and F# at the same time — perhaps via some type conversions on the C# side (conversion from F# function to a suitable wrapper on the C# side).

...

@polytypic
Copy link
Owner

...

By F#+, do you mean the FSharpPlus project? I think the goals of that project are somewhat incompatible with this approach. It already has an optics implementation that heavily builds on the overloading machinery of F#.

There are various pros and cons to each approach to optics. Nice things about the approach in this repo are that it gives you fairly flexible optics (isos, lenses, prisms, traversals) represented as standard functions (without really any type level wizardry) and allows using standard function composition for composing optics. Implementation can also be fairly efficient, compact, and straightforward. On the other hand, this approach does not distinguish between the optic kinds at the type level and does not support applicative traversals (like e.g. F#+ version or a higher-kinded encoding).

TBH, I don't have interest in spending time polishing open-source libraries at the moment. I've spent many years of my free time on such things already. Creating a quick demo/prototype like this repo for learning/knowledge transfer purposes is quite different. However, I can certainly try to help if you want to pursue implementing some sort C# <-> F# interoperable optics using this approach.

@wallymathieu
Copy link
Author

Thanks for the answer! I'll try to understand this approach more fully since it looks interesting.

@gusty
Copy link

gusty commented Apr 26, 2020

Nice things about the approach in this repo are that it gives you fairly flexible optics (isos, lenses, prisms, traversals) represented as standard functions (without really any type level wizardry) and allows using standard function composition for composing optics.

Also the F#+ implementation allows using standard function composition for composing optics.

@polytypic
Copy link
Owner

Also the F#+ implementation allows using standard function composition for composing optics.

Yes, it is very cool!

I came up with this technique, because we had to use C# 7.3. This F# version is really for learning/knowledge transfer purposes. I haven't seen anyone describe this approach before (someone might have, but I haven't seen it) and it seems to strike a very attractive compromise. I also believe this approach could be implemented in quite a few mainstream languages, which is a large part of why I made this repo public.

@gusty
Copy link

gusty commented Apr 27, 2020

@polytypic for your information, F#+ use a lightweight SRTP overloaded functor for the current lenses implementation, by using the knowledge that no functor for primitive types is needed.

When I simplified the implementation to that, I also did a zero-srtp implementation, using interfaces, the branch is here: https://github.com/fsprojects/FSharpPlus/tree/light-lens it was an early exploration, but in the end I decided to go with the current light srtp implementation as it works very fast at both compile and runtime.

Of course, things get more complicated with traversals, there you need bi-generic functions I see no other way other than restricting traversals to specific traversables of a specific applicative otherwise.

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

3 participants