# Deepseq versus "make invalid laziness unrepresentable"

**URL:** <https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126>\
**Category:** Uncategorized\
**Created:** [March 21, 2024, 10:51am UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126 "2024-03-21T10:51:54Z")\
**Posts on this page:** 11\
**Page:** 2

<div class="post-metadata">

**Author:** ![mixphix](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/mixphix/32/5629_2.png) [@mixphix](https://discourse.haskell.org/u/mixphix)\
**Post date:** [March 24, 2024, 7:07pm UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/21 "2024-03-24T19:07:38Z")

</div>

Idris is an eagerly-evaluated language, but it has a [`Lazy`](https://idris2.readthedocs.io/en/latest/tutorial/typesfuns.html#laziness) “type former/constructor” that tells the compiler to delay the evaluation of its argument. This lets the programmer be explicit in what values ought to be treated as delayed computations.

I’ve yet to read much in the way of practical uses of Idris code, but I imagine this would be a good place to start looking for performance comparisons of e.g. strict vs lazy container types.

---

<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:** [March 24, 2024, 10:08pm UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/22 "2024-03-24T22:08:06Z")

</div>

While a `Lazy` _“type former/constructor”_ makes it easier to use, the only construct a programming language requires to support laziness is the conditional:

- 

> [@](#):
>
> (page 242 of 600)
> 
> An `if..then..else` conditional is actually a function of three arguments, but a very special kind of function. The intent and meaning of a conditional is that either the second argument or the third, but never both, is evaluated. Thus, by its very nature, a conditional, _must_ be evaluated outside-in. All languages use a variant of lazy evaluation for conditional statements and expressions. Thus a programmer can emulate lazy evaluation in any language by using conditionals. Exhibit 12.14 shows the use of `if` in Pascal to emulate the lazy evaluation built into Miranda liberally.
> 
> [The Anatomy of Programming Languages](https://core.ac.uk/download/pdf/214330064.pdf) (1993)

  - 

> [@](#):
>
> (page 368 of 600)
> 
> Compare the Miranda code in Exhibit 12.13 to the more-or-less equivalent `Pascal` code in Exhibit 12.14. Both functions compute the two roots of a quadratic equation, but the Pascal code is twice as long and far more complex. […]
> 
> * * *
> 
> **Exhibit 12.13.** `Where` takes the place of assignment.
> 
> ```plaintext
> quadroot a b c = error "complex roots", delta < 0
> = [term1], delta = 0
> = [term1+term2, term1-term2], delta < 0
> where
> delta = b*b - 4*a*c
> radix = sqrt delta
> term1 = -b/(2*a)
> term2 = radix/(2*a)
> 
> ```

- 

> [@](#):
>
> (page 369 of 600)
> 
> **Exhibit 12.14.** Assignment used to name subexpressions in `Pascal`.
> 
> ```plaintext
> type root_list= ^root_type;
> type root_type = record root: real; next: root_list end;
> 
> function quadroot(a, b, c: real): root_list;
> var delta, radix, term2: real;
> roots, temp: root_list;
> begin
> roots := NIL;
> delta := b*b - 4*a*c;
> if delta < 0
> then writeln(’Error: complex roots’)
> else begin
> new(roots);
> roots^.root:= -b/(2*a);
> if delta = 0
> then roots^.next := NIL
> else begin
> radix := sqrt(delta);
> term2 := radix/(2*a);
> new (temp);
> roots^.next:= temp;
> temp^.root := roots^.root - term2;
> roots^.root := roots^.root + term2;
> temp^.next := NIL
> end
> end;
> quadroot := roots
> end;
> 
> ```

Having seen that Pascal version _alone_, it shouldn’t then be much of a surprise that one [particularly-annoyed](https://gmarceau.qc.ca/functional-programming.html) computer scientist called for an alternative paradigm:

- [Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs](https://www.cs.cmu.edu/~crary/819-f09/Backus78.pdf) (1978)

But liberty has its price: for certain tasks, the laziness of languages like Miranda™ or Haskell means that they may sometimes be slower in comparison to some old imperative language (one that **still** doesn’t have any modern support for modules). But that’s no great surprise either:

> [@](#):
>
> Still, one may argue that an imperative language (Backus: “von Neumann language” [[14](https://www.cs.cmu.edu/~crary/819-f09/Backus78.pdf)]) will always beat a functional language on von Neumann machines because the former is only the flimsiest disguise for the underlying stored-program uniprocessor machine. 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)

The epitome of the mismatch between non-strict semantics and imperative hardware must surely be the veritable _“cottage industry”_ that has formed to (somewhat) ameliorate the difficulties in dealing with that most basic construct of laziness - the conditional: pipeline stalls and flushes, branch (mis)prediction, **_et al!_**

**Garbage in, garbage out** - performance comparisons between Haskell and an imperative [bug-prone language](https://techcrunch.com/2015/05/02/and-c-plus-plus-too) running on imperative [bug-laden hardware](https://vuls.cert.org/confluence/display/Wiki/Vulnerabilities+Associated+with+CPU+Speculative+Execution) are _irrelevant_.

---

<div class="post-metadata">

**Author:** ![eldritch-cookie](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/eldritch-cookie/32/4130_2.png) [@eldritch-cookie](https://discourse.haskell.org/u/eldritch-cookie)\
**Post date:** [March 28, 2024, 4:19pm UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/23 "2024-03-28T16:19:30Z")

</div>

> [@atravers](#):
>
> **Garbage in, garbage out** - performance comparisons between Haskell and an imperative [bug-prone language](https://techcrunch.com/2015/05/02/and-c-plus-plus-too) running on imperative [bug-laden hardware](https://vuls.cert.org/confluence/display/Wiki/Vulnerabilities+Associated+with+CPU+Speculative+Execution) are _irrelevant_.

i actually agree but until we make a new architecture and then implement it the only comparison that makes sense is how fast haskell is compared to X language in bug laden hardware. i actually would like to work to help here i just don’t know where to start?

---

<div class="post-metadata">

**Author:** ![emiruz](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/emiruz/32/4042_2.png) [@emiruz](https://discourse.haskell.org/u/emiruz)\
**Post date:** [March 28, 2024, 5:31pm UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/24 "2024-03-28T17:31:08Z")

</div>

I’m learning Scala at the moment for work. It seems like a less elegant Haskell on first contact, but it is very quick to learn and has a lot going for it: strict evaluation, but it has some opt-ins for “laziness”, and OO functional programming is quite nice. You can also just mix mutable stuff seamlessly. Immutable variable? Use val … Mutable variable? Use var … The [Scala 3](https://docs.scala-lang.org/scala3/book/introduction.html) book is exactly what I’d want from a Haskell noob guide: enough of a bootstrap to get going, and nothing more.

Finally, I’ve a terseness fetish and in Scala you can compress single argument anonymous function from (x =\> x + 2) to just (\_ + 2) , we should totally steal that …

---

<div class="post-metadata">

**Author:** ![ApothecaLabs](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/apothecalabs/32/3215_2.png) [@ApothecaLabs](https://discourse.haskell.org/u/ApothecaLabs)\
**Post date:** [March 28, 2024, 5:55pm UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/25 "2024-03-28T17:55:43Z")

</div>

> [@emiruz](#):
>
> Finally, I’ve a terseness fetish and in Scala you can compress single argument anonymous function from (x =\> x + 2) to just (\_ + 2) , we should totally steal that …

What’s wrong with [sectioning](https://wiki.haskell.org/Section_of_an_infix_operator) a la `(+2)`?

---

<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:** [March 28, 2024, 10:15pm UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/26 "2024-03-28T22:15:13Z")

</div>

> [@emiruz](#):
>
> strict evaluation, but it has some opt-ins for “laziness” […]

But all a strict language really needs are `if...then...else` conditionals to emulate laziness.

* * *

> [@emiruz](#):
>
> You can also just mix mutable stuff seamlessly:
> 
> - Immutable variable? Use `val` …
> - Mutable variable? Use `var` …

If by _“seamlessly”_ you mean _“able to sneak in an effect anywhere in the program”_ - there’s a reason why the name chosen for things of pseudo-type `IO T -> T` often start with the prefix `unsafe` `(`hint: parallelism `;-)`

---

<div class="post-metadata">

**Author:** ![emiruz](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/emiruz/32/4042_2.png) [@emiruz](https://discourse.haskell.org/u/emiruz)\
**Post date:** [March 29, 2024, 7:47am UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/27 "2024-03-29T07:47:17Z")

</div>

> [@ApothecaLabs](#):
>
> What’s wrong with [sectioning](https://wiki.haskell.org/Section_of_an_infix_operator) a la `(+2)`?

You may – and I very frequently do – need the variable to feature in many places in an anonymous function: E.g. \_^2 + \_\*2 + 5 or h(f(\_), g(\_,3))

Similarly, I think comprehensions in Scala make more sense in complex cases. They are basically an arbitrary for loop supporting multiple generators with a yield statement. Reads like normal code. From [here](https://docs.scala-lang.org/tour/for-comprehensions.html):

```haskell
def foo(n: Int, v: Int) =
   for i <- 0 until n
       j <- 0 until n if i + j == v
   yield (i, j)

 // prints (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) (6, 4) (7, 3) (8, 2) (9, 1)
foo(10, 10).foreach {
  (i, j) => println(s"($i, $j) ")
}

```

---

<div class="post-metadata">

**Author:** ![rhendric](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/rhendric/32/2689_2.png) [@rhendric](https://discourse.haskell.org/u/rhendric)\
**Post date:** [March 29, 2024, 8:12am UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/28 "2024-03-29T08:12:32Z")

</div>

> [@emiruz](#):
>
> You may – and I very frequently do – need the variable to feature in many places in an anonymous function: E.g. \_^2 + \_\*2 + 5 or h(f(\_), g(\_,3))

Note that in Scala, each `_` is a new parameter; those expressions would not reuse a single parameter in multiple places.

---

<div class="post-metadata">

**Author:** ![emiruz](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/emiruz/32/4042_2.png) [@emiruz](https://discourse.haskell.org/u/emiruz)\
**Post date:** [March 29, 2024, 8:30am UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/29 "2024-03-29T08:30:25Z")

</div>

Ah thanks, I didn’t know that, my mistake. I guess its still valid for different reasons: 1. Placement of the variable (i.e. if its anywhere other than the beginning or end its harder in Haskell), and 2. multiple variables treated as merely ordered rather than named.

---

<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:** [March 29, 2024, 8:32am UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/30 "2024-03-29T08:32:34Z")

</div>

Lightweight iterators/generators/streams/comprehensions are extremely important. I haven’t used them in Scala but I love them in Python (where I had trouble getting my non-FP colleagues to adopt them). Here’s how I would implement your example in `bluefin`:

```haskell
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TypeOperators #-}

import Control.Monad (when)
import Bluefin.Eff (Eff, runEff, (:>))
import Bluefin.IO (effIO, runEff)
import Bluefin.Stream (Stream, forEach, yield)
import Data.Foldable (for_)
import PyF (fmt)

foo :: (e :> es) => Int -> Int -> Stream (Int, Int) e -> Eff es ()
foo n v y = do
  for_ [0..n] $ \i -> do
    for_ [0..n] $ \j -> do
      when (i + j == v) $
        yield y (i, j)

main = runEff $ \io -> forEach (foo 10 10) $ \(i, j) ->
  effIO io (putStr [fmt|({i}, {j}) |])

```

For another example see [Break with traverse / traverse\_? - #23 by tomjaguarpaw](http://discourse.haskell.org/t/break-with-traverse-traverse/9152/23)

I think it’s nice to observe that none of this is “built in” to Haskell, except `do` notation and `[0..n]`. These are all provided by libraries:

- Streaming (via `bluefin`)
- `for`
- `when`
- `fmt` string interpolation (via `PyF`)

---

<div class="post-metadata">

**Author:** ![emiruz](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.haskell.org/emiruz/32/4042_2.png) [@emiruz](https://discourse.haskell.org/u/emiruz)\
**Post date:** [March 29, 2024, 10:43am UTC](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126/31 "2024-03-29T10:43:19Z")

</div>

Yeah when you think about it a little bit, list comprehensions can be used instead of map, filter, zip, drop, take, takeWhile, dropWhile, and so on. Lots of those functions can just be one-line list comprehensions. I’d personally make any high leverage things like that elegant core language features. In [trying to write Python functionally last week (AoC2021)](https://github.com/emiruz/adventofcode2021) I ended up using list comprehensions constantly since its more parsimonious than `map(lambda x: ... , filter(lambda x: ..., ...))` : yuck!

[Previous page](https://discourse.haskell.org/t/deepseq-versus-make-invalid-laziness-unrepresentable/9126.md?page=1)
