-
Notifications
You must be signed in to change notification settings - Fork 211
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
Adding higher-order type constructor to dart #1655
Comments
Most likely it would be possible to support higher-kinded type parameters in Dart. I'm not sure about the implications for optimization opportunities (support for higher-kinded type parameters might prevent certain optimizations from taking place), and it might well be a lot of work to implement it, so we'd need some very good use cases. ;-) There are some conflicts with Dart of today as well: For instance, generic types are considered to denote their "default" instantiation when no type parameters are passed. So with |
@eernstg in my case I was trying to implement a functional programming package based on cats. I had some problems in modeling the Foldable class without higher-kinded type. Based on the Language funnel, there seems to be many requests to support functional programming features in dart (Patterns, Multiple return values, Destructuring). Higher-kinded types would be another step in this direction. |
I may be a bit confused, so just to confirm, this is what I think you want to see (just without the errors, of course): /// T can be List, Set, or any other iterable, but we don't care about the actual elements.
/// We care more about what type of iterable we're talking about than an actual iterable object
abstract class Foldable<T extends Iterable> {
// Error: The type T is defined with 0 type parameters,
// but 1 type arguments were given.
B foldLeft<A, B>(T<A> iterable, B initialValue, B transform(B, A));
}
void main() {
Foldable<List> fold1;
// This is what I'm assuming you want to do.
int result1 = fold1.foldLeft([true, false], 0, (int left, bool right) => left);
// Error, since iterable has to be a List, not a Set.
int result2 = fold1.foldLeft({true, false}, 0, (int left, bool right) => left);
// Not an error, but it should be, since we want to enforce a List<bool>
int result3 = fold1.foldLeft([1, 2, 3, 4], 0, (int left, bool right) => left);
} Assuming the above is accurate, I'll go on. My first thought was "why have a T at all, if all you care about is an iterable?": abstract class Foldable2 {
B foldLeft<A, B>(Iterable<A> iterable, B initial, B transform(B, A));
} It occurred to me that you may have more methods like abstract class Foldable3<E> {
Iterable<E> iterable;
T foldLeft<T>(T initial, T transform(B, E));
/// Will use the same type as [foldLeft] since they both use the same [iterable] object.
T foldRight<T>(/* ... */);
} But, if you really want to use this as a container class and really don't need the same instance but also really do need the same type of iterable, then I don't think that's possible. In general, what you're trying to do is this: abstract class Foo<T> {
E experiment<E>(T<E> object);
} You can't guarantee that T can accept E as an argument -- imagine your /// Works with any numeric type
class MyNumericCollection<T extends num> { }
abstract class Foldable4<T> { // let's imagine this doesn't throw an error, like you're asking
B foldLeft<A, B>(T<A> iterable, B initialValue, B transform(B, A));
}
void main() {
Foldable4<MyNumericCollection> foldable = Foldable4<MyNumericCollection>();
foldable.foldLeft<int, bool>(MyNumericCollection<int>(), 0, (int left, bool right) => left); // A = int, B = bool
// Error, since MyNumericCollection can't accept a bool, but Foldable4 has no way of knowing that,
foldable.foldLeft<bool, int>(MyNumericCollection<bool>(), true, (bool left, int right) => left); // A = bool, B = int
} In other words, it's not safe to be able to apply generics to any type, because that type may not accept generics, or it may require a certain subtype as its generic, none of which can be known in advance. Unless you're asking for syntax to require "a class that can accept any other type as a generic". |
We'd need to have a full kinding system added to the Dart type system in order to handle higher-order type parameters properly. The simplest non-trivial kind is class C<X extends \x.Iterable<x>, Y> {
X<Y> xs;
C(this.xs);
Iterable<Y> get iterableXs => xs; // OK, we'd have `X<Y> <: Iterable<Y>`.
}
void main() {
C<\x.List<x>, int> c = C([1, 2, 3]); // OK, we'd have `\x.List<x> <: \x.Iterable<x>`.
List<num> ints = c.xs; // OK, because `c.xs` has type `List<int>`.
} It's a whole new dimension in the type system, and it's going to introduce a new set of cases to consider for every other part of the type system. I'm sure it would be possible, but it would also require some really good use cases. ;-) For now, we might also want to keep in mind that these more sophisticated kinds of typing discipline can usually be replaced by a less precise typing: We will need to accept some casts here and there (where proper higher-order types might have given us full compile-time type safety), but in return we avoid a rather substantial amount of complexity. |
While working on a functional programming package for dart I found that dart does not support higher-order type constructors (higher-kinded type).
For example, a typical
Foldable
typeclass expects a generic parameterF
that itself can have another generic parameter.In scala, it is already possible to do that with the following syntax:
As a concrete example, the type
F
can be aList
and[_]
means that theList
can itself accept any type (e.g.List<int>
). This feature allows defining functions like the following:If
F
isList
then:This is not possible currently in dart. The
fa
parameter cannot itself accept another generic parameter.A workaround would be to define two generic types on the same class like in the following example:
In this example, the return type is a generic
IList<dynamic>
, since it is not possible to statically define a type parameter of another generic type.Is it possible to implement this feature in the dart language?
The text was updated successfully, but these errors were encountered: