Deprecate Foldable for Either

Anthony Clayden anthony_clayden at clear.net.nz
Fri Mar 24 09:17:45 UTC 2017


> On Thu Mar 23 15:03:36 UTC 2017, Edward Kmett wrote:

> > On Thu, Mar 23, 2017 at 6:18 AM, Anthony Clayden wrote:
> > 
> >      Why is `[a]` hard-coded in the signature for
> >      concat? I would expect anything specific to Lists
> >     to be genericised:
> >     concat :: (Foldable t1, Foldable t2) => t1 (t2 a) ->
> > t2 a
> >
> 
> Foldable can't be used to 'construct' in this way. 

Thanks Edward for the comprehensive reply.

Yes I know Foldable isn't powerful enough to construct.
I wasn't seriously proposing that as the signature.

I was pointing out that there were several value judgments
in arriving at the FTP changes.
The decision has gone different ways in different places.
It's not all as predictable by cold logic
as you're trying to make out below.

And you've left people surprised.
FTP left `concat` hard-coded to Lists.
It left `map` hard-coded to Lists.
Why didn't it leave `length` hard-coded to Lists?

The promise with FTP was to not break code,
and for code that already compiled to continue to work
with the same behaviour. Mostly that's been delivered.

The counterpart hasn't been delivered:
inappropriate uses of some methods
(which therefore didn't previously compile -- good)
do now compile, and whatever they calculate
is a surprise/non-intuitive for a significant number.

To my intuition, "length" -- as an English word --
 is about structures that have length.
I can see the benefit you point out below
for having a generic method for size of a Foldable.
Most of those Foldables I don't see as having "length".

> Neither Foldable f nor even Traversable f give you the
> power to construct a new 'f' with different shape.
>

Exactly. So why even bother with
concat (Right [...]); or concat (Just [...]) ?
 
> 
> concat is just a type restricted version of fold = foldMap
> id provided basically for legacy compatibility.
>

OK. It's arbitrary but your justification is it was always
arbitrary.
FTP `concat` does the same as pre-FTP `concat`.
"For legacy compatibility".

By that same argument:
pre-FTP `length` wasn't even in Foldable.
It was arbitrarily restricted to Lists.
"For legacy compatibility" it should have stayed restricted
to Lists.
 
> 
> The Foldable/Traversable proposal was to bring the
> functions that already existed in base in Data.Foldable
> into the Prelude and eliminate the monomorphic versions of
> those combinators that made importing these more general
> versions painful for users.

`length` was never in Data.Foldable.
There was never a more general version.
You're blowing smoke.


> We didn't set out to make new
> functions, merely standardize on the ones folks had been
> using for a decade. concat was left intact, because there
> was already a generalization available, and no particular
> reason to break all the existing code that expected it.
> 
> >    Why have an instance of Foldable which always returns
> >     length 1?
> >      (Or for some instances returns length 0 or 1.)
> >
> 
> Say you go to write a function
> 
> toVector :: Foldable f => f a -> Vector a
> toVector xs = Vector.fromListN (length xs) (toList xs)
> 
> With length in Foldable, ...

No. Length was not in Foldable.
You should have stopped to ask why!

You give good reasons for having a method in Foldable
that consistently gives a size.
Those are not good reasons for calling that method `length`
or for breaking expectations that `length` applies for
Lists,
Not for Foldables.

> 
> A number of container types can use 'length' rather than
> having to supply their own monomorphic size function.
> Would 'length' have been better called 'size'?

Yes! Or `cardinality`.

> That is another color the bikeshed could have been
colored,

That's an arrogant comment.
You've allowed mopeds, motorbikes and skateboards
into the bikeshed. And now there's not enough room for the
bikes.
Now you blow smoke that it's only about the colour of the
shed.

> but it would have involved taking a fresh name, possibly
in the
> Prelude, and the name collisions of a common name with
> existing code was considered to be the greater evil.

Data.Set has `size`. It used to have `cardinality`, that was
removed.
OK not the Prelude, but close enough.
`size` in Data.Set does exactly what `length` now does.

> 
> > `concat` and `length` should not be in Foldable.
> > They should be in a separate class `Consable` (say),
> > which would be a sub-class of Foldable.
> >
> 
> length being in such a class would mean that every author
..

Would use a sensibly-named method (`size`) when they wanted
the, er, size of a Foldable.
And using `length` would document the code
that they were applying to something that might be lengthy.

> ... This would have also
> meant dumping a brand new abstraction in Prelude without
> the preceding decade worth of experimentation on what
> works well.

As it is, we've got what?
A brand new abstraction (called `length`) in Foldable
without a preceding decade worth of experimentation
on whether length makes sense for Either or Maybe.
Furthermore without a preceding decade worth of telling
people
that length [1, 2] is 2;
but length (1, 2) is 1.

> In general the FTP didn't seek to go out of
> its way to make up new classes, merely to standardize
> existing code ...

You're blowing smoke again.
There was no existing code using `length`
of a Foldable, because `length` wasn't a method.

> 
> While working on the Foldable/Traversable Proposal what
> happened was we found we needed to add a number of methods
> to the Foldable class to avoid silent changes in the
> semantics of existing Haskell programs. Some Foldable
> combinators folded in different directions than their
> monomorphic counterparts.
> 
OK. How well communicated was that?

It certainly couldn't have applied for `length`.
The semantics of existing Haskell programs
was that `length` worked for Lists.
Only for Lists. Not Foldables in general.

> Along the way as we worked to fix these infelicities and
> noticed that as a side-effect that this allowed Foldable
> authors some power to execute these operations with better
> asymptotics where possible for their containers. This nice
> knock-on effect lets folks shed some names that they were
> taking from the environment by using what Prelude offers.
> During this process some folks noticed that length/null
> fit into the scheme,

Well those folks were wrong.
What they should have noticed was that `size`/null fit.

> ...
> 
> With the choices made all of the "mainstream" base modules
> now have no name conflicts and can be imported
> unqualified.

Good. I am not criticising the FTP change in general,
nor its objectives.
But moving `length` from Prelude to Foldable
isn't justified on those grounds.
There wasn't previously a `size` (or equivalent) in
Foldable.
Why introduce it when there was no experience of
"using for a decade" -- if that was the criterion?

> 
> Could we have named them flength (or size) and fnull so
> that people had to ask for them explicitly and left
> length/null alone? Yes. But it would have meant taking new
> names from the Prelude or not re-exporting them from
> Data.Foldable, and the AMP/FTP tried to very careful about
> introducing any new names to the Prelude, and wanted users
> to be able to supply instances without having to
> explicitly import Data.Foldable.
> 
> We were very dubious about the response we'd get
> introducing new, untested, names to Prelude ...

So you preferred to introduce new, unattested behaviour.

`length` of an Either is unattested.
`length` of a Maybe is unattested.
That `length` of (1, 2) is 1 is unattested.

> as everyone's code is impacted by that choice 

Again, no: nobody's code could have been using
Foldable length.

> and folks happen to be using all the "good" names for such
things,

Yes that's a problem.

> and nobody had done so in the preceding 17 years,

Because they couldn't. Because `length` applied only for
lists.

> so any changes along
> those lines are surprising.
> 

So do you think it unsurprising asking for the length of a
Maybe?
Do you think it unsurprising that the length of (1, 2) is 1?

Note: "length", not "size".

So did it come as a surprise that people are surprised?

I'm not surprised newbies are surprised.
They're using tutorials saying length applies for Lists.
And concat applies for Lists of Lists.

It seems to be not just newbies surprised,
judging by how often the question comes up.



AntC


More information about the Libraries mailing list