Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I am.

In any concrete context, Maybe (Maybe A) could _probably_ be simplified to just Maybe A as we expect. Alternatively, we could be in a situation where there are two notions of failure (represented here as Nothing and Just Nothing) in which case we'd be better off simplifying to Either Error A where Error covers you multiplicity of error cases.

But while these are all obvious in a concrete context, what we often are doing is instead compositional. If I want to write code which works over (Maybe a) for some unknown, library-user-declared type `a` then I may very well end up with a Maybe (Maybe Int) that I can't (and mustn't) collapse.

As a concrete example, consider the type of, say, a JSON parser

    ParserOf a = Json -> Maybe a
We hold the notion of failure internal to this type so that we can write

    fallback : ParserOf a -> ParserOf a -> ParserOf a
which tries the first parser and falls back to the second if the first results in error. We might also want to capture these errors "in user land" with a combinator like

    catch : Parser a -> Parser (Maybe a)
If we unwrap the return type of `catch` we get a Maybe (Maybe a) out of a compositional context (we can't collapse it). Additionally, the two forms of failure are distinct: one is a "handled" failure and the other is an unhandled failure.


Similarly, a polymorphic function may want to put values of an unknown type in a Map or MVar. From the outside it may be completely reasonable to call that function on Maybe Foo, which would mean a Maybe (Maybe Foo) somewhere internally and I would struggle to call that bad design.


> In any concrete context, Maybe (Maybe A) could _probably_ be simplified to just Maybe A as we expect.

And doing so is just what `join :: m ( m a ) -> m a` specialises to for `m = Maybe`!


That's just one way to do it. Another might be

    collect :: Maybe (Maybe a) -> Either[Bool, a]


But you mentioned simplifying `Maybe (Maybe a)` to `Maybe a`, which your `collect` doesn't do (at least not directly).

(Also, shouldn't `Either[Bool, a]` (which I don't know how to make sense of) be `Either Bool a`? Even with this signature, I'm not sure what the implementation would be, and Hoogle doesn't turn up any obviously correct results ( https://www.haskell.org/hoogle/?hoogle=collect https://www.haskell.org/hoogle/?hoogle=Maybe+%28Maybe+a%29+-... ), but that's probably my fault.)


I think the obvious implementation is `maybe (Left False) (maybe (Left True) Right)`

If we have a value then we clearly have both layers. If we don't have a value then we need to distinguish Nothing from Just Nothing by way of the book.


Oh, I see; we're thinking of `Maybe a` as `a + ()`, and then identifying `(a + ()) + ()` with `a + (() + ())` and then `() + ()` with `Bool`. Thanks!


Right, exactly!




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: