
Very interesting! What do you mean by a "better" unfold?
On Fri, Jul 21, 2017, 13:06 MarLinn
On 2017-07-21 17:57, Kim-Ee Yeoh wrote:
Another perfectly cromulent definition is:
untilNothing f = fromJust . last . takeWhile isJust . iterate (f =<<) . Just
This has 2 advantages:
1. It illustrates the haskellism that "A list is a loop is a list." 2. It composes much-beloved list combinators into a reasonable pipeline.
Note that
fromJust . last . takeWhile isJust . iterate (f =<<) . Just ≡ last . catMaybes . takeWhile isJust . iterate (f =<<) . Just
Note further that that with duplicate x = (x,x),
\initialElement -> catMaybes . takeWhile isJust . iterate (f =<<) . Just $ initialElement ≡ \initialElement -> initialElement: unfoldr (fmap duplicate . f) initialElement
In other words, the pipeline is basically equivalent to a simple unfoldr modulo the first step. Therefore,
untilNothing f initialElement = last $ initialElement : unfoldr (fmap duplicate . f) initialElement
Which reveals the relation to anamorphisms and makes it possible to drop two of the three pain-inducing functions (isJust and fromJust).
This further hints at the fact that loops are a combination of anamorphisms/unfolds (here: unfoldr) and catamorphisms/folds (here: last). As last can easily be replaced with better options like foldMap Last, the search for a "better" implementation should basically consist of a search for a more suitable unfold. A simple hoogle seems to reveal several options.
Cheers, MarLinn
PS: The relation to lists still remains in my version, but it may be easier to see that the "haskellism" is just an unfortunate result of both their prominence in the standard libraries and the specialised syntax we have for them. That's why it's a "haskellism", and not a universal relation.