# 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:** 1

<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 24, 2024, 6:56pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/1 "2024-11-24T18:56:49Z")

</div>

Maybe it was already asked before but what are benefits of Bluefin compared to using plain `IO` functions?

Why should I use

```haskell
foo
  :: (e1 :> es, e2 :> es) 
  => Handle1 e1 -> Handle2 e2 -> Eff es Foo

```

instead of a plain

```haskell
foo :: Handle1 -> Handle2 -> IO Foo

```

---

<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 24, 2024, 8:53pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/2 "2024-11-24T20:53:29Z")

</div>

The benefit is that you can remove from the set of effects. If you have

```haskell
foo :: IORef Int -> IORef Bool -> IO Foo

```

then you are stuck in `IO` forever. With Bluefin, if you have

```haskell
foo ::
  (e1 :> es, e2 :> es) =>
  State Int e1 ->
  State Bool e2 ->
  Eff es Foo

```

then you can handle the `State`s, removing them from scope, and even end up with a pure value.

```haskell
result :: Foo
result = runPureEff $
  evalState 0 $ \sInt -> do
    evalState True $ \sBool -> do
      foo sInt sBool

```

---

<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 24, 2024, 10:42pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/3 "2024-11-24T22:42:09Z")

</div>

Same can be done with `runST`:

```haskell
foo :: STRef s Int -> STRef s Bool -> ST s Foo
result :: Foo
result = runST $ do
  sInt <- newSTRef 0
  sBool <- newSTRef True
  foo sInt sBool

```

Plain `IO` also “removes effects” pretty fine:

```haskell
do
  r <- withH1 $ \ h1 -> do
    x <- withH2 $ \ h2 -> foo h1 h2
    -- 'h2' is "removed" at this point
    bar h1 x
  -- 'h1' is "removed" at this point

```

It doesn’t prevent us from putting a handle in a function result, but this can be overcome with a helper like:

```haskell
data Foo s a = Foo { unFoo :: a }
withFoo :: a -> (forall s . Foo s a -> IO b) -> IO b
withFoo x f = f (Foo x)
-- now the 'foo' below won't compile
-- "because type variable ‘s’ would escape its scope"
foo :: IO Int
foo = unFoo <$> withFoo 1 pure

```

Both `ST` and `IO` code looks simpler and have simpler types while allowing to block “effects” from escaping if required.

Is there a need in removing effects from set?

If we need to produce a pure value using the impure algorithm, `runST` allows us to do it. In impure code we might like a DB connection or a file handle not to escape, but is it worth the additional complexity everywhere? People don’t usually store connections in function results.

Are there other benefits of using Bluefin over plain `IO` or `ST`?

---

<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 25, 2024, 7:26am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/4 "2024-11-25T07:26:39Z")

</div>

> [@vshabanov](#):
>
> Are there other benefits of using Bluefin over plain `IO` or `ST`?

I think your question is more “why use effects in the first place?”. It’s a valid question, because Bleufin (or effectful for that matter) is something new to learn, and a little more administrative effort. What does one gain? Quite a few things!

Most importantly for me it’s that an effect system pushes me to think about “What are the different ways my program interacts with the world?”. Separating those different ways into different effects is a wonderful exercise.

A second big benefit is that IO doesn’t tell you much. Could be writing files, network requests, database things. With an effect system, every function will tell you what side effects it has with much more granularity. That helps me understand much better what a function actually does.

Effects have a nature of seperating the “what” from the “how”. That means you can have different implementations for the same effect. This typically works really well to set up mocking for tests. E.g. Replace the Database functionality with pretending you updated something and returning a constant value.

---

<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 25, 2024, 1:04pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/5 "2024-11-25T13:04:29Z")

</div>

