Live data from Hacker News

Why monads have not taken the Common Lisp world by storm (2008)

marijnhaverbeke.nl

31–40 of 49 posts

Re: Why monads have not taken the Common Lisp world by storm (2008)

#31

There is a point made here about how Haskell's namespace handling makes monads easy, while CL's makes them ugly. I don't know enough about CL's namespaces to understand this. Can someone explain?

Functions and other values are stored in separate namespaces so when you want to call a function that is stored in a "regular" variable you must write

(funcall (function variable) arg1 arg2 ... argn)

Or shorthand (funcall #'variable arg1 arg2 ... argn)

Basically, some people find this ugly, I mostly find it to say "HEY!! We're doing this specific thing right here". To me it's more helpful than ugly.

Re: Why monads have not taken the Common Lisp world by storm (2008)

#32
post #16

Earlier quoted context omitted.

It's easy for a Haskell expert to sweep typeclass resolution under the rug, but it's definitely some pretty black magic at first no matter how "simple" its implementation is. The reality is that the compiler works really hard to ensure that it can guess the right "get" and it's pretty possible for it to fail. Of course, when it fails you know immediately and can remedy it by type annotations, but that can still be ch…

Thanks. I sometimes wonder, is there a way in Haskell to display a type signature of a function for a particular instance? For example, is there a way to display type of get when used as an instance of State ? I know I can derive it but I would sometimes like to see if I am correct..

Some vim and emacs plugins can give you the type of subexpressions like this. Namely, you want the ghc-mod plugin since it provides the hooks into the compiler to query type information.

Re: Why monads have not taken the Common Lisp world by storm (2008)

#33
post #23

Earlier quoted context omitted.

Yup. If I had read this article when it was first written instead of now, I probably would have produced a fair bit less unnecessarily complicated and difficult-to-maintain code over the past several years. Instead, I had to figure out why I was having such a hard time coming up with a satisfactory implementation of the pattern in C# - and why I maybe shouldn't have wanted one in the first place - the hard way.

Just curious, why would you argue that you shouldn't have wanted it the first place? Monads are one thing, which you can approximate somewhat via LINQ, but there are other simpler patterns such as Monoid, that really makes sense to use as programming construct, that just somehow never works in C#.

Because it seems like there always turns out to be some other approach that works better and is more idiomatic in C#. Usually something really forehead-smackingly obvious like mutation or a callback.

Re: Why monads have not taken the Common Lisp world by storm (2008)

#34
post #32

Earlier quoted context omitted.

Thanks. I sometimes wonder, is there a way in Haskell to display a type signature of a function for a particular instance? For example, is there a way to display type of get when used as an instance of State ? I know I can derive it but I would sometimes like to see if I am correct..

Some vim and emacs plugins can give you the type of subexpressions like this. Namely, you want the ghc-mod plugin since it provides the hooks into the compiler to query type information.

Is there a way to do this in ghci? I know the :t command, but I don't know how to say that I want a specific instance.

Re: Why monads have not taken the Common Lisp world by storm (2008)

#35
post #24
post #16

Earlier quoted context omitted.

It's easy for a Haskell expert to sweep typeclass resolution under the rug, but it's definitely some pretty black magic at first no matter how "simple" its implementation is. The reality is that the compiler works really hard to ensure that it can guess the right "get" and it's pretty possible for it to fail. Of course, when it fails you know immediately and can remedy it by type annotations, but that can still be ch…

It's also quite possible for this type of functions to get a polymorphic type, in which case the compiler generate code that will pass along essentially a virtual table object for the particular instance of the call site. Hardly black magic.

I agree that the implementation is quite obvious. It's the inference—the collusion between the HM type constraints and the Prolog-like typeclass constraints—that's magical.

Re: Why monads have not taken the Common Lisp world by storm (2008)

#36
post #15

Earlier quoted context omitted.

That's a really great point that I rarely see come up. Yes, Haskell makes you "recreate" the RWST monad stack that imitates impure languages... but the same tools also let you build other "language domains" which are fiendishly difficult to implement in non-pure settings (on par with CPS transforming yourself into the mother monad and then working backwards from there). On Lisp has a chapter devoted to making a leaky…

>Yes, Haskell makes you "recreate" the RWST monad stack that imitates impure languages This is really a point that seems to get lost in most of learning materials on the web. LYAH doesn't even acknowledge transformers. I am pretty new to Haskell but it seems to me that transformer stack decisions are a pretty significant design decision for your application. What has happened to me is almost all the code in my applic…

That's definitely a stage of a Haskell program design. The stack helps to separate out layers of effects, but it can be easy to fix that stack concretely at an early stage and then feel the weight of it later on with overly specialized functions.

The solution is usually to use the mtl-style transformer classes which let you write generalized functions which depend upon capabilities of the transformer stack instead of the concrete stack itself. You end up with a sort of natural dependency injection framework. For instance, here's a function which works on any RW-style monad stack

    augment :: (MonadReader a m, MonadWriter a m) => a -> m ()
    augment a = ask >>= \a' -> tell (a'  a)
