Hacker News new | ask | show | jobs
by liontwist 522 days ago
Familiarity is a part, but abstract reasoning is fundamentally harder than concrete.

Understanding the map signature in Haskell is more difficult than any C construct. Now do IO monad.

2 comments

> Understanding the map signature in Haskell is more difficult than any C construct.

This is obviously false. The map type signature is significantly easier to understand than pointers, referencing and dereferencing.

I am an educator in computer science - the former takes about 30-60 seconds to grok (even in Haskell, though it translates to most languages, and even the fully generalised fmap), but it is a rare student that fully understands the latter within a full term of teaching.

Are the students who failed the pointer class the same ones in the fmap class?

I didn’t say “using map” I said understanding the type signature. For example, after introducing map can you write its type signature? That’s abstract reasoning.

Pointers are a problem in Haskell too. They exist in any random access memory system.

Whether pointers exist is irrelevant. What matters is if they're exposed to the programmer. And even then it mostly only matters if they're mutable or if you have to free them manually.

Sure, IORef is a thing, but it's hardly comparable to the prevalence of pointers in C. I use pointers constantly. I don't think I've ever used an IORef.

If you have an array and an index, you have all the complexity of pointers. The only difference is that Haskell will bounds check every array access, which is also a debug option for pointer deref.
You are very disconnected from learners. They get confused over mutability, not bounds checking, which is not an option for raw pointers consistently
Hard to believe that “learners ... get confused over mutability” more than functional programming when millions of middle-schoolers grokked the idea of “mutability” in the form of variables in Basic, while I (and at a guess, at least thousands of other experienced programmers) have no fucking idea about pretty much all the stuff in most of the tens or hundreds of articles and discussions like this that we've seen over the years. Just plain stating that “mutability is more difficult” without a shred of evidence ain't gonna fly.
That’s an unfair comparison because these are two unrelated concepts. In many languages, pointers are abstracted away anyway. Something more analogous would be map vs a range loop.
And I'd say the average React or Java developer these days understands both pretty well. It's the default way to render a list of things in React. Java streams are also adopted quite well in my experience.

I wouldn't say one is more difficult than the other.

IMO `map` is a really bad example for the point that OP is trying to make, since it's almost everywhere these days.

FlatMap might be a better example, but people call `.then` on Promises all the time.

I think it might just be familiarity at this point. Generally, programming has sort of become more `small f` functional. I'd call purely functional languages like Haskell Capital F Functional, which are still quite obscure.

Well, he responded to someone saying the type signature of map was more complicated than ANY C construct.
Fair point
`map` aint so bad...

    map :: (a -> b) -> [a] -> [b]
I suppose an absolute beginner would need someone to explain that Haskell type signatures can be read by slicing at any of the top level arrows, so that becomes either:

> Given a function from `a` to `b`, return a function from a `list of as` to a `list of bs`.

or:

> Given a function from `a` to `b` and a `list of as`, return a `list of bs`.

I find the first to be the more intuitive one: it turns a normal function into a function that acts on lists.

Anecdotally, I've actually found `map` to be one of the most intuitive concepts in all of programming. It was only weird until I'd played around with it for about 10m, and since then I've yet to be surprised by it's behavior in any circumstance. (Although I suppose I haven't tried using it over tricky stuff like `Set`.)

`fmap` is admittedly a bit worse...

    fmap :: Functor f => (a -> b) -> f a -> f b
But having learned about `map` above, the two look awfully similar. Sure enough the same two definitions above still work fine if you replace `list` with this new weird `Functor` thing. Then you look up `Functor` you learn that it's just "a thing that you can map over" and the magic is mostly gone. Then you go to actually use the thing and find that in Haskell pretty much everything is a `Functor` that you can `fmap` over and it starts feeling magical again.
You and I have a math part of our brain that appreciate the elegance from the algebraic structure.

I’m saying that thing you did where you start representing concepts by letters which can be populated by concrete objects is not a skill most people have.

Oh. Yeah that's a good point.