> [@vshabanov](#):
>
> Same can be done with `runST`

Correct, but Bluefin does more than `ST`. One way to see Bluefin is as a “generalized `ST`”. It’s generalized because it also treats exceptions and `IO`, neither of which `ST` treats. Regarding the former, you can write

```haskell
bar ::
  (e1 :> es, e2 :> es) =>
  State Int e1 ->
  Exception Bool e2 ->
  Eff es Foo

result :: Foo
result = runPureEff $
  evalState 0 $ \sInt -> do
    handle (\case True -> defFoo1; False -> defFoo2) $
      \exBool -> do
        bar sInt exBool

```

removing the `Exception` from scope, as well as the `State`, and ending up with a pure value. Regarding `IO`, it cannot be removed from scope, but its absence (i.e. the absence of an `IOE e ->` argument) shows that a function does not do `IO`.

> [@vshabanov](#):
>
> Plain `IO` also “removes effects” pretty fine … It doesn’t prevent us from putting a handle in a function result

That pattern is syntactically convenient, and common in the Haskell world (for example, [`withFile`](https://www.stackage.org/haddock/lts-22.43/base-4.18.2.1/System-IO.html#v:withFile)), but it doesn’t actually guarantee removing effects from scope, as you point out.

> [@vshabanov](#):
>
> but this can be overcome with a helper

Unfortunately that’s not sufficient. Consider the following attempt at scoping a resource:

```haskell
withResource ::
  (forall s. Resource s -> IO r) ->
  IO r

useResource :: Resource s -> IO Result

```

Then I can write

```haskell
bad :: IO (IO Result)
bad = withResource $ \resource ->
  pure (useResource resource))

```

and get access to the resource outside of the scope of `withResource`. That’s bad! (@Leary explained this to me in [an earlier thread on the topic](http://discourse.haskell.org/t/bluefin-prevents-handles-leaking/10627/19)).

> [@vshabanov](#):
>
> Both `ST` and `IO` code looks simpler and have simpler types while allowing to block “effects” from escaping if required.

`ST` does allow to block effects from escaping, but it is not really simpler: it’s just doing less. You can write almost the example same code in Bluefin as you would in `ST`, if all you wanted to do was to manipulate state.

`IO` does not allow to block effects from escaping, as demonstrated above.

> [@vshabanov](#):
>
> Is there a need in removing effects from set?

I feel that need, as do some others. Maybe you and different others do not. That’s fair enough. But assuming you _do_ want to remove effects, and you do want value-level effects handles, then I don’t think you’ll find a simpler API than Bluefin’s. (One way this might change is if Haskell got a type level set type. Then we could simplify the types, for example doing away with the `e1 :> es` constraint.)

> [@vshabanov](#):
>
> If we need to produce a pure value using the impure algorithm, `runST` allows us to do it.

Yes, but only as long as you didn’t want to use exceptions as well as state.

> [@vshabanov](#):
>
> In impure code we might like a DB connection or a file handle not to escape, but is it worth the additional complexity everywhere? People don’t usually store connections in function results.

I think it’s worth it. You may not. It’s probably a matter of preference.

> [@vshabanov](#):
>
> Are there other benefits of using Bluefin over plain `IO` or `ST`?

Well, not really, but that’s a bit like asking “is there any other benefit of pure functional programming, besides all functions returning the same result for the same input?”. In both cases the simple foundation provides something very sturdy to build reliable software on top of!

---

<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 25, 2024, 11:24pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/6 "2024-11-25T23:24:40Z")

</div>

Thank you for pointing out the problem with the `(forall ... -> IO a)` workaround.

I agree that if not allowing handles to escape is important then Bluefin is probably the most compact way to implement the “generalized `ST` monad”.

> I think it’s worth it. You may not. It’s probably a matter of preference.

It’s not just a matter of preference, but also the amount of work involved. The issue I see is that I have to wrap all the code in `Eff` monad (a very intrusive change) for the benefit of not allowing a database connection handle to escape. This is quite a hefty price to pay for a problem I have never personally faced.

`ST` is usually very local. It’s still a pure function outside. The effect system infects all the code, makes interaction with other libraries less convenient, requires digging into how it works with exceptions, state, and concurrency.

`effectful` allows not to pass arguments (which I consider a bad practice), so it removes the boilerplate in some places at the cost of adding it in others. A debatable benefit but still a benenfit.

Bluefin adds boilerplate but doesn’t remove much, so its benefit of not being able to store handles and being able to remove them should be really important to justify its use.

I had an experience with a legacy transformers-ridden codebase and I haven’t seen any places where effects were removed. It’s mostly `runTheGood $ runTheBad $ runTheUgly $ .. ` at the top function and that’s it.

My use of `ST` is at most few pages long functions implementing imperative algorithms. Not much place for exceptions there. And `ST` is usually for performance. I’d like to have a full control there without additional layers.

Sorry for the big wet blanket reply. I do think that “generalized `ST`” is a good idea. But I’m not sure yet if it outweighs the simplicity of pure `IO` or `ST`.

---

<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 26, 2024, 8:38am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/7 "2024-11-26T08:38:27Z")

</div>

> [@vshabanov](#):
>
> > I think it’s worth it. You may not. It’s probably a matter of preference.
> 
> It’s not just a matter of preference, but also the amount of work involved.

It’s a trade-off between the amount of work involved and the amount of benefit gained. I don’t think that trade-off can be resolved by anything other than preference due to the variety of factors involved. Do you think it can?

This discussion reminds me of Python fans who say “I don’t need pure functional programming. Most of the bugs I write are not type errors.” I believe them, but then when I try to write Python I get runtime errors like `NoneType object is not callable`.

Perhaps it’s because I try to write in functional style in Python. But that’s the point! The benefit of strongly typed pure functional programming is not so that your programs are strongly typed and pure. The benefit is that it gives you freedom to confidently write in a style you simply can’t risk in a non-typed setting, because there’s too much chance of making a mistake.

I would say the same holds for Bluefin. It’s not just “database handles can’t leak, but I’ve never had that problem in practice”, it’s that _everything_ is well scoped and that gives you an awful lot of freedom to confidently write in a style you wouldn’t have dared try before. For example, you can fearlessly mix [streams](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Stream.html), [consumers](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Consume.html) and [scoped jumps](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Jump.html) (for implemented `break` and `continue`). So it’s not just avoiding a database handle leaking from a top-level running (which is pointless anyway), it’s the freedom to mix 1000 effects without difficulty and unlock a programming style that you couldn’t use before.

---

<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 26, 2024, 9:44am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/8 "2024-11-26T09:44:10Z")

</div>

Be it `IO ...` or `Eff ...`, people have no choice other than to use the monadic interface. So what is the difference between:

- 128 extra exceptions for `IO ...`
- 128 extra _“external”_ effects for `Eff ...`

…?

---

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [November 26, 2024, 10:05am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/9 "2024-11-26T10:05:14Z")

</div>

> [@vshabanov](#):
>
> `ST` is usually very local. It’s still a pure function outside. The effect system infects all the code, makes interaction with other libraries less convenient, requires digging into how it works with exceptions, state, and concurrency.

Effect systems are local in the exact same way as `ST` is. If you run the final handler, then you’re left with a pure value (some effect systems also allow embedding arbitrary IO, in which case they do end up with an IO value in the end, but that is often optional).

> [@Bluefin compared to effectful \[video\]](http://discourse.haskell.org/t/bluefin-compared-to-effectful-video/10723/47):
>
> Be it `IO ...` or `Eff ...`, people have no choice other than to use the monadic interface. So what is the difference between:
> 
> - 128 extra exceptions for `IO ...`
> - 128 extra _“external”_ effects for `Eff ...`
> 
> …?

One big difference is that you can define what all the effects mean in pure Haskell code, instead of having to rely on black box IO primitives.

---

<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 26, 2024, 10:29am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/10 "2024-11-26T10:29:25Z")

</div>

`o_0` How exactly does one define what an _“external”_ effect means using pure (effect-free) Haskell code?

---

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [November 26, 2024, 10:57am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/11 "2024-11-26T10:57:48Z")

</div>

What do you actually mean with “external” effect? I thought you just meant effects in general.

---

<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 26, 2024, 11:05am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/12 "2024-11-26T11:05:45Z")

</div>

_“External”_, as in _“externally visible”_ :

> [@](#):
>
> The reason for introducing a _different_ monad `ST`, rather than just providing these operations over the `IO` monad, is that destructive updates to variables in a program are not _externally visible_ side-effects. We can therefore encapsulate these imperative effects […] Using `runST` we can write pure (non-monadic) functions whose implementation uses imperative features internally.
> 
> [Monads and Effects](https://nickbenton.name/BHM-revised.pdf) (pages 33-34 of 82).

because I/O exceptions can only be legitimately caught in the monadic type `IO a`.

---

<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 26, 2024, 11:37am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/13 "2024-11-26T11:37:12Z")

</div>

> [@atravers](#):
>
> because I/O exceptions can only be legitimately caught in the monadic type `IO a`.

It’s possible that I’m misunderstanding what you’re saying, but in the same way that `IORef` can be wrapped as `STRef s`, providing an interface to mutable state that is guaranteed to be externally pure, `IO` exceptions can be wrapped, providing an interface that is guaranteed to be externally pure. This is what `effectful`’s [`Error` effect](https://hackage.haskell.org/package/effectful-core-2.2.1.0/docs/Effectful-Error-Static.html) is. Bluefin copied that and calls it [`Exception`](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Exception.html).

---

<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 26, 2024, 4:23pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/14 "2024-11-26T16:23:18Z")

</div>

The archetypal examples of externally-visible effects are:

- the modifying of a top-level reference’s contents.

- the various forms of I/O (using files, networks, devices, _etc_).

---

<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 26, 2024, 9:48pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/15 "2024-11-26T21:48:40Z")

</div>

> I don’t think that trade-off can be resolved by anything other than preference due to the variety of factors involved. Do you think it can?

Some things are measurable. It’s possible to count the number of `IO` functions in a codebase and estimate the number of lines to be changed. That would be an effort. Then we can count the effects removed. Then there’s indeed preference – the multiplier we need to outweigh the effort. It may be harder to justify preference in front of a concrete value-to-effort ratio.

> This discussion reminds me of Python fans who say “I don’t need pure functional programming.

I could be experiencing a Blub paradox. And I hoped that I had one when I started working with a monad-transformers ridden codebase. But in the end it turned out to be just a pure overengineering: rigid, tightly coupled, hard to use and hard to extend (`MonadBaseControl` is simply impossible for some use cases).

I hope things are different with Bluefin. But

> For example, you can fearlessly mix [streams](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Stream.html), [consumers](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Consume.html) and [scoped jumps](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Jump.html) (for implemented `break` and `continue`)

I can do the same in IO, or, much better, not do that and write a simple, purely functional code instead. I didn’t choose Haskell to go back to the imperative mess:

- [streams](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Stream.html) – `yield` looks nice for Python, but we already have lazy lists. In `IO` we can use `writeChan` if we like, or call a user supplied callback-function.
- [consumers](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Consume.html) – `await` is not always nice even in JavaScript. Again, we can pattern match on a lazy list, use `readChan`, the standard blocking `readLine` or `await` from the `async` package.
- [scoped jumps](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Jump.html) – I’m sorry, but this is definitely not the code I’d like to see in Haskell.

> it’s the freedom to mix 1000 effects without difficulty and unlock a programming style that you couldn’t use before.

The fact that I can mix effects doesn’t mean I should. It’s important to have an orthogonal modular codebase. Mixing evertything means a mess and a big maintenance pain.

Bluefin looks favourably comparing to other effect systems because it makes this mixing obvious – you see that you pass too many arguments to this function and need to do something with this. But I’m not sure I’d like to change all `IO` (and many pure functions) to `Eff`. The Blub paradox is still strong with me.

Interesting, is it possible to do some parts of Bluefin in pure `ST`? If instead of a custom `Eff` monad we can have an `ST` (with all the standard `ST` functions), but with an early return, or state variables that don’t escape the sub-region. I suspect with some hacks it should be possible to make

```haskell
foo :: (e :> es) => Exception Bar s -> ST es Foo

```

and then we can play with it locally without converting everything to `Eff` (though I don’t use `ST` often and prefer pure functions whenever possible)

---

<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 26, 2024, 10:07pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/16 "2024-11-26T22:07:54Z")

</div>

> [@jaror](#):
>
> Effect systems are local in the exact same way as `ST` is. If you run the final handler, then you’re left with a pure value (some effect systems also allow embedding arbitrary IO, in which case they do end up with an IO value in the end, but that is often optional).

Effect systems are usually used for I/O related effects and the final handler is usually in `main` and returns `()`. So they’re not that local in their standard usage.

And using an effect system when writing a pure code is questionable. Why use monadic code when we can use pure functions instead?

> [@jaror](#):
>
> One big difference is that you can define what all the effects mean in pure Haskell code, instead of having to rely on black box IO primitives.

I would disagree. IO primitives are not a black box – the library code is available, a lot of the basics are covered in research papers and books. Haskell’s I/O and concurrency design is top-notch. And most Haskell developers know how stock I/O and concurrency works.

On the other hand, we have some experimental effects system where we _do_ have to look into pretty convoluted code to understand how it works. And we can have several such systems (they are like JavaScript frameworks nowadays 🙂 ), each with its own idiosyncrasies and most of them much worse than what we have in `base`.

---

<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 26, 2024, 10:40pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/17 "2024-11-26T22:40:44Z")

</div>

> [@vshabanov](#):
>
> It’s possible to count the number of `IO` functions in a codebase and estimate the number of lines to be changed. That would be an effort. Then we can count the effects removed. Then there’s indeed preference – the multiplier we need to outweigh the effort. It may be harder to justify preference in front of a concrete value-to-effort ratio.

I may have misunderstood you. It sounds like you might be talking about the effort involved in converting an existing codebase to Bluefin. I was talking about using Bluefin at all.

I would say the benefit of developing a _new_ project in Bluefin is greater than the benefit of converting an existing project to Bluefin. After all, for a new project Bluefin will help you develop it in a way where you have less risk of bugs. For an _existing_ project one might expect many of the bugs have already been eliminated by other means. (I would say the same of the benefit of converting an existing project to a pure functional language, versus starting a new projecting in a pure functional language.)

> [@vshabanov](#):
>
> rigid, tightly coupled, hard to use and hard to extend (`MonadBaseControl` is simply impossible for some use cases).

Yes, `effectful` (and hence Bluefin) were developed for good reasons, including significant weaknesses in the MTL approach.

> [@vshabanov](#):
>
> but we already have lazy lists

You can’t mix them with effects, and they risk leaking space.

> [@vshabanov](#):
>
> In `IO` we can use `writeChan` if we like

I suppose so!

> [@vshabanov](#):
>
> or call a user supplied callback-function

Right, that’s exactly what Bluefin’s `Stream` is: a well-scoped callback-function.

> [@vshabanov](#):
>
> `await` is not always nice even in JavaScript

Bluefin’s `await` has no relation to Javascript’s. It’s analogous to that of [`pipes`](https://hackage.haskell.org/package/pipes-4.3.16/docs/Pipes.html#v:await) or [`conduit`](https://hackage.haskell.org/package/conduit-1.3.6/docs/Data-Conduit.html#v:await).

> [@vshabanov](#):
>
> `await` from the `async` package

Which? I can’t find it.

> [@vshabanov](#):
>
> [scoped jumps](https://hackage.haskell.org/package/bluefin-0.0.12.1/docs/Bluefin-Jump.html) – I’m sorry, but this is definitely not the code I’d like to see in Haskell.

Really? Do you like to see the `Maybe` or `MaybeT` monads? They’re isomorphic to Bluefin’s scoped jumps.

> [@vshabanov](#):
>
> It’s important to have an orthogonal modular codebase. Mixing evertything means a mess and a big maintenance pain.

Well, I agree, and Bluefin provides you with tools to address this issue: you can freely mix effects within components, but handle the internal effects at component boundaries and expose a very precise, simple API, that leaks no details about the implementation.

> [@vshabanov](#):
>
> Interesting, is it possible to do some parts of Bluefin in pure `ST`? If instead of a custom `Eff` monad we can have an `ST` (with all the standard `ST` functions), but with an early return, or state variables that don’t escape the sub-region.

Yes, actually, I think it should be possible to do that. It seems a bit dubious but it could probably be made to work.

> [@Bluefin compared to effectful \[video\]](http://discourse.haskell.org/t/bluefin-compared-to-effectful-video/10723/55):
>
> Why use monadic code when we can use pure functions instead?

Personally I prefer programming imperatively, with well-scoped effects, than programming “pure functionally”. For example, consider these fold combinators:

- `foldr`
- `fold`/`foldl'`
- `foldM`
- `mapAccumL`/`mapAccumR`
- `mapAccumLM`/`mapAccumRM`
- `any`/`all`

They are all just `for`/`for_` with different choices of effects in scope. If you squint a bit you can do `mapMaybe` and `concatMap` in roughly the same way. Why program “functionally” with two handfuls of primitives when `for`/`for_` do the same job?

> [@Bluefin compared to effectful \[video\]](http://discourse.haskell.org/t/bluefin-compared-to-effectful-video/10723/55):
>
> we have some experimental effects system where we _do_ have to look into pretty convoluted code to understand how it works

Are you thinking of anything in Bluefin? If so please let me know what it is and I’ll try to simplify.

---

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [November 27, 2024, 10:31am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/18 "2024-11-27T10:31:19Z")

</div>

> [@vshabanov](#):
>
> IO primitives are not a black box – the library code is available

At some point some IO primitives will need to show something to the screen. I don’t think the code that my GPU uses to move pixels around in its VRAM is available. In general, IO primitives are tightly coupled to many layers of abstraction. In contrast, operations in effect systems are decoupled from any particular implementation.

You could model a screen in a completely pure way using a state effect with the type `[[Pixel]]` or something like that. It wont be fast, but you will be able to wrap your mind about the complete implementation.

---

<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 27, 2024, 10:52am UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/19 "2024-11-27T10:52:01Z")

</div>

But at _some_ point somewhere in the program, there will still need to be an I/O action which actually displays `[[Pixel]]` values - there’s no (safe) escape from the I/O _“black boxes”_ in Haskell. However, there is another option for those who prefer a more denotative approach to effects, at least for I/O:

> **[dialogue](https://hackage.haskell.org/package/dialogue)**
>
> I/O in Haskell Report 1.2

---

<div class="post-metadata">

**Author:** ![jaror](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/jaror/32/3271_2.png) [@jaror](https://discourse.haskell.org/u/jaror)\
**Post date:** [November 27, 2024, 3:57pm UTC](https://discourse.haskell.org/t/why-use-an-effect-system/10841/20 "2024-11-27T15:57:16Z")

</div>

The `dialogue` library also has a `runDialogue :: Dialogue -> IO ()` function which you’ll need to use if you want to actually run your dialogues, so it is no different from effect systems in this regard.

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