4 ms·
Literally anything written in Haskell. When you write stateful code in Haskell (such as code that reads from a database, makes a network call, or does IO, to us
by justinpombrio 8y ago
Literally anything written in Haskell. When you write stateful code in Haskell (such as code that reads from a database, makes a network call, or does IO, to use your examples), that code will be wrapped in a Monad. Thus the type signature of the code shows that it's stateful code, and Haskell's type checker will ensure that any code that calls it also has a stateful type. For example, if a function takes in an `Int` and returns an `Int`, and along the way may directly or indirectly perform IO, that function will have type `Int -> IO Int`.
Now of course, you don't have to cleanly separate a functional core from a stateful shell. But if you don't, all of your code is going to end up wrapped in nested Monads declaring all of the ways that it's inadvertently stateful, and that's a very painful way to program. So Haskell pushes you strongly towards having a functional core and stateful shell.
For projects written in Haskell, the wiki has a long list:
https://wiki.haskell.org/Haskell_in_industry https://wiki.haskell.org/Haskell_in_industry
- smadge 8y agoI agree, but I think it still takes some coding self-discipline to write code with a functional core and stateful shell in Haskell. There’s little stopping you from having every return type wrapped in the IO monad. It’s not any more unnatural to do that than it is to code in any imperative language.
- justinpombrio 8y ago> It’s not any more unnatural to do that than it is to code in any imperative language. Yeah, I guess the `do` notation makes it pretty painless. If you start mixing monads, though, things get hairy quickly.
- waluigi 8y agoMonad Transformers aren't _that_ bad, the MTL style of doing things makes it all pretty painless. It also provides a huge opportunity for testing. At a very high level, you describe all of your effects as a series of embedded, compostable DSLs that you define interpreters for. The awesome part is that you can switch out the interpreters at will, so you can, for example, replace something that handles network requests with something that returns dummy data almost effortlessly.
- justinpombrio 8y agoI think we have different pain thresholds. I would consider this very painful: http://hackage.haskell.org/package/transformers-0.5.5.0/docs/Control-Monad-Trans-Class.html#g:7 http://hackage.haskell.org/package/transformers-0.5.5.0/docs... > It also provides a huge opportunity for testing. [...] That's a neat point, thanks for bringing it up.
- vmchale 8y agoHaskell actually has a reasonably functional way of approaching things like I/O (in part due to laziness), so that you can e.g. parallelize I/O actions by passing them to a `parallel` function.