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

Ben Franksen ben.franksen at online.de
Fri Oct 1 01:42:39 UTC 2021


Am 17.09.21 um 07:15 schrieb Michael Turner:
> I might have missed your link to "Monoid" because my attention fell on
> "monoid mappend". Sorry for that.
> 
> "The contribution of each element to the final result is combined with an
>     accumulator via an /operator/ function.  The operator may be explicitly
>     provided by the caller as in `foldr` or may be implicit as in `length`. In
>     the case of `foldMap`, the caller provides a function mapping each element
>     into a suitable 'Monoid', which makes it possible to merge the per-element
>     contributions via that monoid's `mappend` function."
> 
> This is a little better, but I'd write it this way, I think.
> 
> "Folds take operators as arguments. In some cases, it's implicit, as
> in the function "length". These operators are applied to elements when
> lazy evaluation requires it, with a fold 'accumulator' as one of the
> operands. 'foldMap' uses a function (implicit? explicit?) that maps
> elements into . . . ."

The problem you two are both facing is this: you want to describe, 
abstractly, generally, the common principle behind an ad-hoc 
lumped-together set of functions. This is very likely to result in 
contortions and provides you with no insight.

You need to realize that these methods are all simple specializations of 
two or three basic functions. The only reason they are methods of the 
class is to allow specialized implementations for optimization.

Foldable is a very bad example to learn from. IMO its documentation 
should only describe 'toList', define foldMap and fold in terms of foldr 
or foldl, and otherwise refer you to the functions in Data.List. These 
are documented in simple terms.

The best description for foldr I have ever come across is this: "foldr f 
z l replaces in the list l the data constructors [] and (:) with z and 
f, respectively." Once you understand the list data type and remember 
that (:) is right associative, this makes foldr totally obvious. Left 
folds are a bit less immediately intuitive as they go against the 
"natural" associativity, but you can think of foldl as being the 
analogue of foldr for "snoc" lists (lists with cheap addition of 
elements at the right end), but implemented for normal lists.

Once you understand that, everything else are trivial specializations, 
such as

   sum = foldl' (+) 0

The only real subtlety is foldl vs. foldl' i.e. lazy vs. strict. This is 
quite difficult to understand, as it requires to go pretty deep into the 
evaluation model of Haskell, but for a beginner it suffices to know that 
you probably want to use foldl'.

Once you understand how folds and their various specialisations work for 
lists, generalizing that knowledge to Foldable structures is trivial: 
just think

   Data.Foldable.foldr f z l = Data.List.foldr f z (toList l)

etc.

Cheers
Ben
-- 
I would rather have questions that cannot be answered, than answers that
cannot be questioned.  -- Richard Feynman




More information about the Haskell-Cafe mailing list