3 ms·
I find that too: Purity is Haskell's fundamental killer feature. Other languages now also have quite sophisticated type systems, some of which can do specific
by nh2 3y ago
I find that too:
Purity is Haskell's fundamental killer feature.
Other languages now also have quite sophisticated type systems, some of which can do specific checks beyond Haskell in certain areas (Rust's control flow analysis, TypeScript's ways to do "gradual" typing of JS), while Haskell can do more in general.
But only in Haskell can I look at a function's type and know it doesn't do any IO.
In development and production, this allows you to immediately skip over large amounts of code when debugging issues. Pure functions are a key reason why Haskell is good at correctness and maintainability.
- nh2 3y ago(I say "only in Haskell" disregarding some more sophisticated or specific languages such as Agda, Idris, Futhark, etc. but those are a lot more niche.)
- logicchains 3y agoNim and D both have this feature. Among more popular languages, C++20 constexpr comes close: if you see a constexpr function, you know it's a "pure" function. Although there are still some things that can't be done in constexpr functions, the list is getting smaller and smaller with every new version.
- tome 3y agoEffect tagging in first order, monomorphic code is easy. Doing it in the higher order and polymorphic case is the tricky bit. Do Nim and D support that?
- thesz 3y agoconstexpr reduces general side effects. Can we reduce specific side effects? For one very important example, consider software transactional memory. It has general side effects in the implementation behind the scenes, but inside transaction code they are not allowed. What will C++ solution look like? stmconstexpr?
- JonChesterfield 3y agoI thought STM was dead. Seems to be minimal adoption within clojure and all the hardware which tried to do it has been disabled for being broken. What makes it a particularly important example? The C++ plan of attack probably is more syntax though. Maybe parameterise constexpr, constexpr<input_only_io> or similar.
- ParetoOptimal 3y ago> I thought STM was dead. My company codebase makes generous use of STM in Haskell. STM is the first concurrency solution I reach for in Haskell and I believe it's the idiomatic thing to do.
- dwohnitmok 3y agoSTM is very pervasively used in Haskell. It's usually among the first tools a production Haskeller would reach for when dealing with concurrency. It has died in other ecosystems mainly because it really shines when you have a lot of pure functions and a static type system, which is really up Haskell's alley. Any impure functions really spoil the soup. Clojure's STM implementation is missing crucial combinators to combine different STM actions compared to Haskell (e.g. Haskell's `orElse`), which makes it much less useful. It's also more difficult to remember how to compose STM actions in a dynamically typed language, since you can't directly inspect the action at the REPL in the same way you would do with a simple data structure, which means those few Clojure codebases which use STM don't tend to use it pervasively, but instead confine it to a single place, because it gets too easy to make the equivalent of type errors in Haskell (but which are much more difficult to diagnose because they're not really type errors from the perspective of Clojure). Or to put it another way, Haskell's STM implementation focuses on STM actions as first-class entities, which allows you to have all sorts of reusable actions scattered around your codebase or even stored in data structures (e.g. a list of actions). This is also why there are combinators for combining different STM actions (e.g. `orElse`) rather than just operators on transactional references. This means you can build up a rich library of actions in different places throughout your codebase, then at the "very last moment" in your program you atomically combine different STM actions together (ensuring through atomicity that they all see a consistent view of the world). Clojure's STM implementation on the other hand focuses exclusively on transactional references, which means it's difficult to build up a library of STM action "lego pieces" that you can reuse throughout your codebase. You can try to retrofit the same thing, but then you run into mismatches between different actions which is what I alluded to with type errors. This lack of composability is my view as to why STM has mostly withered in Clojure.
- thesz 3y agoI used to entertain myself embedding various languages into Haskell, mostly hardware description related. Usually, one goes with a static parameterization of a monad. But [1] shows that it is possible to have a dynamic parameterization, where underlying types of a state can change. [1] http://blog.sigfpe.com/2009/02/beyond-monads.html http://blog.sigfpe.com/2009/02/beyond-monads.html This means that we can control state types and, borrowing from ST monad, we can control introduction of resources and their use. If certain free type variable is in state, we can use associated resource. Deletion of resource is a deletion of free variable from a state parameterization. All this is from 2009 or so. The borrow checker of Rust is a library in Haskell, if you patient enough. The purity of Haskell made many these libraries possible, exactly because we can control different side effects.