FSharpPlus icon indicating copy to clipboard operation
FSharpPlus copied to clipboard

Use strict types for applicatives

Open gusty opened this issue 6 years ago • 5 comments

This will switch to use the internal technique of ~~tupling~~ wrapping in order to avoid flexible types in overloads for the Applicative dispatcher.

Right now there are 2 issues:

  • Types implementing IEnumerable<_> would default to the seq<_> instance. This might be arguably desired.

  • Types implementing IEnumerable<_> would default to the seq<_> instance, even if they implement their own applicative instance. This is not acceptable.

gusty avatar Dec 07 '19 18:12 gusty

I tested with https://github.com/fsprojects/FSharpPlus/pull/207/commits/fea4b08e8ddb8ddce36da264a6b53d07b8fe4d8d but it seems to failing to redirect.

Microsoft (R) F# Interactive version 10.2.3 for F# 4.5
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> open FSharpPlus.TypeLits;;
> let v = vector ((fun i -> i + 1), (fun i -> i * 2));;
[<Struct>]
val v : Vector<(int -> int),S<S<Z>>> = [|<fun:v@2>; <fun:v@2-1>|]

> let u = vector (2, 3);;
[<Struct>]
val u : Vector<int,S<S<Z>>> = [|2; 3|]

> v <*> u;;
[<Struct>]
val it : Vector<int,S<S<Z>>> = [|3; 6|]

> open FSharpPlus;;
> v <*> u;;
val it : seq<int> = seq [3; 4; 4; 6]

cannorin avatar Dec 09 '19 07:12 cannorin

Another update. The other techinique that can be used in place or combined with wrapping is to add a higher DefaultX marker to the interface overload, the problem here if I do that is that type inference gets worst when resolving to those overloads and needs type annotation. This is currently a noticeable problem with the monad overload. I'm coming to the conclusion that if there's no way to solve that type inference problem, a good compromise would be to let interfaces type inference degrade, that problem is preferred to not having external instances being resolved, but it would clearly be a breaking change.

gusty avatar Dec 12 '19 08:12 gusty

This is passing now, but there are some breaking specially in the idiom brackets section. Also the Apply instance for KeyValuePair is removed.

Now, if we put in the balance this regression against not having externally defined applicatives implementing interfaces working decently (namely something along a plain f <*> x <*> y) it should be clear that this is priority.

How we rollout this change? Possibly we would have to skip a 1.1 version and move directly to a 2.0

The open question is whether this could be improved in order minimize the regression. I spent a crazy amount of time looking at this, if I add the time accumulated in fighting applicatives it's probably the time required to fix the F# compiler to make them work properly for once.

If I have more time, I will keep trying, but otherwise this would have to be merged.

Thoughts?

gusty avatar Dec 15 '19 19:12 gusty

It's working now!

Microsoft (R) F# Interactive version 10.2.3 for F# 4.5
Copyright (c) Microsoft Corporation. All Rights Reserved.

For help type #help;;

> open FSharpPlus.TypeLits;;
> let v = vector ((fun i -> i + 1), (fun i -> i * 2));;
[<Struct>]
val v : Vector<(int -> int),S<S<Z>>> = [|<fun:v@2>; <fun:v@2-1>|]

> let u = vector (2, 3);;
[<Struct>]
val u : Vector<int,S<S<Z>>> = [|2; 3|]

> v <*> u;;
[<Struct>]
val it : Vector<int,S<S<Z>>> = [|3; 6|]

>  open FSharpPlus;;
> v <*> u;;
[<Struct>]
val it : Vector<int,S<S<Z>>> = [|3; 6|]

I suppose very few people seriously uses idiom brackets, so these breaking changes are acceptable. Since we are introducing big changes such as #185 and #192 and other breaking change #205 I think it is better to move to 2.0 skipping 1.1.

cannorin avatar Dec 16 '19 04:12 cannorin

Thanks for your feedback. #185 and #192 are not minor things, but at the same time they don't break anything.

Regarding #205 it's not breaking 1.0 since it didn't exists at that time.

So far this is the first serious reason to break 1.0, however I can think of other upcoming breaking changes:

  • A new ListT monad transformer I have on drafts, that won't be compatible with the existing one.

  • A redesign of the computation expression without the "autosense" functionality which users of this library have demonstrated it works only on certain scenarios and create more confusion than other thing.

gusty avatar Dec 16 '19 07:12 gusty

Continued in #569

gusty avatar Nov 23 '23 08:11 gusty