On Wed, Jul 24, 2013 at 1:48 PM, Jonathan S. Shapiro <[email protected]>wrote:
> what I'm saying is that *because the selected instance is an orphan*, we
> should instead give this function type as:
>
> sortR :: Ord R ~ TheOrphanedOrdRInstance => R[] -> R[]
>
That is: this is a procedure that sorts something of type R[] *provided* the
> caller agrees with the choice we made about the orphaned instance
> resolution. We've documented that choice in the interface, and it's up to
> you whether to use it or not.
>
Why this is necessary or even valuable?
Presumably any function R[]->R[] can use any amount of code, and call any
number of other statically resolved orphaned functions as part of how it
achieves it's result. Why would they be named in the type? Why do the
caller and the function have to agree about any of those blocks of code
used to satify the goal of SortR?
As far as I can see, the use of the orphaned Ord R has no affect on the
type or form of R[], only the meaning of "SortR" and its behavior, which is
only understood by humans.
If it was valuable to agree on the Ord implementation, presumably we would
be using a version of sort which parameterized the ord-comparator itself.
Forgive my C# and it's verbosity...
delegate T OrdFn<T>(T a,T b);
List<T> sort<T>(List<T> input, OrdFn<T> fn) { ... }
This runs smack into a major common problem in language and runtime
>> design, which is that we overwhelmingly favor the pattern of
>> named-impementation-factory when in most cases
>> conforming-implementation-factory is not only sufficient, but superior.
>>
>
> I haven't heard those two terms before. Would you be kind enough to
> educate me about them?
>
It turns out my made-up terms were too succinct to be clear.
I'm referring to the prevalence with which we encourage/allow types and
allocations to be specified by specific instance names, when in most cases
using interface (or type-class) and some form of factory would be superior.
That is, the common way to author a sort function will return a list
implementation decided by the sort function, not by the caller.
Of course languages do not prevent us from authoring better solutions..
such as mirroring input types, using type-paramaters, or accepting factory
function parameters. However, I argue that languages are often encouraging
us to do the wrong thing by the mere-fact that the briefest solutions are
often the most constrained, while the most flexible solutions are the most
verbose.
Consider this tour of options for sort() in a C#/Java-ish:
// here we are unnecessarily bound to the List implementation
List<T> sort<T>(List<T> input) where T : IComparable<T> {
List<T> output = new List<T>();
// do something to produce a sorted version of input
return output;
}
// here we are not bound to the list implementation, but we produce only
List
ICollection<T> sort<T>(ICollection<T> input) where T : IComparable<T> {
List<T> output = new List<T>();
// do something to produce a sorted version of input
return output;
}
// here we are flexible and mirror the input list type, which may or may
not be desired
ICollection<T> sort<T>(ICollection<T> input) where T : IComparable<T> {
List<T> output = new List<T>();
// do something to produce a sorted version of input
return output;
}
C sort<T,C>(C input) where C : ICollection<T>, new() {
var output = new C ();
// do something to produce a sorted version of oinput
return output;
}
_______________________________________________
bitc-dev mailing list
[email protected]
http://www.coyotos.org/mailman/listinfo/bitc-dev