Earlier quoted context omitted.
I think I prefer this: foldr _ z [] = z foldr k z (x:xs) = k x $ foldr k z xs
I suspect we all prefer that, but the point of abstracting out a closure that captures k and z is for performance.
Pedagogical Downsides of Haskell
71–80 of 118 posts
Re: Pedagogical Downsides of Haskell
#72Earlier quoted context omitted.
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,…
As I understand it, monads help solve the problem of sequential computation in Haskell but the concept is not limited to that. For example, how would you consider the monadic properties of data type like Maybe or Either to be (exclusively?) interpreted through the lens of sequential computation? What about commutative monads where the order doesn’t matter?
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`.Re: Pedagogical Downsides of Haskell
#73Earlier quoted context omitted.
I suspect you are right that there's a type of person Haskell feels very intuitive to. I think if your mind works that way you might have a hard time appreciating the degree of confusion "regular" programmers face when trying to decipher the mess of symbolic soup.
There is no reason for Haskell to be a "mess of symbolic soup". You can make Haskell about as human-readable as Ruby if you choose to.
Re: Pedagogical Downsides of Haskell
#74Earlier quoted context omitted.
The first.
Do you have insight you can share into why you find it that way?
I'd argue "of course not". You already know that it's the foldr worker because it's a local recursive definition inside foldr. And you already know it closes over k and z because it uses them without defining them locally. Nothing in that name provides additional semantic value.
You could still use it anyway, on the argument that a little redundancy can help aid reading. But the more Haskell code you read and write, the less that redundancy helps you with anything. On the other hand, the proliferation of names that contain almost no semantic content starts to drag on you. And so an idiom was developed for naming recursive workers that do the core job of what the parent's name promises: just name it "go". Nothing to think about. It's reduced down to a level that communicates exactly that it's not clever. It's just doing the thing it has to do. And it's standardized. If you see it, you know exactly what it's doing. There's no need to waste time mapping a new name into your existing set of well-known patterns.
So... As to the original argument's point? I think it probably is awkward for pedagogy. But it's absolutely better for actively using the language.
Re: Pedagogical Downsides of Haskell
#75Had good experience at https://exercism.org/tracks/haskell I don't think this article is helpful for beginners.
I think this article's audience is teachers of beginners, not beginners themselves. At least the author is writing about their experience as a teacher. Don't know why you thought it would be an article for beginners, but good on you for linking a resource regardless.
Re: Pedagogical Downsides of Haskell
#76Earlier quoted context omitted.
I suspect we all prefer that, but the point of abstracting out a closure that captures k and z is for performance.
Eh, the performance isn't from abstracting out a closure. It's from making the definition non-recursive so that it can be inlined. Then the compiler can see and inline the k and z parameters into the "go" block to eliminate indirect references. It's really all about inlining.
foldr k z = foldr' k z
where
foldr' k z [] = z
foldr' k z (y:ys) = y `k` foldr' k z ys
That's obviously not sufficient, so it must have something to do with the nature of the closure. In this case I presume that it's because the closure captures k and z, although if you have any evidence to the contrary that would be interesting to see.Re: Pedagogical Downsides of Haskell
#77Re: Pedagogical Downsides of Haskell
#78Earlier quoted context omitted.
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,…
As I understand it, monads help solve the problem of sequential computation in Haskell but the concept is not limited to that. For example, how would you consider the monadic properties of data type like Maybe or Either to be (exclusively?) interpreted through the lens of sequential computation? What about commutative monads where the order doesn’t matter?
It probably confuses people because this is a problem haskell created for itself.
Re: Pedagogical Downsides of Haskell
#79Earlier quoted context omitted.
Eh, the performance isn't from abstracting out a closure. It's from making the definition non-recursive so that it can be inlined. Then the compiler can see and inline the k and z parameters into the "go" block to eliminate indirect references. It's really all about inlining.
If it was just about making it non recursive so it could be inlined then the following would be sufficient: foldr k z = foldr' k z where foldr' k z [] = z foldr' k z (y:ys) = y `k` foldr' k z ys That's obviously not sufficient, so it must have something to do with the nature of the closure. In this case I presume that it's because the closure captures k and z, although if you have any evidence to the contrary that wo…
When this happens, note that it's actually no longer constructing a closure at runtime. It has essentially closed over the values at compile time, using some very trivial transformations. If you use a definition that is too complex for those trivial transformations, you're getting in the way of the compiler doing its job. I always prefer to write my code with sympathy for the compiler. The less magic it needs to do, the better it does its job.
Re: Pedagogical Downsides of Haskell
#80For 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 standard library docs to help. So you can either just say "don't worry about this for now, just trust me" or spend a whole chapter diving into macro syntax. The number of concepts you need to implement a basic program is pretty large and you could easily spend a chapter going into any of them.
Personally I'm not a fan of the approach in this post to just "lie" to people but I do find myself showing a non-optimal implementation because that's all the syntax I've introduced up to that point. Then later I show how to do it better. I know some readers just want the final answer up front though.