When I first encountered Haskell, I was puzzled by references to ‘actions’. I looked in the Haskell 2010 Language Report and there the term ‘action’ seemed to be used to mean an expression of a type m a where m was an instance of class Monad. The term ‘IO action’ seemed to be used to mean an expression of type IO a. The report suggested that ‘computation’ might be a synonym for ‘IO action’ or, perhaps, also a -> IO b. (On the other hand, I wondered, from other things that I had read, if, strictly speaking, actions/computations were expressions of type IO a and all other uses of ‘action’ were, to some degree, metaphorical.)
Is an ‘effect’ a synonym for an expression of type IO a?
Is an ‘effect’ a synonym for an expression of type IO a?
No. Consider the (trivial) I/O action:
pure 'a' :: IO Char
By design, it has no associated effect. So the presence of IO (...) in a type of an expression merely indicates that the expression could have effects (in the classic sense - causing a change in some other context, in this case the rest of reality).
What some find objectionable about the I/O-as-monadic-action approach is its agglomeration of all classic I/O effects. What an (type-based) “effect system” then enables is the restricted use of those classic effects, without e.g. having to define a separate newtype for each (combination of) classic effects - instead you just nominate which of those classic effects you need by selecting the appropriate “type-modifiers” (one for each of the required effects).
(Note: I’m being vague here with terminology, because of the wide variety of effect-system implementations…and I’m not an effect-system designer ;-)
Many thanks for the explanation. Can I put it like this:
All effects are expressions of type IO a but not all expressions of type IO a are effects, because some expressions of type IO a definitely do not correspond to any change in the ‘state’ of the real world: pure x :: IO a being an example.
An effect system provides a way of grouping effects that have something in common.
Another thing to be aware of is the laziness in terminology. For example:
IO (instead of IO a) isn’t a “type”, but a type constructor.
Just isn’t a “constructor”, but a data constructor.
Maybe a isn’t a “monad”, but a monadic type.
This is why I’ve been using the term classic effect - because the word “effect” is now so often being used to describe those “type modifiers” I keep referring to. It would be very helpful for there to be one common glossary for all effect systems, because there’s probably no chance of having one common basis (or library) for all effect systems!
I was in a bit of a hurry earlier, so now to address the other parts of your post:
When I first encountered Haskell, I was puzzled by references to ‘actions’. I looked in the Haskell 2010 Language Report and there the term ‘action’ seemed to be used to mean an expression of a type m a where m was an instance of class Monad.
Some time ago when I was doing some tidying-up of the Haskell wiki, I noticed a monad “introdutorial” on the Monad page which I then separated out into its own page:
The report suggested that ‘computation’ might be a synonym for ‘IO action’ […]
I suspect that’s more due to happenstance than deliberation: early texts about monadic I/O did use the term “computation”. But as my ST s a example showed, an action (or computation) need not engage in any form of I/O.
[…] or, perhaps, also a -> IO b.
…yeah, I think I’ve found it:
…this would be a classic example of “laziness in terminology”. So how would I (re)phrase this?
…more thought needed here, too.
On the other hand, I wondered, from other things that I had read, if, strictly speaking, actions/computations were expressions of type IO a and all other uses of ‘action’ were, to some degree, metaphorical.
When monadic I/O was introduced to Haskell 1.3, an expression with the type IO (...) was referred to as a “computation”. But by the time Haskell 98 arrived, it had been largely superseded by the term “action” (the Report still used “computation” ). So no metaphors (those are saved for the tutorials;-)…anyone for a burrito?
It’s not a direct answer to your question, but the keynote from the 2023 Haskell Symposium at ICFP was “The Evolution of Effects.” It’s a walk through history but I think for a term of art like “effect,” that’s a good thing to understand.
Thanks for the reference to the ST s a monadic type. That led me to the 1994 Lazy Functional State Threads and ‘stateful computations’ and “[a stateful computation] is like a ‘script’, detailing the actions to be performed on its input state”.
Thanks also to @Ambrose for the reference to Nicholas Wu’s remarkable talk, which has introduced me to the term ‘algebraic effect handlers’ (which I think refers to ‘handlers of algebraic effects’).
Some more suggested reading regarding I/O in Haskell:
How to Declare an Imperative (1997) by Philip Wadler provides a more “top-down” introduction to monadic I/O. It also shows a few (other) possible approaches to implementing monadic I/O.
State in Haskell (1995) by John Launchbury and Simon Peyton Jones is the “extended edition” of Lazy Functional State Threads, including more examples of usage for ST s a.
(A cautionary note: in both Lazy Functional State Threads and State in Haskell, ST s a is non-strict. So there’s a potential for “time leaks” in the examples from either article as the current default implementation of ST s a in Glasgow Haskell is strict).
I think you’ll have you’ll have trouble getting a definition of “effect”. It’s a very general concept like “type”, “set” or “number”. But if you take for granted a notion of “effect” then an “effect system” is a coherent framework for working with effects.
By that definition I would guess that IO, ST and transformers are all “effect systems”. Effect systems like eff, polysemy, effectful and Bluefin are often called “extensible” because of the way they allow effects to be freely combined. I would say that MTL was an attempt at an extensible effect system, but it falls short because of the n^2 instances problem which is makes it too cumbersome to truly freely combine effects in practice.
Since the Haskell 2010 Report does (briefly) mention continuations (page 132 of 329) and refers to callbacks (pages 116 and 119), albeit in the context of the FFI: