Lysxia / first-class-families

First-class type families
https://hackage.haskell.org/package/first-class-families
MIT License
86 stars 12 forks source link

Lifted Infix Operators #57

Open BebeSparkelSparkel opened 4 weeks ago

BebeSparkelSparkel commented 4 weeks ago

I have found it useful to have lifted infix operators to reduce the amount of parentheses and Evals. For example:

type List = Eval (Map SomeFunction '[SomeTypes]) ++ Eval (Map SomeFunction '[SomeTypes])

becomes

type List = Map SomeFunction '[SomeTypes] ^++^ Map SomeFunction '[SomeTypes]

This reduces a lot of noise in the expressions.

Is there a way to the existing operators with Exp wrapped parameters in an infix fashion?

If not, is wrapping the operator with ^s a good naming strategy?

Lysxia commented 3 weeks ago

There was a similar discussion here: https://github.com/gspia/fcf-containers/issues/15

In hindsight it might have been preferable to have the lifted operators by default (i.e., give them the normal names) so that we could write expressions without a lot of Eval. I'm in favor of adding the lifted operators somewhere, but not 100% sure what's the best way to go about it.

  1. What you suggest is to add the lifted operators with a special naming scheme (^++^ is the lifted ++). We can also add lifted functions like CompareE as the lifted Compare. Pro: Backwards compatible. Con: If those are going to be the most used names, it's a shame to mangle them.
  2. We could rewrite the whole library to export lifted functions by default (i.e.., redefine ++ to be ^++^ in your proposal). But this breaks backwards compatibility.
  3. Another backwards compatible solution is to create another set of modules (call them Fcf2 or FcfLifted) so we can reuse the simple names.

Option 3 sounds preferable to me. Would you agree? Other suggestions are welcome.

BebeSparkelSparkel commented 3 weeks ago

I like what @snoyberg did with mono-traversable and his Data.MonoTraversable.Unprefixed where the functions from Data.MonoTraversable are renamed to conflict with base. This allows the user to choose to use the non-conflicting prefixed names from Data.MonoTraversable or the conflicting names from Data.MonoTraversable.Unprefixed.

So, I would prefer your 1 and 3.