# Why use an effect system?

**URL:** <https://discourse.haskell.org/t/why-use-an-effect-system/10841>\
**Category:** Learn\
**Created:** [November 24, 2024, 6:56pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841 "2024-11-24T18:56:49Z")\
**Posts on this page:** 20\
**Page:** 3

<div class="post-metadata">

**Author:** ![darkxero](https://avatars.discourse-cdn.com/v4/letter/d/f07891/32.png) [@darkxero](https://discourse.haskell.org/u/darkxero)\
**Post date:** [November 29, 2024, 1:58am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/41 "2024-11-29T01:58:04Z")

</div>

> [@Bluefin compared to effectful \[video\]](http://discourse.haskell.org/t/bluefin-compared-to-effectful-video/10723/78):
>
> What’s the point of granularity means if all those finely-slided effects are going to be all mashed together again into an I/O action?

If you know what the effect is you can react accordingly.

You can retry if there’s a connection timeout but you can choose not to get stuck retrying if the file you want to send is corrupted.

You can use custom exceptions here but now you have to track what comes from where and catch accordingly.

> [@vshabanov](#):
>
> When I first heard about adding a lot of “effect” annotations 15 or so years ago, my colleague pointed out that there was a similar thing in Java – checked exceptions, and they’re widely considered an antipattern.

You can argue that all alternatives are abused and turned into an antipattern.

People abuse checked exceptions and now you have 50 different checked exceptions spreading across functions when you could use a result type. Some checked exceptions have no real reason to exist: for example the constructors that take string arguments and throw an exception when the argument is unsupported when all you needed was an enum.

People abuse unchecked exceptions and now you don’t know what or where can explode for whatever reason so you add a top level try catch and have to debug on production and add try catches on the classes you find out you need granularity and you better wish reality doesn’t change otherwise it’s patch time again. Turns out that unreliable webservice does want a nested try catch rather than blowing up and trying again 10 minutes later.

People compromise: now they are writing “throws Exception” everywhere and now you can see what blows up. And everything can blow up. For whatever reason. At least you know now. Maybe it’s an SQLException, there was a timeout because the database got a nasty query. Maybe it’s an IOException because the file was locked for some reason. Maybe it was a null pointer? Who knows. It’s the unchecked exceptions abuse scenario made explicitly manifest. Also, please don’t turn exception messages into stringly typed exceptions.

People ditch exceptions and now use result types for everything. Now there’s question marks absolutely everywhere. Not knowing where, which and how to handle the results, exactly, they panic and call it a day. It will never happen anyways, right? Now they want to make the program runnable long term, reliable, and scalable, so they introduce threads to go blazingly fast and they have to catch the panics to stop the program from crashing. Back to exceptions we go.

I think the universal conclusion we can draw from all these cases is that it’s better to push IO, the allmother of exceptions, to the edge of your program, as far away as possible. Handle them however you like. Discretion is key.

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [November 29, 2024, 3:55am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/42 "2024-11-29T03:55:07Z")

</div>

> If you know what the effect is you can react accordingly.

But you won’t know if all you’ve got is an I/O action:

- produced by some effect system as _“the lowest common denominator”_.

- and that effect system can’t cope with the failure.

Therefore you still have to track what is failing where and catch accordingly.

* * *

> You can argue that all alternatives are abused and turned into an antipattern.

There’s no need to argue - according to:

- [Browse and search packages | Hackage](https://hackage.haskell.org/packages/search?terms=effect+system+%28deprecated%3Afalse%29) (`effect system (deprecated:false)`)

there is over 250 packages pertaining to effect systems. As for exception _“frameworks”_ :

- [Browse and search packages | Hackage](https://hackage.haskell.org/packages/search?terms=exception+%28deprecated%3Afalse%29) (`exception (deprecated:false)`)

…only 217 (but I note that some are also connected to certain effect systems).

So can _any_ unifying concept be abstracted from all of this?

* * *

> […] IO, the allmother […]

# `type IO a = Eff All a`

# 
Q: What do you call the _deletion_ of over 200 different effect systems?  
A: **A good start.**

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [November 29, 2024, 6:24am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/43 "2024-11-29T06:24:49Z")

</div>

> [@darkxero](#):
>
> I think the universal conclusion we can draw from all these cases is that it’s better to push IO, the allmother of exceptions, to the edge of your program, as far away as possible.

Prior to version 1.3, Haskell went even further - `IO a` didn’t exist! So the entire program was just an ordinary effect-free function:

```haskell
main :: [Response] -> [Request]

```

with the role of `runDialogue` (from the aforementioned `dialogue` package) delegated to a rather-hefty subroutine in each Haskell 1.2 implementation. But this denotative style was deemed [embarrassing](https://www.cs.tufts.edu/comp/150PLD/Papers/awkward.pdf), and prompted the switch to [monadic I/O in Haskell 1.3](https://web.archive.org/web/20080325064317/http://www-fp.dcs.st-and.ac.uk/~kh/papers/io-tutorial/section3_2.html):

> [@](#):
>
> The monad constructor `IO` is a liberation to the purist functional programmer in that it permits expression of arbitrary imperative commands within a higher-order type-secure language. Unlike languages like Lisp or ML, in which arbitrary expressions may have side-effects, only expressions of monadic type may do so in Haskell. The rest of the language is undisturbed.

But now `IO a` is deemed _“semantically opaque”_, and apparently needs to be finely-sliced into systems of effects: 250 of them and counting (…unless the effect system doesn’t have a typed effect which matches the actual effect; then it’s back to that _“lowest common denominator”_, `IO a` - hrm).

Be they absent from or present in Haskell, effects (side or otherwise) are frustrating for many to to deal with…

> [@](#):
>
> A strange game.  
> The only winning move is  
> not to play.
> 
> How about a nice game of chess?
> 
> [_Joshua_](https://nzwargamer.net/wargames-11-11-movie-clip-the-only-winning-move-1983-hd/).

---

<div class="post-metadata">

**Author:** ![FPtje](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/fptje/32/5773_2.png) [@FPtje](https://discourse.haskell.org/u/FPtje)\
**Post date:** [November 29, 2024, 7:52am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/44 "2024-11-29T07:52:37Z")

</div>

I’m not sure the hackage list for effects related packages is a real argument for anything. People like reinventing wheels, especially in Haskell. There are tons of variations for all sorts of concepts: effects, transformers, exceptions, lenses, database libraries, array representations, sorting algorithms, “best way to represent a piece of text”, streaming, testing, you name it.

In the end a handful become big. Then you can have discussions about which library has which good idea. That’s what this thread was originally. It looks like the discussion now is going more towards “effect systems suck altogether”, with wordings like “solution looking for a problem”, comparisons to Java and making Haskell unattractive for newbies.

Maybe we can take a step back. What are we really discussing here? Is it whether one does or does not prefer using effects themselves, or is it whether _other people_ should or should not be working with effects?

---

<div class="post-metadata">

**Author:** ![tomjaguarpaw](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/tomjaguarpaw/32/1230_2.png) [@tomjaguarpaw](https://discourse.haskell.org/u/tomjaguarpaw)\
**Post date:** [November 29, 2024, 8:34am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/45 "2024-11-29T08:34:12Z")

</div>

The topic of the merits of effect systems is very interesting but has diverged significantly from the original topic. Perhaps a mod would be able to split the recent posts that are not about Bluefin and effectful into a new thread?

---

<div class="post-metadata">

**Author:** ![jeukshi](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jeukshi/32/4040_2.png) [@jeukshi](https://discourse.haskell.org/u/jeukshi)\
**Post date:** [November 29, 2024, 9:31am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/46 "2024-11-29T09:31:23Z")

</div>

> [@vshabanov](#):
>
> “I need mocking and this requires the effect system” – no, seen the `Connection` above? It’s an _abstract data type_, it can be a record of functions and has your mocking.

You made a lot of good points, but this one got me thinking. Do you propose record of functions as a good alternative to effect systems?

But if that is the case, `Bluefin` actually is a fancy record of functions solution!

```haskell
write :: Connection -> Foo -> IO ()
write :: (e :> es) => Connection e -> Foo -> Eff es ()

```

I don’t understand how one `write` is modular and reusable, while the other isn’t. Both accept arguments that are going to be used to perform some action. Both exist in codebases where lots of stuff is in `IO` or `Eff` respectively. The only difference I see is that `IO` allows running tons of code, while `Eff` is restrictive to what record `Connection` allows.

Even more so, many of your points apply to `Bluefin` the same way as they apply to records of functions. How come one is closer to `AbstractEffectFactory` than the other?

> [@vshabanov](#):
>
> makes Haskell unattractive for newbies

I think what makes Haskell unattractive to newbies is the lack of simple guidelines on how to structure applications. Haskell Spring could use the fanciest effect library. It would be fine, as long as it takes you by the hand, like Java Springs does.

Meanwhile, I still see `mtl` recommendations, I guess for the lack of better “standard”.

> [@vshabanov](#):
>
> Java – checked exceptions, and they’re widely considered an antipattern.

Java is great at having good ideas and making them look bad. It made a whole generation of developers fear “abstractions”.

Java doesn’t have `IO` type, but they do use a lot of some sort of record of function passing to relevant objects, but usually automated with annotations.

---

<div class="post-metadata">

**Author:** ![jackdk](https://avatars.discourse-cdn.com/v4/letter/j/9f8e36/32.png) [@jackdk](https://discourse.haskell.org/u/jackdk)\
**Post date:** [November 29, 2024, 10:53am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/47 "2024-11-29T10:53:59Z")

</div>

> [@atravers](#):
>
> …how in Haskell are you meant to make them all work together in your new program?

I like [this idiom propsed by Ollie Charles](https://blog.ocharles.org.uk/posts/2017-08-23-extensible-effects-and-transformers.html) (@ocharles your SSL cert needs renewing btw).

```haskell
class Monad m => MonadWhatever m where
  liftWhatever :: Free (Coyoneda WhateverAPICall) a -> m a 

```

Unless you need to take in monadic arguments for some reason, it’s quite flexible and lets other effect libraries provide the necessary instances without you having to depend on every effect library in the library’s core package.

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [November 29, 2024, 9:40pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/48 "2024-11-29T21:40:21Z")

</div>

> [@jeukshi](#):
>
> Java is great at having good ideas and making them look bad.

No, _checked exceptions_ are a bad idea:

- As mentioned earlier, from _The C++ Programming Language, 4th edition_ (2011):

- There’s also these observations from [**2003**](https://www.artima.com/articles/the-trouble-with-checked-exceptions):

So how many more programming languages will have to **avoid** them before people are convinced that checked exceptions are a bad idea?

* * *

> [@jackdk](#):
>
> ```haskell
> class Monad m => MonadWhatever m where
> liftWhatever :: Free (Coyoneda WhateverAPICall) a -> m a 
> 
> ```

New Haskellers are having enough problems with the monadic interface:

> [@](#):
>
> Still, today, over 25 years after the introduction of the concept of monads to the world of functional programming, beginning functional programmers struggle to grasp the concept of monads. This struggle is exemplified by the numerous blog posts about the effort of trying to learn about monads. From our own experience we notice that even at university level, bachelor level students often struggle to comprehend monads and consistently score poorly on monad-related exam questions.
> 
> [Visual Support for Learning Monads](https://repository.ubn.ru.nl/bitstream/handle/2066/181576/181576.pdf) ( **2017** )

…do they really need more problems by _“giving”_ them [extra artefacts](https://www.math.columbia.edu/~esaunders/YonedaLemma.pdf) from [one of the most abstract branches of mathematics](https://www.mathematik.uni-marburg.de/~loogen/Lehre/ws06/Konzepte/tackling.pdf)?

---

<div class="post-metadata">

**Author:** ![jackdk](https://avatars.discourse-cdn.com/v4/letter/j/9f8e36/32.png) [@jackdk](https://discourse.haskell.org/u/jackdk)\
**Post date:** [November 29, 2024, 10:41pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/49 "2024-11-29T22:41:15Z")

</div>

> [@atravers](#):
>
> …do they really need more problems by _“giving”_ them [extra artefacts](https://www.math.columbia.edu/~esaunders/YonedaLemma.pdf) from [one of the most abstract branches of mathematics](https://www.mathematik.uni-marburg.de/~loogen/Lehre/ws06/Konzepte/tackling.pdf)?

Ollie’s post shows the rest of the interface; the Coyoneda stuff is an implementation detail that end users don’t need to interact with.

---

<div class="post-metadata">

**Author:** ![jeukshi](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jeukshi/32/4040_2.png) [@jeukshi](https://discourse.haskell.org/u/jeukshi)\
**Post date:** [November 29, 2024, 11:05pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/50 "2024-11-29T23:05:13Z")

</div>

> [@atravers](#):
>
> There’s also these observations from [**2003**](https://www.artima.com/articles/the-trouble-with-checked-exceptions):

I do actually mention this article [here](http://discourse.haskell.org/t/rust-has-no-exceptions/10729). Although I focus on different aspects of it, because some are not very convincing.

Versioning one just smells to me like a mix of magical thinking and java-esque obsession with breaking changes. Not a great mix, tbh. Funny how adding D to foo “breaks client code” (it breaks compilation), but not adding D and throwing it anyway, breaks somebody code at runtime, but that is ok.

Scalability also seems like a problem with something else. So a subsystem throws 4-10 checked exceptions, but why not one? Maybe ADT Subsystem1Errors. Oh, sorry, no ADT in Java. Let’s do subclass of subsystem1, catch some of there, and rethrow less. Can’t be done. Oh, well.

> [@atravers](#):
>
> So how more programming languages will have to **avoid** them before people are convinced that checked exceptions are a bad idea?

So how many more programming languages, after PHP, Python, and JavaScript, have to become stunning successes before we convince ourselves that type systems are a bad idea? Oh, it is not 2003 anymore, and all of those have some form of type checking.

I don’t think whatever was half-baked into Java and C++ in the 90 should forever cast a shadow on that idea.

For one, checked exceptions are provided by libraries here, so no need to worry that standard library `readfile` will annoy everybody forever.

The other thing is, in Haskell we do a lot of result types, especially in pure code, and many of those are checked exceptions in all but name.

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [November 30, 2024, 12:02am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/51 "2024-11-30T00:02:00Z")

</div>

> [@jackdk](#):
>
> the Coyoneda stuff is an implementation detail that end users don’t need to interact with.

That would be a refreshing change:

[https://wiki.haskell.org/Monad\_tutorials\_timeline](https://wiki.haskell.org/Monad_tutorials_timeline)

* * *

> [@jeukshi](#):
>
> I don’t think whatever was half-baked into Java and C++ in the 1990s should forever cast a shadow on that idea.

That looks suspiciously like another variant of [the true Scotsman fallacy](https://fallacyfiles.org/scotsman.html) - _“a properly-designed effect system/exception framework shall not cause any problems…”_

---

<div class="post-metadata">

**Author:** ![vshabanov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/vshabanov/32/2080_2.png) [@vshabanov](https://discourse.haskell.org/u/vshabanov)\
**Post date:** [November 30, 2024, 12:14am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/52 "2024-11-30T00:14:17Z")

</div>

> [@jeukshi](#):
>
> ```haskell
> write :: Connection -> Foo -> IO ()
> write :: (e :> es) => Connection e -> Foo -> Eff es ()
> 
> ```
> 
> I don’t understand how one `write` is modular and reusable, while the other isn’t.

The first one can be used everywhere. It has no dependencies. Its arguments are monomorphic. I can just insert it into any `IO` computation and it will work without the need to change interfaces.

The second one is tightly coupled to the effect system. It’s impossible to convert to a pure `IO` action and pass to a non-`Eff` subsystem as it was specifically designed not to allow `Connection e` to escape. It’s polymorphic, so any data structure or function that uses `Connection e` becomes polymorphic despite no real polymorphism is involved. It’s only reusable within `Eff` framework and unusable outside. Doesn’t look too modular.

> [@jeukshi](#):
>
> Even more so, many of your points apply to `Bluefin` the same way as they apply to records of functions.

I re-read my points and can’t find which of them apply to a record of functions.

> [@jeukshi](#):
>
> I think what makes Haskell unattractive to newbies is the lack of simple guidelines on how to structure applications.

Not sure about “how to structure applications” – it very much depends on the application. But some guidelines about good and bad practices are definitely possible. I said a similar thing before: [Haskell lacks a body of industrial usage wisdom](http://discourse.haskell.org/t/8-months-of-ocaml-after-8-years-of-haskell-in-production/8405/65).

> [@jeukshi](#):
>
> Meanwhile, I still see `mtl` recommendations, I guess for the lack of better “standard”.

And that’s what frustrates me. Effect systems are highly experimental, most of them are not production ready and/or have very serious flaws. Yet somehow they became a necessary pre-requisite for writing basic programs. They’re not.

If a new experimental thing appears, it’s probably better to advertise it as “look, what an interesting way to program” than “this is the future of Haskell”

---

<div class="post-metadata">

**Author:** ![vshabanov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/vshabanov/32/2080_2.png) [@vshabanov](https://discourse.haskell.org/u/vshabanov)\
**Post date:** [November 30, 2024, 12:37am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/53 "2024-11-30T00:37:52Z")

</div>

> [@darkxero](#):
>
> I think the universal conclusion we can draw from all these cases is that it’s better to push IO, the allmother of exceptions, to the edge of your program, as far away as possible. Handle them however you like. Discretion is key.

Agreed. The more pure code and the less `IO` the better.

If one wants better control, it should be a discreet decision, not a jump on a bandwagon.

---

<div class="post-metadata">

**Author:** ![vshabanov](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/vshabanov/32/2080_2.png) [@vshabanov](https://discourse.haskell.org/u/vshabanov)\
**Post date:** [November 30, 2024, 12:44am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/54 "2024-11-30T00:44:54Z")

</div>

> [@jackdk](#):
>
> I like [this idiom propsed by Ollie Charles](https://blog.ocharles.org.uk/posts/2017-08-23-extensible-effects-and-transformers.html)

Surprisingly, the most obvious option – providing a pure `IO’ interface – is missing. This would be the easiest for library users to integrate into whatever framework they’re using.

---

<div class="post-metadata">

**Author:** ![mikeplus64](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mikeplus64/32/3998_2.png) [@mikeplus64](https://discourse.haskell.org/u/mikeplus64)\
**Post date:** [November 30, 2024, 12:58am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/55 "2024-11-30T00:58:28Z")

</div>

> [@atravers](#):
>
> What’s the point of granularity means if all those finely-slided effects are going to be all mashed together again into an I/O action?

- An effect implementation doesn’t necessarily directly interface with `IO` at all
- Limiting the surface area of where `IO` is used (e.g., only in the final unwrapping of an effect system) has its own benefits which are basically the arguments in favour of using pure functions where possible

Yes, everything must eventually be mashed together into an I/O action. But that’s all Haskell code - it must eventually get to `main`. That doesn’t stop us from writing pure functions.

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [November 30, 2024, 1:40am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/56 "2024-11-30T01:40:58Z")

</div>

> An effect implementation doesn’t necessarily directly interface with `IO` at all

That’s why I’ve been taking care to specify the effects as being _“external”_ (as in externally-visible) - as mentioned elsewhere, _“internal”_ effects can be confined `runST`-style.

* * *

> Limiting the surface area of where `IO` is used (e.g., only in the final unwrapping of an effect system) has its own benefits which are basically the arguments in favour of using pure functions where possible.

No.

For a time it was proclaimed that [the solution to [chemical] pollution was dilution](https://www.marinebio.org/the-solution-to-pollution-is-dilution-no), which is false. Now for Haskell, a similar proclamation is being made - _"the solution to the pollution of effects is the dilution of_ `IO a` _into individually-typed effects"_. But one effect seems to **always** be ignored - _the effect on code_.

Be it:

- `Eff [... {- "external" effects -} ...] a`
- or regular `IO a`

…if a change to some obscure definition deep in the program means that definition then relies on an _“external”_ effect, then **everything** that directly or indirectly relies on that formerly-obscure definition (i.e. its _reverse dependencies_) that was ordinary effect-free Haskell code must also be changed. That only using the maximum _“dilution”_ - one _“external”_ effect - or potentially all of them is irrelevant: as (correctly) noted in **Kleidukos** ’s presentation, avoiding nondeterminism means all effects must be used in a sequential context which can only be accessed _in full_ via the monadic interface.

So using individual _“external”_ effects is **definitely not** the same as just using ordinary effect-free Haskell definitions.

---

<div class="post-metadata">

**Author:** ![darkxero](https://avatars.discourse-cdn.com/v4/letter/d/f07891/32.png) [@darkxero](https://discourse.haskell.org/u/darkxero)\
**Post date:** [November 30, 2024, 2:49am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/57 "2024-11-30T02:49:21Z")

</div>

> [@atravers](#):
>
> So can _any_ unifying concept be abstracted from all of this?

The unifying concept is indeed the existence of IO. You can choose how you want to deal with it. Maybe you feel more at ease with a “no missile launches here” tag effect reminded to you by the type system. Maybe not. Thus, each library with its opinion.

> [@atravers](#):
>
> Prior to version 1.3, Haskell went even further - `IO a` didn’t exist! So the entire program was just an ordinary effect-free function

Also, from the paper:

> [@](#):
>
> This request/response story is expressive enough that it was adopted as the main input/output model in the first version of Haskell, but it has several defects:
> 
> • It is hard to extend. New input or output facilities can be added only by extending the Request and Response types, and by changing the “wrapper” program. Ordinary  
> users are unlikely to be able to do this.  
> • There is no very close connection between a request and its corresponding response. It is extremely easy to write a program that gets one or more “out of step”.  
> • Even if the program remains in step, it is easy to accidentally evaluate the response stream too eagerly, and thereby block emitting a request until the response to that request has arrived – which it won’t.

The representation was error prone.

---

<div class="post-metadata">

**Author:** ![atravers](https://avatars.discourse-cdn.com/v4/letter/a/45deac/32.png) [@atravers](https://discourse.haskell.org/u/atravers)\
**Post date:** [November 30, 2024, 5:43am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/58 "2024-11-30T05:43:43Z")

</div>

It certainly was! So when a way was found to `do` it, dialogue-based I/O (which kept the management of _“external”_ effects **outside** Haskell) was replaced with ~~_functor_~~  ~~_applicative_~~  ~~_arrow_~~  ~~_comonad_~~ monad-based I/O in the form of the abstract type `IO a` (which brought the management of _“external”_ effects **inside** Haskell).

But now, `IO a` has been deemed as being semantically error-prone, in need of dilution into separate _“external”_ effects. However there’s a problem here too - as noted in **Kleidukos** ’s presentation, [side effects are arbitrary](https://youtu.be/lRU6TDgadqw?t=372) (with _“external”_ effects being _externally-visible_ side effects). So how `IO a` should be diluted is also arbitrary - there are no _“unit effects”_ in the same way there are chemical elements…and now there are more effect systems for Haskell than the 92 naturally-occurring elements of chemistry.

To summarise:

| _“External”_ effects are managed… | Problem/s |
| --- | --- |
| outside Haskell (_“wrapper”_ ) | Error-prone (finnicky!) |
| inside Haskell (`IO a`) | Error-prone (semantically!) |
| inside Haskell (effect system) | Error-prone (wrong choice!) |

…are there _any_ other alternatives that can work for Haskell?

---

<div class="post-metadata">

**Author:** ![BurningWitness](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/burningwitness/32/3665_2.png) [@BurningWitness](https://discourse.haskell.org/u/BurningWitness)\
**Post date:** [November 30, 2024, 7:28am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/59 "2024-11-30T07:28:59Z")

</div>

In my view the only true benefit to effect systems is that it’s the only sane way of getting dynamic dispatch in Haskell, so for anything production-grade you \*could\* have a mirror test system that behaves exactly the same, but calls test versions of all real-world things it links to. It’s still a remarkably hard thing to achieve however: you have to know how to structure your code and you have to avoid any type shenanigans because recursive type families are exponentially slow.

I sympathize with the idea that it would be nice to keep track of which effects are used in any given function, it’s a strongly typed language after all, but having to choose one of five effect libraries and then getting “rewarded” with both a bulkier codebase and performance overheads squarely puts this in the “only use at work on the high level” territory. If GHC had seamless native support for this and some way to precompile functions that only use one implementation at runtime, it would be a no-brainer.

I don’t see a natural benefit of using `Reader`s over plain argument passing. Passing arguments indeed looks bulkier at the first glance, but it allows me to divide the context to the smallest necessary bits at every point. `Reader` on the other hand necessitates using lens (or more recently field selectors), blurs the line between which arguments are actually needed in a given function, and does not look any prettier.

I don’t see a need in checked exceptions, I lean on the side of “if I expect something to fail without terminating the process, then it’s not an exception”. It’s a natural extension of trying to decouple everything pure from effects, as I can simply use datatypes to convey that an undesired (but not critical) condition has occurred instead of breaking the control flow. It’s also faster.

Regarding lack of modularity in effects libraries, that’s pretty much how all of Haskell’s ecosystem works: instead of providing the minimal tools and letting users stitch things together, it’s instead expected that you use one of fifteen convenient runner functions and for anything beyond that you have to dive into non-PVP-compliant internals. This won’t change unless the community agrees it’s undesirable, good luck with that.

---

<div class="post-metadata">

**Author:** ![osa1](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/osa1/32/4710_2.png) [@osa1](https://discourse.haskell.org/u/osa1)\
**Post date:** [November 30, 2024, 7:46am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/60 "2024-11-30T07:46:25Z")

</div>

> [@atravers](#):
>
> There’s also these observations from [**2003**](https://www.artima.com/articles/the-trouble-with-checked-exceptions):
> 
> - Let’s start with versioning, because the issues are pretty easy to see there. Let’s say I create a method foo that declares it throws exceptions A, B, and C. In version two of foo, I want to add a bunch of features, and now foo might throw exception D. It is a breaking change for me to add D to the throws clause of that method, because existing caller of that method will almost certainly not handle that exception.

Regardless of whether you reflect the change (throwing a new type of exception) in the type signature or not, throwing a new type of exception **is** a breaking change (i.e. can break clients), and the users should be aware of it. It should cause a major version bump in your library even without checked exceptions.

Clients then need to consider what to do about the exception, and revisit the call sites.

My observation is that a lot of commentary on checked exceptions from 2000s and earlier (mostly in the context of C++ and Java) do not apply to today’s type systems, scale, and language features. Java did it poorly, and left people traumatized.

There will always be a use case for unchecked (and asynchronous) exceptions, like `StackOverflow`, `HeapOverflow`, and `ThreadKilled`. It probably makes sense to give the users the ability to throw unchecked exceptions as well, and let them decide when it makes sense to have an exception checked vs. unchecked.

Checked exceptions can be modeled as effects, and I suspect with polymorphic variants they can be conveniently composed (I have some notes on this [here](https://gist.github.com/osa1/38fd51abe5247462eddb7d014f320cd2)). No one proved that they can’t be made convenient to use.

[Previous page](https://discourse.haskell.org/t/why-use-an-effect-system/10841.md?page=2)

[Next page](https://discourse.haskell.org/t/why-use-an-effect-system/10841.md?page=4)
