Live data from Hacker News

Monads are a Class of Hard Drugs (2008)

lambda-diode.com

11–20 of 37 posts

Re: Monads are a Class of Hard Drugs (2008)

#11
post #8

Anyone who understands monads is on a class of hard drugs. I'm still looking for someone who can present a cogent explanation of monads using only Python. (I'm willing to replace "Python" in the above challenge with "any language I know well," which would include Python, C, C++, Java, JavaScript, and quite a few others which I won't bother to list here. Notably lacking from this list are Lisp, Scheme, Caml, Haskell,…

Python it is. I've explained monads using Python many times.

http://www.dustingetz.com/2012/04/07/dustins-awesome-monad-t...

http://www.dustingetz.com/2012/10/02/reader-writer-state-mon...

(I'm not dustingetz though, he's named dustingetz on HN.)

Re: Monads are a Class of Hard Drugs (2008)

#12
post #9
post #8

Anyone who understands monads is on a class of hard drugs. I'm still looking for someone who can present a cogent explanation of monads using only Python. (I'm willing to replace "Python" in the above challenge with "any language I know well," which would include Python, C, C++, Java, JavaScript, and quite a few others which I won't bother to list here. Notably lacking from this list are Lisp, Scheme, Caml, Haskell,…

What I wish someone had explained to me earlier was that Monads are an abstraction level up from most things you ever program with. Learn specific ones, and the general picture will start to make more sense. Avoid the IO monad until you understand, in order: + the List monad (probably the easiest for python people, since it's very similar to list comprehensions) + the Maybe monad (kind of a degenerate case) + the Sta…

>+ the Maybe monad (kind of a degenerate case)

Hey. Hey. heyyyyy.

I've used bind + maybe monad 'ish stuff in Python to clean up code previously littered with redundant if checks.

Re: Monads are a Class of Hard Drugs (2008)

#14
post #9

Earlier quoted context omitted.

What I wish someone had explained to me earlier was that Monads are an abstraction level up from most things you ever program with. Learn specific ones, and the general picture will start to make more sense. Avoid the IO monad until you understand, in order: + the List monad (probably the easiest for python people, since it's very similar to list comprehensions) + the Maybe monad (kind of a degenerate case) + the Sta…

>+ the Maybe monad (kind of a degenerate case) Hey. Hey. heyyyyy. I've used bind + maybe monad 'ish stuff in Python to clean up code previously littered with redundant if checks.

He probably means its a degenerate case of the list monad. Which is a useful way to look at it: a Maybe value is like a list of length at most 1.

You can also look at it as a degenerate case of Either. (That is, Maybe a ~ Either () a.)

This is "degenerate" in the mathematical sense, much the same way you can think of a point as a degenerate circle.

Re: Monads are a Class of Hard Drugs (2008)

#15
post #10
post #8

Anyone who understands monads is on a class of hard drugs. I'm still looking for someone who can present a cogent explanation of monads using only Python. (I'm willing to replace "Python" in the above challenge with "any language I know well," which would include Python, C, C++, Java, JavaScript, and quite a few others which I won't bother to list here. Notably lacking from this list are Lisp, Scheme, Caml, Haskell,…

>Anyone who understands monads is on a class of hard drugs. It's so frustrating to hear you say that. Monads are such a simple concept but they're difficult to explain because they're far more general and abstract than most programming topics. The best explanation I have is that monads are a way of storing some kind of computation with a value. When the user wants access to that value, he uses a monadic operator whic…

So basically monads are like a Java object that has a private field and a getter method that has some extra logic. Hey, that's really simple, you're right!

duck & runl

Re: Monads are a Class of Hard Drugs (2008)

#16
post #8

Anyone who understands monads is on a class of hard drugs. I'm still looking for someone who can present a cogent explanation of monads using only Python. (I'm willing to replace "Python" in the above challenge with "any language I know well," which would include Python, C, C++, Java, JavaScript, and quite a few others which I won't bother to list here. Notably lacking from this list are Lisp, Scheme, Caml, Haskell,…

> I'm still looking for someone who can present a cogent explanation of monads using only Python.

Personally, I don't do monads in any other language than Haskell. I find monads painful even in Ocaml. I'm pretty stupid as a programmer. And --- especially when doing things such as monad transformers --- I need lots of type checking and lots of type inference to help me over my mistakes (which are pervasive).

The cool thing is that when I've written these things called "monad transformer stacks" (see Real World Haskell for what I guess is the best explanation for those), I find that when my code gets through the type checker, it really does just work. It works, even when I've lost any sense of what my code is actually doing underneath. Without the type system, I couldn't have any confidence of this, and the runtime bugs you can potentially get with monads are so subtle that I would be terrified to use them in a language like Python (note again, I'm stupid, and YMMV).

The other reason why I wouldn't do monads without types is because, to me, monads are the type. The semantics of a monad is pretty much just that type (plus some crucial axioms). Types in Haskell are much more expressive than in most languages. The way "operator overloading" works in Haskell means that by specifying types, you are often generating runtime code (think C++ templates, but not for too long). That's why you see more type annotations in Haskell compared to (say) Ocaml. Though if you want to do the same thing in Ocaml, you'll be knee deep in the even more verbose world of these things called functors.

Re: Monads are a Class of Hard Drugs (2008)

#17
post #9
post #8

Anyone who understands monads is on a class of hard drugs. I'm still looking for someone who can present a cogent explanation of monads using only Python. (I'm willing to replace "Python" in the above challenge with "any language I know well," which would include Python, C, C++, Java, JavaScript, and quite a few others which I won't bother to list here. Notably lacking from this list are Lisp, Scheme, Caml, Haskell,…

What I wish someone had explained to me earlier was that Monads are an abstraction level up from most things you ever program with. Learn specific ones, and the general picture will start to make more sense. Avoid the IO monad until you understand, in order: + the List monad (probably the easiest for python people, since it's very similar to list comprehensions) + the Maybe monad (kind of a degenerate case) + the Sta…

Most information on Monads start out with IO, which I agree isn't helpful. I found one that explained it with Maybe and Either, and that was where I began to understand it.

I think Maybe is the easiest to grasp for people who work in procedural languages, since there's a very common idiom of returning a nil object if some operation doesn't succeed. You can look at Maybe and see immediately; "oh this is like a type-safe version of that". Then from there, Either makes since almost instantly, and you can sneak in List and some others before they realize they shouldn't be able to understand it :)

Since I like your order of Monadic instruction, do you perhaps have a preferred starting point for learning Arrows? I can see that it's a way to compose sequences of computation, but I don't get what problems they solve that are difficult to solve with other methods.

Re: Monads are a Class of Hard Drugs (2008)

#18
post #8

Anyone who understands monads is on a class of hard drugs. I'm still looking for someone who can present a cogent explanation of monads using only Python. (I'm willing to replace "Python" in the above challenge with "any language I know well," which would include Python, C, C++, Java, JavaScript, and quite a few others which I won't bother to list here. Notably lacking from this list are Lisp, Scheme, Caml, Haskell,…

Consider the pattern of using None (or null) as an error. You want to compute: var x x=f(x) x=g(x) x=h(x)

however, if either f,g, or h return None, then the final value of x is None. The standard way of doing this is: def f(x): if x==None: return None ...

The monadic solution is the Maybe monad. Maybe has two constructors, Just(x) and Nothing. The above code would be equivilent to var x x=Just(x) x=x.apply(f) x=x.apply(g) x=x.apply(h)

The definition of Maybe is pretty simple. The Just object takes a value of a given type, and will run that value through a given function: Class Just(): def __init__(val): this.val = val

def apply(f); return f(x)

The Nothing object is even simpler: Class Nothing(): def apply(f): return Nothing()

Using this, we can see that in our original example, once one function returns Nothing, we skip all the other functions and end up with Nothing. When a function does return something, it needs to wrap it in Just, so we have:

def f(x): ... return Just(x)

In general, to be a Monad you need to satisfy the type class Monad(): def apply(f)

Of course, using Monads like this can end up being somewhat messy, so there is much syntactic sugar around them.

Re: Monads are a Class of Hard Drugs (2008)

#19
post #15
post #10

Earlier quoted context omitted.

>Anyone who understands monads is on a class of hard drugs. It's so frustrating to hear you say that. Monads are such a simple concept but they're difficult to explain because they're far more general and abstract than most programming topics. The best explanation I have is that monads are a way of storing some kind of computation with a value. When the user wants access to that value, he uses a monadic operator whic…

So basically monads are like a Java object that has a private field and a getter method that has some extra logic. Hey, that's really simple, you're right! duck & run l

No, objects in Java are more complicated than monads. They include the concepts of identity, mutable state and inheritance; all of which monads lack.

Re: Monads are a Class of Hard Drugs (2008)

#20
post #8

Anyone who understands monads is on a class of hard drugs. I'm still looking for someone who can present a cogent explanation of monads using only Python. (I'm willing to replace "Python" in the above challenge with "any language I know well," which would include Python, C, C++, Java, JavaScript, and quite a few others which I won't bother to list here. Notably lacking from this list are Lisp, Scheme, Caml, Haskell,…

They're not smart to do in python. Monads are an expressive, simple pattern of coding that can be type-checked. In dynamic languages it'll just look like a lot of unnecessary line noise. In HM type systems it's a great way to help you pass contexts around in a way lets you focus on your values.

But if you just want to speak Python, let me try to translate.

---

As a motivation for monads in Python, we're going to try to make "total" Python. To do so, we have to eschew execptions. This means we'll write stuff like

    def mypop(l):
      if len(l) > 0:
        return l.pop()
      else:
        return None
which, if we pass it a list of numbers, is guaranteed to return either a number or None---I've sidestepped the empty list exception. Now let's say I want to compose this function. For instance, my list of numbers is a list of bids and I have a function where I can try buying something with my bid.

    def buy(tendered):
      effective = tendered*1.2 # there's a discount!
      if market_open():
        if effective > 60:
          return True
        else:
          return False
      else:
        return None
So I believe that buy takes numbers and returns Booleans, so I might think that

    def trybuy(l): return buy(mypop(l))
takes lists of numbers and returns a boolean as to whether I've bought it. Of course, I have to be smart enough not to send in an empty list otherwise the discount in 'buy' will cause an error. I also have to be sure that if I try buying on days the market is closed to handle the 'None'. In Haskell, we'd write these constraints into the types and values using a Maybe type.

Here's a Pythonic Maybe type (kind of not pythonic though with the magic sentinel value, but we don't want to be able to sneak 'None's in).

    class Maybe(object):

      __sentinel__ = object()

      def __init__(self, obj = __sentinel__):
        self.isNothing = False
          if obj == self.__sentinel__:
            self.isNothing = True
          else:
            self.just = obj

    def just(x): return Maybe(x)
    def nothing(x): return Maybe()
Now we can have 'mypop' and 'buy' to return Maybe types to cover the cases of empty lists and closed markets.

    def mypop(l):
      if len(l) > 0:
        return just(l.pop())
      else:
        return nothing()

    def buy(tendered):
      effective = tendered*1.2 # there's a discount!
      if market_open():
        if effective > 60:
          return just(True)
        else:
          return just(False)
      else:
        return nothing()
So now we've abstracted the 'None's out a bit. 'mypop(l)' is always a "Maybe(Bool)" and you can inspect it to determine what the case is like 'mypop(l).isNothing'. Of course, this isn't any different from using None's and checking with "x == None" except it's more explicit: if you forget that 'mypop' returns Maybes then your program will throw an error on every use... instead of just the ones where you could have gotten a None without noticing for a while. (This is where the "You Probably Already Invented Monads" idea comes from, btw.)

In Haskell we'd say that mypop has type

    mypop :: [Float] -> Maybe Float
and buy has type

    buy :: Float -> Maybe Bool
but this makes it harder to make 'trybuy :: [a] -> Maybe Bool' since buy doesn't accept Maybes. It's also pretty clear, though, that if we send in an empty list we shouldn't even attempt to buy anything (our paycheck hasn't come in yet), so let's write that as a failure mode.

    def bind(maybe_something, maybe_process):
      if maybe_something.isNothing:
        return nothing()
      else:
        return maybe_process(maybe_something.just)
and now we can write trybuy such that it respects maybes with almost no additional noise

    # trybuy :: [Float] -> Maybe Bool
    def trybuy(l): return bind(mypop(l), buy)
The pattern we've captured here---the creation of lots of explicit context to help make functions more total and fail more quickly if you misuse them and the use of 'bind' to write functions that don't need to know about context on their input---is the Monad pattern. In Haskell, we recognize that many, many kinds of context are Monadic and thus can have default compositions programmed in. 'bind' is heavily overloaded and whenever you're writing code with context you use it often to compose functions without paying the complexity cost of routing that context around.

It's obviously not a really great Python pattern. This largely has to do with the fact that Python isn't terribly explicit about what's going on: you have to remember where exceptions and edge cases can fall out. In Haskell, we just use types to encode all of that into the documentation and the type checker ensures that we never mess up.

Post reply on HN