Description
Using present given syntax, it's a bit awkward to define conditional given instances:
given listOrd[T](given Ord[T]): Ord[List[T]] ...
It's worse in the anonymous case:
given [T](given Ord[T]): Ord[List[T]] ...
and even worse in the monomorphic case:
given (given outer: Context): Context = ...
Context bounds can help avoid many cases where a given
parameter would be needed but
they do not work in all situations, e.g. they don't work if the typeclass in question has more than one parameter.
Going with the "intent over mechanism" motto, it would be nice if there was specific syntax for
conditional givens. Here's a proposal to fix the three use cases:
given listOrd[T]: Ord[T] => Ord[List[T]] ...
given [T]: Ord[T] => Ord[List[T]] ...
given (outer: Context) => Context = ...
The new syntax reads much better: "given Ord[T]
implies Ord[List[T]]]
...".
An immediate concern is that this looks too much like we implement a function type. Yes, but
- in a logical sense, providing an instance of a function type is equivalent to providing a conditional instance (by modus ponens)
- there's precedent, where we use
=>
also in cases and self-types - in all these cases one can still implement a real function type by putting it in
(...)
.
A separate question is whether in that case we would still support the old syntax with given parameters in instances. My vote would be no, let's have a single way to define things.
I believe that the new syntax also alleviates a concern people were having about the dual use of given
as a provider and a consumer. In a sense that dual use is inevitable since given parameters are both consumers and providers. But it's still a concern if given
's with different meanings are used next to each other. With the new syntax, this is no longer possible since "providers" (i.e. given instances) don't contain anymore "consumers" (i.e. given parameters) in their clauses.