[Haskell-cafe] Haskell's "historical futurism" needs better writing, not better tools

Viktor Dukhovni ietf-dane at dukhovni.org
Fri Oct 1 01:14:36 UTC 2021


On Fri, Oct 01, 2021 at 02:40:49AM +0200, Ben Franksen wrote:

> > I am also curious whether I'm part of the solution or part of the
> > precipitate.  I've recently contributed new documentation for
> > Data.Foldable and Data.Traversable:
> > 
> >      https://dnssec-stats.ant.isi.edu/~viktor/haskell/docs/libraries/base/Data-Foldable.html#g:7
> >      https://dnssec-stats.ant.isi.edu/~viktor/haskell/docs/libraries/base/Data-Traversable.html#g:4
> > 
> > are these a step in the right direction, or examples of more writing
> > that sucks?
> 
> Sorry, but IMO it sucks.

The main goal of the overview was to help users to be able to reason
about the behaviour of the class methods, and be able to choose the
correct one of (foldr, foldl, or foldl') without forcing an entire list
into memory or needlessly generating a long list of lazy thunks.

So I don't think that just saying "toList", done quite does the job.

That said, given that there are surely sections of prose that could
be better, would you care to submit diffs for inclusion in MR 6555?

    https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6555

you can check out the branch, and send me diffs?  Or is it sufficient
to change just the particularly egregious sentences you noted?

> They define semantics in a semi-formal notation, which I find succinct 
> and very intuitive. This can be easily generalized to Foldable via 
> 'toList'. Indeed, there is almost nothing about Foldable that cannot be 
> understood once you understand Data.List and the toList method. Even 
> foldMap is (semantically) just (***):

Well a balanced Tree can have an efficient corecursive foldl, or a
performant 'foldr`', and Sets can know their size statically, and `elem`
runs in linear time even in structures that potentially support faster
search.

And it is perhaps worth asking whether you feel you still have anything
you'd like to learn about Foldable, for if not, perhaps the
documentation is not for you, and that's fine...

> In fact all class methods have simple semantic definitions in terms of 
> the same named functions from Data.List via 'toList'.

But performance may differ radically, and `toList` may diverge for
`snocList` when infinite on the left, though that's a rather
pathological example.

> Expectations of runtime cost should be either explicitly stated in the 
> docs for each method or left out.

That's not enough if users can't reason about the available choices or
don't know how to implement performant instances.  Function synopses
rarely provide enough room for more than a cursory description and
a few examples.  That's not their role.  This is why Unix manpages
have both a SYNOPSIS and a DESCRIPTION section.

I am quite open to improved language in the overview, and less open to
the idea that it is just baggage to throw overboard.  In particular,
I've had positive feedback on the material, despite perhaps overly
turgid prose in some places.  Please help to make it crisp.

I find absence of overview (DESCRIPTION if you like) sections in many a
non-trivial Haskell library to be quite a barrier to working with the
library, the synopses alone are rarely enough for my needs.


> The most important documentation for a class, its laws, is (1) not 
> contained in the class docs, (2) not even linked from there, and (3) too 
> cryptic.

The links are fixed in MR 6555, and I've asked David Feuer to contribute
prose to clarify the laws, I also find them rather opaque, and left them
as is when I wrote the overview.  This is a good opportunity to address
issues with the laws.

> I would *at least* expect the Monoid newtype wrappers (Endo, 
> Dual, Sum, Product) and their inverses to be hyperlinked to their 
> definition.

Agreed, and some sort of explanatory text...  These are inherited
from earlier versions of the module which had only the laws and
no overview.

> I may be wrong but it looks to me as if this could be derived by adding 
> one more method 'fromList' that is required to be left inverse of 'toList':
> 
>    fromList :: Foldable a => [a] -> t a
>    fromList . toList = id

This is roughly the sort of thing one can do with Traversable (recover
the structure from its spine and element list, but not its element list
alone).  The point is that various non-linear (e.g. tree-like)
structures with the same element order have distinct "spines".

> Of course, for some Foldables (e.g. those with a fixed finite number of 
> elements), fromList would be partial.

And not well defined without a `t ()` spine into which the elements can
be inserted.

> Is there a sensible (useful, lawful) Foldable instance which has no 
> 'fromList'?

Sure, any tree-like structure where shape is not implied by the element
list alone.

> I suspect no. In fact I suspect addition of fromList (with the left
> inverse law) would nicely serve to rule out useless/surprising
> instances.

While I don't love harsh critiques, I do recognise that a harsh
criticism can be an source of energy that can be harnessed to good ends.
Therefore, if you're willing to apply that energy to improving the text,
I'd love to work with you.  If you feel the document is beyond repair,
I'll be disappointed, but I'm willing to accept that.

Thanks for taking the time to look it over.

-- 
    Viktor.


More information about the Haskell-Cafe mailing list