where the Monoid constraint allowing us to use () is coming from the typeclass Prolog involved with the MonadWriter class.

You can then use augment in ANY monad transformer stack which involves Reader and Writer over the same state type.

Note that this defers the extremely important decision about your monad transformer layer order---the caller of augment decides whether to call it with "ReaderT w (Writer w) a" or "WriterT w (Reader w) a". Reader/Writer commute so it's not a problem, but this changes things in the op's example using "ParsecT (LogicT m)" versus "LogicT (ParsecT m)". If your function depends on a particular ordering of the effects then it must have a less general type.

Re: Why monads have not taken the Common Lisp world by storm (2008)

#37
post #16

Earlier quoted context omitted.

It's easy for a Haskell expert to sweep typeclass resolution under the rug, but it's definitely some pretty black magic at first no matter how "simple" its implementation is. The reality is that the compiler works really hard to ensure that it can guess the right "get" and it's pretty possible for it to fail. Of course, when it fails you know immediately and can remedy it by type annotations, but that can still be ch…

Thanks. I sometimes wonder, is there a way in Haskell to display a type signature of a function for a particular instance? For example, is there a way to display type of get when used as an instance of State ? I know I can derive it but I would sometimes like to see if I am correct..

There's a hack you can use until Type Holes lands in production GHCi. If you turn on ImplicitParams you can write

  getAny :: (Random a) => State StdGen a
  getAny = do g      
which will fail the type checker because your type didn't include the information about what ?whatAmI is---the error will be something like "could not find definition of ?whatAmI :: State StdGen StdGen -> State StdGen StdGen", although you may only get partial information as the compiler may complain about your undefined function before it's resolved what you're looking for.

You can also leave off the type annotation and GHCi will infer the type of ?whatAmI. Then if you check the type of "getAny" you'll see

    getAny
      :: (?whatAmI::m s -> n s', RandomGen s', Random b,
          MonadState s m, MonadState s' n) =>
         m b
which provides all of the information the typechecker knows all in one go. Take note that the type it derives is somewhat more general than the one we want since it allows ?whatAmI to transform the involved monad. Obviously "get" doesn't do this.

Re: Why monads have not taken the Common Lisp world by storm (2008)

#38

* Try to quickly write the whole thing as a single recursive descent parser. Note the exploding amount of ugliness. Give up. * Separate out the tokenizer (novel idea, huh?) to keep parser complexity down. Parser is still a mess. Ugh! * Play around with some CL parser frameworks. This helps a bit, but none of the systems I tried produce errors with enough information. * Remember the breeze it was to write a parser wit…

I have no idea what you're working on, but I spent a few weeks this summer writing parsers and trying to figure out how to tackle the ugliness that seems to be inherent in hand-written recursive descent parsers. While I learned a lot, I am not an expert by a long shot. However I did find an interesting technique that is not well covered elsewhere. I came across this* article, which uses JavaScript as the implementati…

The parser is a bastard mix of recursive descent and parser combinators borne out of looking at the Dragon Book and thinking "fuck me, 2000 pages? I'm sure I can remember some CS325...". The language will eventually have macros I'll use for the built-in operators. I guess it's a Lisp? The syntax is sweet-expressions, so infixes are {l op b} which is just (op a b).

Re: Why monads have not taken the Common Lisp world by storm (2008)

#39
post #9
post #7

Earlier quoted context omitted.

Scala has plenty of monads and they work fine.

Scala has a much more powerful type system than Clojure

100% true, but not as powerful as Haskell's. Not sure you can usefully have inheritance and return type overloading.

Re: Why monads have not taken the Common Lisp world by storm (2008)

#40
post #13

Earlier quoted context omitted.

This talk by Douglas Crockford is quite informative: http://www.youtube.com/watch?v=dkZFtimgAcM

As a connoisseur of monad explanations (if not monad understanding) Crockford's talk sounds rushed. It spends a fair amount of time on setup, but when it gets to the meaty bits, it has the feeling of glossing over the details. It could be that all the essential elements are there, but they're covered to quickly to impart any comprehension.

Actually, Crockford is completely wrong in his definition. He is confusing them for functors.
Post reply on HN