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

Ah yes, wonderfully clear syntax:

    do a <- a
       b <- b


That was a poor choice. The local “a” shadows the parameter “a”. You can of course write:

    addM :: Maybe Int -> Maybe Int -> Maybe Int
    addM ma mb = do
      a <- ma
      b <- mb
      return (a + b)
As an aside, the inferred type would be much more general, because (+) works on any number and do/return work on any monad:

    addM :: (Monad m, Num a) => m a -> m a -> m a
Which means you could use it like this:

    addM (Just 5) (Just 10) == Just 15
But also like this:

    addM [1, 2] [4, 8]
      == [1 + 4, 1 + 8, 2 + 4, 2 + 8]
      == [5, 9, 6, 10]
Or like this:

    addM (Right 42) (Left "NaN") == Left "NaN"
And in many more interesting ways. :)


Of course, addA = liftA2 (+) is even more general.


That particular syntax makes much more sense when you have functions that return a Maybe value:

    do a <- getA "foo" "bar"
       b <- getB "foo" a
       ...
I used a deliberately overly simple example so I could go on from do-notation--which many people are already familiar with--to applicatives and idiom brackets.

Besides, it looks like any normal program, except you're using <- to define variables rather than =. Can't see how it could be any clearer than that.


Except that what it looks like isn't actually what it's doing (made even clearer by the a <- a example).

I like the Maybe concept and non-nullable types; I just think being able to overload operators like "=" and ";" in C++ and Haskell is optimizing writability over readability and in most cases, readability is by far the more important attribute.


You can't overload = or ; in Haskell. What you can do is to easily write code over some sort of 'boxed' values, where the type of the box is given by type signatures, and more importantly is almost always quite clear from context.

In this case, think of Maybe as a box containing one or zero instances of a type. For Maybe

    do x <- maybeAnInt
       y <- maybeAnotherInt
       return (x+y)
Lists are 'boxed' values containing any number of elements

    do x <- [1,2]
       y <- [10,20]
       return (x+y)
The monadic semantics for lists means this returns the sum of each combination of values, namely [11,21,12,22]. This is essentially like a database join, which is why a monadic structure was used for LINQ.

For Promises

    do x <- intPromise
       y <- anotherIntPromise
       return (x+y)
This returns a new promise containing the sum of the result of two promises instead of using callbacks.

Essentially all these types live in a Maybe/List/Promise box. There are many more examples. The nice thing about monads is that the semantics of how these things work is abstract enough to allow a variety of interpretations, but constrained enough (by the Monad laws) that you get a nice intuition of how things work after using a few different instances.


But you're quite clearly NOT overloading "=" or ";". Instead of saying

    do
       a = getFoo x y z
       b = getBar p q
(which won't compile), you're saying

    do
       a <- getFoo x y z
       b <- getBar p q
Which is not an overloaded operator. In fact, it's not even meant to suggest equals (which in Haskell rather strictly means mathematical equality) but rather assignment ("=" in the expression "x = x + 1;").


The use of Haskell here was just for illustration; there's nothing stopping a programming language designer from having clear, convenient syntax for dealing with Maybe values.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

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

Search: