# Why imperative code is worse than functional code

**URL:** <https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473>\
**Category:** Uncategorized\
**Created:** [August 29, 2023, 10:07pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473 "2023-08-29T22:07:06Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![AntC2](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/antc2/32/1872_2.png) [@AntC2](https://discourse.haskell.org/u/AntC2)\
**Post date:** [August 31, 2023, 11:12pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/25 "2023-08-31T23:12:12Z")

</div>

> [@Probie](#):
>
> But the Python solution _isn’t even correct_.

Great counter-example! Also quite plausible that you’d have a basic coverage over some sequence of topics, then Advanced coverage over exactly the same sequence. For each Advanced area you might start `"Recap", "Installation", ...` to load some extra packages.

(I was going to ask back on the O.P. with its talk of “key-value” whether the key was ‘lesson name’ or the combo ‘section name+lesson name’.)

---

<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:** [September 1, 2023, 6:37am UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/27 "2023-09-01T06:37:12Z")

</div>

> [@maxigit](#):
>
> Would you say the Haskell version does not work if it was accidentally given a cyclic list?

It does work! It would return a lazily-consumable infinite list 🙂 EDIT: although on trying it I discover that infinite input seems to require the _lazy_ `State` monad ☹

---

<div class="post-metadata">

**Author:** ![Probie](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/probie/32/3232_2.png) [@Probie](https://discourse.haskell.org/u/Probie)\
**Post date:** [September 1, 2023, 6:49am UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/28 "2023-09-01T06:49:14Z")

</div>

> [@maxigit](#):
>
> Would you say the Haskell version does not work if it was accidentally given a cyclic list?

There are a lot of Haskell versions, so I’d need to know which one you’re referring to, but I think a lot of the solutions would give an acceptable answer, especially if what you’re doing is serialising to something like JSON and streaming it.

The original problem is meant to work on a list of sections, where a section is a key-value data structure containing a list of lessons, where a lesson is also a key-value data structure. Nowhere in the problem statement is JSON mentioned, except for

> Here is an example input (formatted in JSON for convenience):

and

> The output should be (formatted in JSON for convenience):

I will agree that the code as given will probably work for whatever the intended use-case was, but “containing two references to the same object in a collection being traversed while performing mutation” is not some really obscure edge case, it’s something that occurs all the time.

---

<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:** [September 1, 2023, 10:50am UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/30 "2023-09-01T10:50:44Z")

</div>

…and all of that is _“a bit”_ of a:

> [@](#):
>
> [simonpj:](http://discourse.haskell.org/t/beautiful-functional-programming/7411/23)
> 
> […] storm in [a] teacup!

Why? Because the questionable use of simple(ton) examples has probably occurred before:

- no doubt there were various snippets of assembly code which purported to show the superiority of assembly over that _“new-fangled”_ Fortran and LISP stuff.

- there probably were analogous snippets of code showing the superiority of `goto` over structured programming.

- and one can only imagine all the snippets of code purporting to show the superiority of manual memory ~~_manglement_~~ management over GC!

They are **all** examples of _“storms in teacups”_…the teacups found in child’s-toy dollhouses!

* * *

Getting back to the _actual_ topic of this thread:

> [@jaror](#):
>
> Why [is] imperative code worse than functional code?

**Mutation.**

While _The Anatomy of Programming Languages_ also nominates sequencing as being a problem:

- arbitrary sequencing but no mutation: [confluence.](https://www.cs.cornell.edu/courses/cs4110/2012fa/lectures/lecture14.pdf)

- arbitrary mutation but no sequencing: nondeterminism!

Standard ML and OCaml both illustrate this point - at first glance, definitions in both languages have little to no resemblance to the rambling sequences of statements found in the likes of Pascal or C. But that lack of visible sequencing is irrelevant: due to the relative ease of access to mutation both provide, Standard ML and OCaml are also imperative languages.

* * *

Alright, so what about Haskell and its use of [seemingly-inexplicable](https://wiki.haskell.org/Monad_tutorials_timeline) interfaces?

- 

> [@](#):
>
> (page 57 of 60)
> 
> […] the resulting language is undeniably complicated, and the monadic parts have a very imperative feel. I would be delighted to find a way to make it simpler and more declarative.
> 
> [Tackling the Awkward Squad: monadic input/output, concurrency, exceptions, and foreign-language calls in Haskell](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.13.9123&rep=rep1&type=pdf) (2002).

- 

> [@](#):
>
> I don’t mind that we haven’t yet been [liberated from the von Neumann model](http://conal.net/blog/posts/can-functional-programming-be-liberated-from-the-von-neumann-paradigm). As long as [we] _remember_ [that] we haven’t.
> 
> As long as we keep on searching.
> 
> [Conal Elliott:](http://conal.net) [Is Haskell a purely functional language?](http://conal.net/blog/posts/is-haskell-a-purely-functional-language) (2010).

…for something better (or a proof that none exists, analogous to [that for the _Entscheidungsproblem_](https://www.ics.uci.edu/~lopes/teaching/inf212W12/readings/church.pdf)).

---

<div class="post-metadata">

**Author:** ![mtamc](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mtamc/32/3624_2.png) [@mtamc](https://discourse.haskell.org/u/mtamc)\
**Post date:** [September 1, 2023, 1:49pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/31 "2023-09-01T13:49:22Z")

</div>

> [@tdammers](#):
>
> A pure expression is naturally encapsulated; an effectful expression is not, because it has “hidden” dependencies on the outside world.

This is one of my favorite things about functional code. In imperative code, in order to understand the value inside a mutable variable, you must read its entire scope. In functional code, a value’s expression is all you need to understand it. You can navigate to its building blocks’ definitions with ease thanks to LSP too, though I wish that the Haskell language server had a way to also navigate to libraries’ definitions as well.

---

<div class="post-metadata">

**Author:** ![mtamc](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mtamc/32/3624_2.png) [@mtamc](https://discourse.haskell.org/u/mtamc)\
**Post date:** [September 1, 2023, 2:02pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/33 "2023-09-01T14:02:00Z")

</div>

I also use vim and I’ll try haskdogs, it seems like exactly what I need, thanks!

---

<div class="post-metadata">

**Author:** ![chrisdone](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/chrisdone/32/1408_2.png) [@chrisdone](https://discourse.haskell.org/u/chrisdone)\
**Post date:** [September 1, 2023, 8:23pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/34 "2023-09-01T20:23:31Z")

</div>

Perhaps the more modern question is not “imperative versus functional”, but _formal syntactic code languages_ (imperative, functional, logical, …) versus _machine generated computations_ (ML, GPT, etc). If one can give plain English descriptions, some AWS keys, and get back “a system”, the languages and transfer formats in-between may lose relevance. That’s if you take the MIT view, anyway. (See Sussman on why they switched from Lisp to Python.)

[![](https://img.youtube.com/vi/OgRFOjVzvm0/maxresdefault.jpg "SICP: the end of an era") ](https://www.youtube.com/watch?v=OgRFOjVzvm0)

---

<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:** [September 1, 2023, 9:05pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/35 "2023-09-01T21:05:18Z")

</div>

> [@chrisdone](#):
>
> If one can give plain English descriptions […]

If, indeed.

As [noted memorably by Dijkstra](https://www.cs.utexas.edu/users/EWD/ewd06xx/EWD667.PDF), plain human languages would only suffice for _“trivial”_ usage (depending on how _“trivial”_ is defined). For more rigour, a more precise and therefore restricted language is needed.

---

<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:** [September 1, 2023, 9:18pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/36 "2023-09-01T21:18:03Z")

</div>

I can only hope that an A(G)I smart enough to write complete software from plain English descriptions will understand that it needs to explain its work and thus present the “system” using an easy to understand (e.g. functional/denotative) formalism.

The MIT view is very disappointing. They observed a problem: nobody understands software any more. And then they just decided to give up and stop teaching how to understand software. That seems like the opposite of what society needs.

---

<div class="post-metadata">

**Author:** ![Nycticorax](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/nycticorax/32/834_2.png) [@Nycticorax](https://discourse.haskell.org/u/Nycticorax)\
**Post date:** [September 2, 2023, 7:58am UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/37 "2023-09-02T07:58:13Z")

</div>

I agree. I don’t know the MIT view but it would be silly to stop developping formally precise languages just because a few programming tasks can be described using ML. That would be as silly as to stop developping mathematics and proof-theory just because sometimes we can get by using only statistics.

---

<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:** [September 2, 2023, 9:09am UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/38 "2023-09-02T09:09:49Z")

</div>

> [@jaror](#):
>
> The MIT view is very disappointing.

[According to](https://chrisdone.com/posts/dijkstra-haskell-java) @chrisdone, the replacing of Lisp with Python at MIT seems to be related to Java replacing Haskell at the University of Texas. So despite it usually being the more obnoxious of the two, the _superficial_ simplicity of imperative code (and programming) continues to beguile.

> [@](#):
>
> (page 18 of 217)
> 
> The functional language is a ballerina at an imperative square dance.
> 
> [Graph Reduction Without Pointers](https://www.cs.unc.edu/techreports/89-045.pdf) (1989).

…and seems destined to remain a novelty as more and more imperative _“dance halls”_ appear, despite [the goad of parallelism](https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.168.4008&rep=rep1&type=pdf).

---

<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:** [September 2, 2023, 9:27am UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/39 "2023-09-02T09:27:43Z")

</div>

> [@atravers](#):
>
> the replacing of Lisp with Python at MIT seems to be related to Java replacing Haskell at the University of Texas […] the _superficial_ simplicity of imperative code (and programming) continues to beguile.

I don’t think it is related in this way. See the explanation from Sussman in the video that Chris linked above. Sussman is essentially saying that it became impossible to fully understand software systems as the software (and hardware) grew exponentially from 1980-1997 and so they quit. They transitioned to a “poke at it until it seems to do what you want” approach. The reason Python was chosen is simply because it had the largest robotics libraries at the time.

---

<div class="post-metadata">

**Author:** ![AntC2](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/antc2/32/1872_2.png) [@AntC2](https://discourse.haskell.org/u/AntC2)\
**Post date:** [September 2, 2023, 9:46am UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/40 "2023-09-02T09:46:51Z")

</div>

> [@atravers](#):
>
> As [noted memorably by Dijkstra](https://www.cs.utexas.edu/users/EWD/ewd06xx/EWD667.PDF),

> the last decades have shown in the Western world a sharp decline of people’s mastery of their own language …

Yeah, miserable old s.o.b.s have been complaining about the yoof since – oh – Socrates’ time.

We still have to get over the bump from an enterprise’s own description of what it wants (which might use some formal tools/notations, but won’t be in a programming language) to a ‘proof’ (I’m joking) that this particular suite of programs delivers to that description.

---

<div class="post-metadata">

**Author:** ![AntC2](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/antc2/32/1872_2.png) [@AntC2](https://discourse.haskell.org/u/AntC2)\
**Post date:** [September 2, 2023, 10:07am UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/41 "2023-09-02T10:07:32Z")

</div>

> [@chrisdone](#):
>
> Sussman on why they switched from Lisp to Python

That seems to be saying the reason is libraries: volume of, complexity of. Sussman doesn’t mention models of computation.

Modern programming is not needing to understand at the level of data-items-through-processor (he’s saying); but rather what does this library do? (because it’s so humungous the docos are never adequate); what do these other libraries do? How do I plug the output from one into the input to another to get the solution? (I get the analogy of a 1,000-pin chip vs. individual capacitors and diodes, or even 12-pin ICs.)

So …? if LISP had plenty of libraries, MIT wouldn’t have switched? If Haskell – as a ‘glue’ language – could interface smoothly to Python libraries, he’d use Haskell? I fear Haskell’s laziness would remain as an insurmountable impedance mismatch.

---

<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:** [September 2, 2023, 11:30am UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/42 "2023-09-02T11:30:36Z")

</div>

> [@AntC2](#):
>
> Yeah, miserable old s.l.o.b.s have been complaining about the yoof since – oh – Socrates’ time.

…do try to remember that sentiment when you’re old! As for me…well, I prefer this depiction of certain CS luminaries:

> [@](#):
>
> Admittedly, Haskell also had some shameful pre-teen influences from hooligans like Church, Curry, Landin, and Milner […]
> 
> [The C language is purely functional](http://conal.net/blog/posts/the-c-language-is-purely-functional) (2010).

* * *

> [@AntC2](#):
>
> So […] if LISP had plenty of libraries, MIT wouldn’t have switched?

…possibly, yes: it has been used to build entire [operating systems](https://www.theregister.com/2023/03/31/mit_cadr_software_recovered).

> [@AntC2](#):
>
> I fear Haskell’s laziness would remain as an insurmountable impedance mismatch.

…before giving up, perhaps we should see how another declarative language works with laziness:

[Lazy Stream Programming in Prolog](https://arxiv.org/pdf/1907.11354) (2019).

---

<div class="post-metadata">

**Author:** ![Liamzy](https://avatars.discourse-cdn.com/v4/letter/l/50afbb/32.png) [@Liamzy](https://discourse.haskell.org/u/Liamzy)\
**Post date:** [September 2, 2023, 3:09pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/43 "2023-09-02T15:09:32Z")

</div>

I think the question shouldn’t be, “why is imperative code is worse than functional code”, but rather, “Is imperative code always worse than functional code, and if so, when is it better?”

That was essentially the point being made by Jose Valim / (maybe SPJ?) in the other thread.

* * *

As to whether imperative code is always worse; well, let’s say, we want a list of instructions; i.e, “wash the dishes, clean the sink, take out the trash”. The natural form of this list of instructions is, well, a list of sequential instructions. Should we specify instead “the house after the trash has been taken out, the sink has been cleaned, and the dishes have been washed” instead?

That is to say, there are some applications wherein by definition, imperative programming is better than functional programming because the problem is fundamentally imperative.

* * *

The other issue is that imperative programming is sort of played out, whereas functional programming still has a lot of life left in it for development and exploration. In my view, the Jose Valim question is basically just asking for better combinators (unconcat for lists, zipover, although most of these needs are already met by lens).

In the event that a good or better functional programming technique does yet not exist, imperative programming is better because you do not have to develop the alternative, and propagate the idiom to make it understandable.

Say, for instance, you’re working in a language without map or filter, and it’s not idiomatic to use such. In this case, you’d have to implement the map and filter functions yourself before use, which is unergonomic, and can help make your code less readable due to outside unfamiliarity with your idiom.

* * *

On the other hand, this does not mean that we should settle for C or Fortran in every language. Haskell, after all, is a research language.

We should be appreciating and looking forward to problems like the ones Jose Valim proposed, because it’s through problems that we find and push the limits of functional programming.

---

<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:** [September 2, 2023, 5:30pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/44 "2023-09-02T17:30:57Z")

</div>

- 

> Say, for instance, you’re working in a language without map or filter, and it’s not idiomatic to use such. […]

Hrm. Say you’re working in a language without convenient access to mutation e.g. Haskell, and it’s not idiomatic to use such a feature in said language…

- 

> [@](#):
>
> Should we specify instead “the house after the trash has been taken out, the sink has been cleaned, and the dishes have been washed”

  - `(removeTrash . cleanSink . washDishes) :: House -> House`

  - `(removeTrash' <=< cleanSink' <=< washDishes') :: House' -> ST s House'`

- 

> […] there are some applications [for] imperative programming because the problem is fundamentally imperative.

  - 

> In the event that a good or better functional programming technique does yet not exist […]

…and that’s where you would first try using encapsulated state (`ST`, `runST` and co.)

- 

> In my view, the Jose Valim question is basically just asking for better combinators […]

_“How many combinators does it take to screw in a light bulb?”_

- 

> […] it’s through problems that we find and push the limits of functional programming.

…you mean like the lack of adoption of nonstrict evaluation in newer languages such as Elixir?

---

<div class="post-metadata">

**Author:** ![Liamzy](https://avatars.discourse-cdn.com/v4/letter/l/50afbb/32.png) [@Liamzy](https://discourse.haskell.org/u/Liamzy)\
**Post date:** [September 2, 2023, 6:53pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/45 "2023-09-02T18:53:45Z")

</div>

> - `(removeTrash . cleanSink . washDishes) :: House -> House`
> - `(removeTrash' <=< cleanSink' <=< washDishes') :: House -> ST s House`

Which poses a worse problem, no? This is a chain of function applications, and the first problem is that it’s (.), not (\>\>\>). The bigger problem is that you can think of function applications imperatively, i.e, you are working in a pipeline, taking the action of transforming values from a → b, and so on. Church-Turing, no?

> [@](#):
>
> \* …and that’s where you would first try using encapsulated state (`ST`, `runST` and co.)

Given that ST / runST perform worse than State.Strict.State with modify’ in many cases, it might not be a good idea. Accumulating parameters and Strict State give enough access to essentially imperative thinking.

There’s also the question of, well, since statements in Haskell (check Haskell Report 2010) are values in do notation, whether it’s more convenient and flexible to have access to:

[ washDishes  
, cleanSink  
, removeTrash  
]

wherein it’s possible to sequence\_ the operations together, as well as reverse, foldr, and so on on the [HouseAction]. A bit Lispy I guess.

* * *

My own stance is, well, generally, the four cases where essentially imperative code are acceptable are:

- You are throwing effects, and Conal Elliott’s ask for a better alternative to IO and monads hasn’t been fully fulfilled, despite monad transformers, free monad interpreters, and effect libraries.
- You need more precise control over performance, or just better performance.
- You’re limiting your idiom to make the codebase easier to onboard onto.
- You don’t have a better functional solution available.

* * *

My real opposition here is against the desire to “declare victory” and be done with it. The last I checked, no one had managed to get a zip solution that was more succinct than the Python, and I suspect this can’t be done without lenses (after which it’s roughly a 2-3 liner; the real issue with this problem for Haskell I think is that Haskell runs on ADTs, not objects, and you either cheat with the datatype, sacrificing fidelity, or resort to lenses, which exist to make this problem go away, but do so at the cost of readability).

---

<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:** [September 2, 2023, 9:36pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/46 "2023-09-02T21:36:17Z")

</div>

> [@Liamzy](#):
>
> Which poses a worse problem, no?

No.

If you allow mutation in a programming language, you are immediately confronted with a choice: sequencing or nondeterminism. Furthermore if you allow mutation to be accessed from (potentially) everywhere in that language, then the choice of sequencing or nondeterminism will also apply everywhere.

My first example - `(removeTrash . cleanSink . washDishes)` is only sequential: no mutation involved.

As for the second example, let’s assume the worst: ~~`House`~~ `House'` is `STRef`-based and therefore relies on mutation. Now for that choice - we don’t want nondeterminism so we must choose sequencing, which the monadic `ST` type provides. But fortunately for us, there’s also `runST`, which allows us to keep the use of mutation (and the need for sequencing) private: **_nice!_**

* * *

> [@Liamzy](#):
>
> Given that `ST` / `runST` performs worse than `State.Strict.State` with `modify’` in many cases, it might not be a good idea.

…and given it’s similarity to (strict) `ST` in GHC, is `IO` also affected?

* * *

> [@Liamzy](#):
>
> My real opposition here is against the desire to “declare victory” and be done with it.

Considering that Haskell continues to require mutation (and therefore sequencing) for I/O, after the ~~_better_~~ longer part of three decades, I suspect that such a declaration will not be happening any time soon. So our functional programs will continue to be boats in an imperative sea, and we will have to keep watch for, and reseal leaking hulls:

`http://discourse.haskell.org/t/an-epic-future-for-spj/3573/9`

---

<div class="post-metadata">

**Author:** ![Liamzy](https://avatars.discourse-cdn.com/v4/letter/l/50afbb/32.png) [@Liamzy](https://discourse.haskell.org/u/Liamzy)\
**Post date:** [September 2, 2023, 10:26pm UTC](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473/47 "2023-09-02T22:26:14Z")

</div>

Implicitly, RW, no? Remove trash, clean sink, wash dishes, these are actions outputting to a global state. So there is an implicit form of mutation occurring because we are jumping from the semantics of a functional programming language to a real world; i.e, in Haskell, House would be a wrapper, effect system, or monad transformer stack over IO.

So perhaps we’re misunderstanding each other.

* * *

As to IO vs ST, I’ve seen cases wherein IORefs seem to optimize better than pure code (IORef is used as a data carrier here for unsafePerformIO).

* * *

As to declaring victory, accumulating parameter might be “simulating” state or having state be handled by the compiler, but it’s still effectively stateful in that state is being stored in a function argument. That’s why I kept on going back to the Jose Valim problem; I kept on trying to get a Lens-based solution out of it that would avoid the need for quasi- or crypto-imperative State Monad.

[Previous page](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473.md?page=1)

[Next page](https://discourse.haskell.org/t/why-imperative-code-is-worse-than-functional-code/7473.md?page=3)
