Live data from Hacker News

Pedagogical Downsides of Haskell

ciobaca.substack.com

91–100 of 118 posts

Re: Pedagogical Downsides of Haskell

#91

Earlier quoted context omitted.

The `Monad` instance for `Maybe` and `Either` is precisely for doing sequential computation! Consider the following: myBigSubroutine :: Maybe Int -> Maybe Int -> Maybe Bool myBigSubroutine ma mb = do a b) Here we are sequencing the "effect" of optionality. `ma` must be evaluated before `mb` and if it returns a `Nothing` then we short circuit and do not evaluate `mb`.

> `ma` must be evaluated before `mb` No - either one can be evaluated first, with the other being short-circuited. If you swap the order of those lines, the function is exactly the same (in terms of inputs and outputs, at least).

This `do` syntax desugars to binds like:

    ma >>= \a -> mb >>= \b -> return (a > b)
We can then inline the definition of `>>=` and `return` to get:

    case ma of
      Nothing -> Nothing
      Just a ->
        case mb of
          Nothing -> Nothing
          Just b -> Just (a > b)
Imagine that `mb` is actually a really expensive computation that we don't want to perform unless `ma` returns a value. Sequencing our case statements in this way allows us to do that. `mb` will remain an unevaluated thunk until `ma` evaluates to a `Just a` value.

Re: Pedagogical Downsides of Haskell

#92

Earlier quoted context omitted.

The `Monad` instance for `Maybe` and `Either` is precisely for doing sequential computation! Consider the following: myBigSubroutine :: Maybe Int -> Maybe Int -> Maybe Bool myBigSubroutine ma mb = do a b) Here we are sequencing the "effect" of optionality. `ma` must be evaluated before `mb` and if it returns a `Nothing` then we short circuit and do not evaluate `mb`.

I think the commenter who mentioned syntax is on to something. If I write this fn my_big_subroutine(ma: Option , mb: Option ) -> Option { match (ma, mb) { (Some(a), Some(b)) => Some(a > b), (_, _) => None, } } it’s clearer to me what the intent is. I’m not sure why the other syntax is so hard for me but it feels hard to understand for some reason.

The `do` block I showed is more like this:

    fn my_big_subroutine(ma: Option, mb: Option) -> Option {
        match (ma) {
            (Some(a)) => 
              match (mb) {
                (Some(b)) => Some(a > b),
                _ => None
              }
            (_) => None,
        }
    }
Which in this case is equivalent in this example, however I'm trying to stress the sequencing. Imagine `mb` had some very expensive computation in it, then it will remain an unevaluated thunk if we shortcircuit on `ma`.

> it’s clearer to me what the intent is. I’m not sure why the other syntax is so hard for me but it feels hard to understand for some reason.

We can write `myBigSubroutine` with case matching:

    case ma of
      Nothing -> Nothing
      Just a ->
        case mb of
          Nothing -> Nothing
          Just b -> Just (a > b)
In fact, the `do` notation version desugars to something equivalent to this snippet.

The motivation for using the `Monad` instance (and thus `do` notation), is that it allows us to be polymorphic over the effect described by `>>=` (and thus `do`).

This lets us have a customized version of sequencing computations specialized to whatever "effect" we need, not just casing on optional values.

Re: Pedagogical Downsides of Haskell

#93

I find its syntax & idiomatic style incredibly difficult to follow, in a way nearly no other languages have been for me, including some functional languages (OCaml doesn't seem nearly as bad to me, for instance). It's sometimes implied that those who trip over Haskell just aren't big-brained enough to understand various important concepts related to it, but I've found they're usually very easy to grasp, provided the…

I find the terminology that Haskell uses quite misleading for software engineering. It borrows concepts from category theory with quaint names such as a "monad", "endofunctor", "catamorphism", etc. The problem is that, instead of a "monad", we can say "brrrdogcogfog" and nothing will change -- the name is absolutely irrelevant to the problem being solved. Given that a monad is an interface for sequential computation,…

Composition/SeqComp comes for free. A monad is how to wrap something up,apply a function to the wrapped up thing, and how to unwrap it.

Re: Pedagogical Downsides of Haskell

#94

The pedagogical downside of Haskell is that it ignores the physical reality of the machine. Physically, a computer is imperative, has mutating state, and is filled with all kinds of possible race conditions. Even after you apply the operating system, allowing processes to live together (and giving you space to define new ones), very few constraints are placed on your program and process space. Instead of building on…

>"The Lambda Calculus", the physical machine is looked at with disdain and pity, its limitations to be worked around to provide the one true abstraction.

That isn't true. There are graph reduction machines whose natural model of computation is lambda calculus and they are generally very efficient compared to sequential processors implementing Turing machines.

Re: Pedagogical Downsides of Haskell

#95
post #82

Earlier quoted context omitted.

F# calls them Computation Expressions which is far more approachable imo

That sounds almost as vague to me as “object” does in OOP. Don’t non-monadic functions also consist of expressions that describe computations?

Everything is vague. Hell, Haskell functions are not really functions in the mathematical sense.

Re: Pedagogical Downsides of Haskell

#97

I find its syntax & idiomatic style incredibly difficult to follow, in a way nearly no other languages have been for me, including some functional languages (OCaml doesn't seem nearly as bad to me, for instance). It's sometimes implied that those who trip over Haskell just aren't big-brained enough to understand various important concepts related to it, but I've found they're usually very easy to grasp, provided the…

[dead]

Re: Pedagogical Downsides of Haskell

#99

This is great and a lot of it rings true to my experience writing a book to teach Rust. It's basically a giant topological sorting exercise to find the optimal order to introduce syntax so that you steer clear of rabbit holes. Or you just end up drawing the owl. For example, to implement a simple "hello world" program in Rust you have to use a macro (println!), so you can't even look for a function signature in the s…

I provide a dependency diagram so students can work out where to apply most effort and how to catch up if they miss something.

I also show likely dependencies from the course assessment to the various topics. For instance, there is a strong dependency on the IO monad, but a weaker/optional dependency on (general) monads.

In terms of presentation order, I tend to over-simplify early in the course and circle back and make things more precise later.

(I'm teaching a 2nd year university course on Functional Programming with Haskell for the first time, so I found the OP fascinating. Thanks!)

Re: Pedagogical Downsides of Haskell

#100

Earlier quoted context omitted.

I'm sorry to break it to you but every single programming language in existence ignores the physical reality of the machine. That's the point of abstractions such as programming languages.

There are abstractions which build on the inherently stateful nature of computers with their instruction pointers, registers, memory and peripheral devices, and there are abstractions which coerce you into framing any computational problem like a mathematical formalism.

I've never had to worry about what's a register in Python, and barely about pointers and memory (those are highly abstracted away, exactly to the same extent as they are in Haskell).
Post reply on HN