Hacker News new | past | comments | ask | show | jobs | submit login

> As far as I know, one can create a denotational semantics for any well-defined language. In practical terms, you could pick, say, JavaScript and do a similar representation as explained in the article: Every “non-pure function” is evaluated to a description of the state change that is caused by that function.

Yes this argument has been done before [1], so it's important not to lose sight of the real value proposition:

I want the ability to write a function which returns the same output for the same input, regardless of when/where it's called, number of threads, whether it's in a test or in prod, and so on. But I can already do that in an any programming language, so the real value here is being able to mark the function as such, and have the compiler reject me if I'm wrong.

> However, the more I look into this the less I buy into the whole “functional semantics” for side-effects argument. Immutable data is great, explicit dependencies are great, but those are about minimizing the use of side-effects, not about dressing them up.

A function with minimal side-effects is a function with side-effects [2].

> effectful computations are marked with an ! so they are easier to spot

There's two important steps that you've rolled into one. The first step is the 'functional semantics (with explicit effects)'. E.g. you take your straight-line imperative program:

  html = Http.getUtf8(url);
  path = Path.fromStr(filename);
  File.writeUtf8(path, html);
  Stdout.line ("Wrote HTML to: $(filename)");
and model it monadically:

  Http.getUtf8(url) >>= \html ->
      path = Path.fromStr(filename)
      File.writeUtf8(path, html) >>= \_ ->
          Stdout.line ("Wrote HTML to: $(filename)");
This is where you get your nice functional properties meaning that your compiler won't let you mix them up. Detractors call them red/blue functions. The second step is wrapping it back up into a palatable syntax again.

Haskell and Scala use <- for this. Idris and Roc use !. Js uses await.

[1] http://conal.net/blog/posts/the-c-language-is-purely-functio...

[2] https://queue.acm.org/detail.cfm?id=2611829




> [1]

Yes, Conal Elliots arguments are very relevant here.

> A function with minimal side-effects

Clarification, what I mean with “minimizing the use of side effects” is not about within a function, but in a program. Exaggerated example: You could write Haskell in a style where everything returns an IO and mutates some global state. Not doing that, and having most things pure is useful due to the simplified reasoning in the pure parts.

> There's two important steps that you've rolled into one.

Have I? What I want to say is that I do believe the syntactic distinction between calling side-effecting functions vs pure functions is useful.

Do I need to care about how the compiler enforces that? Does the specific encoding need to be part of the language semantics? Do I need to be able to model it monadically within the language?

> This is where you get your nice functional properties meaning that your compiler won't let you mix them up.

I may have formulated this a bit flippantly, but I think you mean the same here as I did when I said that “marked with an ! so they are easier to spot” I did have in mind that this is checked by the compiler. And I think we also agree that this separation is a good thing.


> A function with minimal side-effects is a function with side-effects [2].

Perhaps the real issue is being able to categorize those side-effects at design-time and control behavior based on category.

In particular, logging and telemetry which (ideally) do not matter to the core behavior of the application, versus web-calls (which probably do) and local memory changes (which almost always matter.)




Consider applying for YC's Summer 2025 batch! Applications are open till May 13

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: