16 ms·
The Cult of the Haskell Programmer
- julianeon 2y agoThis would be a great place for any Haskell programmers to insert their own thoughts. I like the look of Haskell myself but I've spent more time with Rust because it seems more practical.
- eru 2y agoIf you like another language that's a bit like Haskell-but-more-practical, give OCaml a try. They even have a for-loop in OCaml!
- habitue 2y agoThere's... forM_ in Haskell. that's basically a for loop, right?
- eru 2y agoYes, you can implement your own loops in Haskell and OCaml (and Scheme and even the GCC-variant of C). However, I meant specifically that OCaml is so 'pragmatic' that they have a for-loop as a built-in syntactic element in the language. They also have mutable variables built-in. In eg Haskell those are 'only' available as part of the standard library.
- habitue 2y agoSorry, bad attempt at humor. I knew what you meant, I was just poking fun at forM_ for being bizarre and unergonomic
- tome 2y agoWhat do you find bizarre and unergonomic about it?
- habitue 2y agoIf you're quite used to Haskell, it's nbd. If you're coming from another language with for loops and someone tells you it's a for loop, you might be surprised that you need to use $ and the loop variable comes after the sequence for x in range(10): print(x) forM_ [0..10] $ \x -> putStrLn x
- karmakurtisaani 2y agoI'm convinced the people who came up with Haskell syntax were on some sort of bath salts.
- nequo 2y agoThe reason it looks the way it does is that forM_ is just a function like any other, not a keyword in a dedicated syntactic construct.
- karmakurtisaani 2y agoYep, and then there's the $, \ and PutStrLn. As a non-Haskell programmer none of those mean anything to me.
- nequo 2y ago$ is short for “put everything to the right inside parentheses” and \x -> y defines an anonymous function. Why do you expect to understand the syntax of a language you never studied?
- karmakurtisaani 2y ago> $ is short for “put everything to the right inside parentheses” There's, you know, also the actual parentheses that everyone already knows. > Why do you expect to understand the syntax of a language you never studied? Because most languages have a syntax that you can grasp almost immediately, since they conform to a common syntax, rather than invent everything all over again. Then you can focus on the actual features of the language and are not bogged down by syntax.
- reduck 2y agoYour profile says > Emacs/Lisp forever I think of Haskell as the declarative statically typed lisp I’ve always wanted.
- danieltanfh95 2y agothen you've never really wanted a lisp...
- kccqzy 2y agoRust is indeed more practical than Haskell, I wouldn't deny that. But Rust lacks full support for higher-kinded types. Exploring a few type classes (known as traits in Rust) like Applicative, Foldable, Traversable can really open your mind. An exaggerated quip by Haskellers is that there are entire libraries on NPM that simply implement the single function `traverse`. While that's an exaggeration, it really helps to look at a few dozen things the single `traverse` function can do to realize its generality.
- eru 2y agoWell, we have entire libraries in Haskell that implement `traverse` for a specific data type, too. The nice thing in Haskell is that the language is strong enough that we can tell the compiler that all those disparate implementations have something in common.
- develop7 2y agoCould you elaborate on the "more practical" bit?
- julianeon 2y agoMore jobs I could get with it, more open source tools or projects I could work on with it.
- kccqzy 2y agoI just thought of one more thing. I really like -fdefer-type-errors in GHC and wish Rust has something similar. Both Rust and Haskell are very opinionated in the way the program is organized. Adding a seemingly small feature can often result in larger-than-expected refactoring. (In Haskell, one might need a new monad transformer layer or convert non-monadic code to monadic; in Rust one might have to rethink ownership patterns or add Rc to many places.) In GHC, type errors can be deferred until run time, until the point where the expression containing the type error is forced. If the expression containing the type error is never evaluated, the program works; if it is, you get an exception raised. This combines especially well with laziness: for example one can find the length of a list even though evaluating the element of the list would result in runtime exceptions. This is useful when I'm halfway through a large refactoring, when there are plenty of errors remaining, but I want to run my test suite to determine whether the parts without compiler errors actually pass their tests.
- mcguire 2y agoAs long as you remember to turn it off after you're finished refactoring. :-) (Yeah, I'm the guy with the co-worker who kept turning off -Wall in C++ because "nobody has time for that".)
- dboreham 2y agoUnfortunately not a very well informed article. Not outright wrong, just sounds like the 100th re-telling of The Illiad. Haskell might have something to do with spreading FP more widely, but it's hardly the origin of the movement. No mention of ML. No mention of lisp, APL, Miranda, ...
- vzaliva 2y agoI get a bit annoyed when people focus too much on the "functional" aspect when discussing Haskell. True, it's a significant part of it, but there are other functional languages that go back as far as Lisp. What sets Haskell apart from these languages is its strong typing, lazy evaluation, algebraic data types (along with supportive matching syntax), and many other small language features which together make it a really nice language.
- GrantMoyer 2y agoSome other features I really miss from Haskell when programming in other languages are the dedicated function composition and application operators, curried functions by default, and support for partial application of operators.
- throwawaymaths 2y agoWhat truly sets Haskell apart is how much the language shoehorns you into being an architecture and abstraction astronaut
- tome 2y agoI program Haskell every day and don't feel like I've been shoehorned into being "an architecture and abstraction astronaut". I do feel I've been gently nudged away from worst practices[1] though. Could you elaborate more about what you mean, maybe giving some examples? [1] https://www.haskellforall.com/2016/04/worst-practices-should-be-hard.html https://www.haskellforall.com/2016/04/worst-practices-should...
- throwawaymaths 2y agoMaybe just scarring from working with haskellers who are writing c++. The project has been delayed probably months due to shitty abstractions. Has never met a self imposed (generous) deadline. They keep breaking the up stack contract that I depend on. Why they didn't just choose c for this project is infuriating. Literally was in a meeting where a new hire was given the green light because "she was a language lawyer but not enough of a language lawyer to get in the way". Fuck that.
- mitchbob 2y agohttps://archive.ph/qP6Sa https://archive.ph/qP6Sa
- friend_and_foe 2y agoI've dabbled with Haskell. I like it a lot, but I want to like it more and I just can't. I don't come from a CS background, I'm pretty good mathematically, and the syntax is just beautiful to me. I remember when I first understood recursion instead of loops, I was amazed. But the whole no side effects thing... I just can't wrap my head around monads. I understand the benefits of no side effects, I still can't figure out how to write code, test it, improve, you know, iterate over it. It feels to me like you need to have your entire program understood and specified before you can write a single line of code. That, and it seems like you need to have a complete understanding of the entire standard library just to get anything done. When I go into Haskell community groups to get some help, I'm usually met with walls of things I don't understand, which is why I'm there I'm the first place. If I could get over these two road blocks I really think I'd write everything I could in the language. I hope to do that some day soon, but it's really hard when you're expected to already get it by the community. I just want to know how to do IO without a complete refactor and be able to read some documents on a library and start using it.
- poorlyknit 2y agoTry using it for concrete problems you have today, start small. I used it to write a small calorie counting web app and some other tiny projects and picked it up that way.
- friend_and_foe 2y agoWell, I wrote a series of functions doing a bunch of mathematical calculations, making lists and that. But when I went to 1) read a file, 2) output results to a file, I ran into some trouble. This was for a real use case I had. Writing the code to do all the calculation was really enjoyable and pretty easy to pick up. Actually turning it into a useful program not so much. I used no libraries and wrote all the math myself, because when I went to investigate libraries none of them seemed to explain what they do in language someone who didn't already know would understand. When I went in stackexchange and other community spaces I got similar results.
- 2y ago
- vaibhavsagar 2y agoThis article doesn't touch on what I consider to be the central feature of Haskell: it is lazily (more precisely non-strictly) evaluated. A lot of the other aspects of it, such as monadic IO, follow from that decision.
- tasuki 2y agoHow does monadic IO follow from laziness?
- nequo 2y agoLaziness requires immutability to work well, and that means you need to represent mutations such as IO operations in an immutable cover like the IO monad.
- tasuki 2y agoMhm, I see now. Perhaps immutability without the laziness would also lead to monadic IO ?
- kccqzy 2y agoYou've got it backwards. Laziness requires mutation to work well. Laziness is just a thunk (a closure) that can be overwritten by a value at a later time. It is impossible to implement laziness if you cannot mutate memory: if the address of the unevaluated closure and the evaluated value cannot be the same, you have to update references to the closure into references to the value, but you cannot do that if you can't mutate memory! People always assume garbage collectors in Haskell might somehow be different due to immutability. But due to laziness it works just like Java garbage collection because laziness requires mutability.
- nequo 2y agoI don't quite understand. You don't update any references when thunks are evaluated, GHC's runtime does. The runtime shields you from any mutation, doesn't it? (Unless you explicitly ask it to let you mutate a value in memory, of course. But that goes beyond the normal evaluation of thunks.)
- librasteve 2y agoraku (raku.org) was implemented by a team who were encouraged to cut their teeth on Haskell. The first complete implementation of a raku parser - PUGS - was written in Haskell. This tradition shows in that raku offers a natural path for Haskell coders to come to raku and still use many of their familiar Haskell idioms. Here is the Haskell -> Raku guide: https://docs.raku.org/language/haskell-to-p6 https://docs.raku.org/language/haskell-to-p6. Raku balances imperative, functional and OO styles in a unified syntax. Functional programming primitives include currying, lazy and eager list evaluation, junctions, autothreading and hyperoperators (vector operators).
- foretop_yardarm 2y agoIt’s a great language for sure. I do worry about the bus factor though, especially given they’ve not had a major release since the most prolific contributor left after some community issues.
- arunix 2y agoWhat were those community issues?
- librasteve 2y agoraku has hit some community issues over the last few years, from (justifiably) standing on the perl versioning when called perl6 and some other issues from time to time. since the name change to raku some years ago, the tussling over the future of perl has declined to nothing on the other issues, well many OSS communities suffer from falling out of individuals at times - all the same the raku commit unity is healthy and large enough to be making slow but steady progress toward the release of v6.e, with a lot of cool features already in preview it’s a supportive and active community and i’d invite you to come over to Discord or IRC and say hi here are the stats on git rakudo since 20 April… _Excluding merges, 7 authors have pushed 133 commits to main and 181 commits to all branches_
- yobbo 2y agoIf you're learning haskell and want an exercise that motivates monads and more, this is great: https://github.com/lsmor/snake-fury https://github.com/lsmor/snake-fury You build a snake game in stages.
- torginus 2y agoA bit of an off topic, but I think FP is a flawed concept in practical terms - it focuses on disallowing local mutation, but usually does nothing to prevent global mutation (which usually happens when the program interacts with its environment via network/OS calls etc.). The resulting programs are just as crash prone as if they were written in Java. Why did nobody go for the actually useful sweet spot - allowing procedural/local mutation, but making the procedures themselves 'pure' and taking care to control side effects on the program scale? This would allow for things like actually useful time travel debugging and runtime code modification while keeping the performance and familiarity of procedural languages.
- nequo 2y ago> allowing procedural/local mutation, but making the procedures themselves 'pure' and taking care to control side effects on the program scale? This is what Haskell does by encouraging you to bundle the part of your code that does mutation into, for example, a state monad, and pass the result of the monadic computation to other pure functions.