Of course it is. Map's type is "(a -> b) -> [a] -> [b]". D just absolutely and completely failed here, despite this being a solved problem 40 years ago.
Of course it is. Map's type is "(a -> b) -> [a] -> [b]". D just absolutely and completely failed here, despite this being a solved problem 40 years ago.
Which should have a type.
>and returns a type that iterates through that range
Which should have a type. The entire point is that this is a solved problem, there is no excuse to simply throw up our hands and say "screw documentation we'll just say this function is a mystery".
Functor f => (a -> b) -> f a -> f b
And please don't miss the point and tell me D doesn't have Functor. The entire point is that D has something, and it doesn't tell us what that something is. It should. Documentation is good.
Or rather, D doesn't have concepts (of which 'Functor' is a special case); that is, the notion of a type that is characterized by having the ability to execute operations is not expressible in its typesystem.
Or rather, it is, but only with classes. You want something like "a return type; fulfilling the condition of being able to be used in this way." This is not something you can specify as a function attribute in D. Instead, ranges use a form of duck typing. The next step in the call chain can tell whether the previous step gave it something it can use using template inconditions, ie. `isInputRange!T`. But the previous step can't assert that it is returning a type that fulfills a constraint. In other words, there's type inconditions but not type outconditions.
It's simply a failure of D the language/compiler (and a huge anti-pattern) to not expose internal types in a way that can be displayed to the programmer.
ceylon could, but they are barely readable anyway.
It does. That'd the `Range` here: https://dlang.org/phobos/std_algorithm_iteration.html#.map.m...
> > and returns a type that iterates through that range > Which should have a type.
It does. But the name of that type depends on the type of the range and on the callable.
> Functor f => (a -> b) -> f a -> f b
This doesn't work because the return type isn't `f b`, it's `g b` where g depends on what f is. It also depends on the callable, because the first parameter isn't necessary a function. The closest is
Callable c, Range r0 => c a b -> r0 a -> r1 b
Where `r1` isn't even a concrete type but a type that depends on both `c` and `r0` and is made up on-the-fly (per instantiation).
> Documentation is good.
I agree. How would you suggest improving the signature of map given that D doesn't have typeclasses? Or with types that depend on other types in the template?
is how you would define that class of types in Haskell. It says "If g is a range, then a pair of types f and g satisfy the FunctorTo interface[1] when knowing f determines g, and there's an implementation of fmapto with this type".
Maybe D needs typeclasses. This thread has certainly put me off of D, because being able to write down types is really quite important to me.
[1] The Haskell class keyword is defines something closer to an interface than an OO class.
The issue arises only with generic heavily templated functions. Nothing in D forbids you to write your programs with all types explicitly written down. That's btw how I mostly write my code.
That should not be a problem. It is a problem in D because of a lacking in D.
>How would you suggest improving the signature of map given that D doesn't have typeclasses?
The language needs fixed so it can express its own types.
It is not a problem, the compiler copes with it. The problem comes from the fact that such a type is absolutely not interesting to know how it is written. The unmangled type is unreadable.
When the return type actually matters, auto should be avoided unless there's no way around it. But that's why we have "Returns:" in Ddoc. The function signature itself is not the complete documentation. I mean, you're acting like all D functions are documented to return auto. They aren't. It's used where it needs to be.
The language expresses its types just fine (it's in the mangled name in the object file). The issue is that there is no point in the human readable form of these types.
Functor f => (a -> b) -> f a -> f b
Functor f => (a -> b) -> f a -> f b
Seems like you had some deep exposure to Haskell, ML or Hindley-Milner in general which, when excessively consumed, detaches from reality.
For one reason or the other you take this discussion serious and personal.
auto map(auto x) {
if constexpr(is_same<decltype(x), int>) {
struct T1 { int getStuff() { return 0; } };
return T1 {};
} else {
struct T2 { void doStuff() { } };
return T2 {};
}
}Ahh.. welcome to computer "science", the ever repeating cycle of 'inventions'