Earlier quoted context omitted.
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.
The article is an introduction to the basic concepts of Haskell, thus beginners may be considered a target audience. However, the style and the content brings to my mind the dreaded monad tutorials. I'm not convinced the article is about pedagogical downsides of specifically Haskell. It mostly reads like a collection of random purported gotchas/differences from someone with experience with other languages.
Pedagogical Downsides of Haskell
81–90 of 118 posts
Re: Pedagogical Downsides of Haskell
#82Earlier 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,…
F# calls them Computation Expressions which is far more approachable imo
Re: Pedagogical Downsides of Haskell
#83Earlier quoted context omitted.
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?
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`.
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).
Re: Pedagogical Downsides of Haskell
#84Earlier quoted context omitted.
One of the more surprising aspects of GHC Haskell is that it is possible to write a very high level code with performance matching or exceeding code written in a low level language, thus honoring the machine. Stream fusion for an example. Not sure if there is any other language with higher abstraction/performance ratio.
JavaScript comes to mind. Its benchmarks are a wonderful testament to the immense engineering resources poured into V8.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Re: Pedagogical Downsides of Haskell
#85Earlier quoted context omitted.
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?
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`.
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.Re: Pedagogical Downsides of Haskell
#86Re: Pedagogical Downsides of Haskell
#87I 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,…
And what the hell is an interface for sequential computation? I think I understand what these Maybe types are and what they accomplish but "interface for sequential computation" sounds a lot like those buzzwords people mix together that could mean anything.
Re: Pedagogical Downsides of Haskell
#88The 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 goal of a programming language is to allow a human to express a sufficiently rigorous solution to a problem. From there, every step along the chain of execution is allowed to make 'unobservable' (for various definitions of the word) changes to execution. Your compiler might unroll your loops, or eliminate some unneeded intermediate variable, or even replace your entire function with a lookup table. Your CPU's microcode might do some weird fuckery with predictive execution. You shouldn't care, as long as the solution is, as far as you can observe, identical to your given one.
Whether functional programming is a better expression of computation than imperative programming is its own problem, but it's both silly and wrong to assert that imperative is better because it matches the behavior of the machine.
Re: Pedagogical Downsides of Haskell
#89[flagged]
Can you give an example of a Haskell way that is not Right?
- Implementing two instances of one member each is much more work than one instance with two members, which incentivizes overly coarse typeclass hierarchies: hence Num and friends, which are a disaster.
- They don't provide a good way to talk about one structure uniquely determining another (e.g. a given semigroup can be made a monoid in at most one way), which leads to boilerplate overly pessimistic constraint resolution.
- The way constraint resolution works forces them to take type constructors, not types - which makes aliases, type families, etc. second class citizens.
Re: Pedagogical Downsides of Haskell
#90I 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,…
Just because you can look at something as describing a computation doesn't mean you always should. For example:
data BinaryTree x =
| Leaf x
| Node (BinaryTree x) (BinaryTree x)
instance Monad BinaryTree where
return :: a -> BinaryTree a
return x = Leaf x
bind :: (a -> BinaryTree b) -> BinaryTree a -> BinaryTree b
bind f (Leaf x) = f x // replace a leaf with the result of calling f on its label
bind f (Node l r) = Node (bind f l) (bind f r) // traverse down the tree, ultimately replacing all the leaf nodes with a new subtree
You can choose to interpret a binary tree as describing nondeterministic computation where you have two choices at every step, but I rarely do. Most of the time trees are just trees.