What is an effect and an effect system?

I read Bluefin, a new effect system - #7 by tomjaguarpaw and wondered: What is an effect? What is an effect system?

There must be something in the air, because I then came across something similar and recent on Reddit: https://www.reddit.com/r/haskell/comments/1c9czmn/what_are_effects/.

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?

5 Likes

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 ;-)

2 Likes

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.

All effects are expressions of type IO a […]

No. To try to alleviate the confusion, here is another monadic action which can have an effect:

newSTRef 3.14159 :: ST s (STRef s Double)

So I would simplify what you wrote to:

  • Any I/O action - of type IO (...) - has the potential to cause a classic effect.

  • Not all I/O actions can cause a classic effect e.g. pure x :: IO Char

Now as for effects and their systems:

An effect system provides a way of grouping effects that have something in common.

…sometimes - some effect systems also allow for extensibility (yes, I forgot about this):

  • You define a new “type modifier” for the classic effect you’re interested in.
  • Then you would define a suitable interpreter for that “modifier” - it is that interpreter which then causes the actual change.

That interpreter could then use potentially any action (depending on what’s in scope) - it could use:

  • I/O actions - IO (...)
  • encapuslated-state actions - ST s (...)
  • parser actions - Parse (...)
  • some other action, or combination thereof.

It’s a bit old, but this:

may help to clarify matters. But always remember:

  • an I/O action may cause a classic effect (a change in some other context);

  • an I/O action may be used to define the interpreter for a new “type modifier” associated with a classic effect;

  • but an I/O action isn’t an effect - it’s a Haskell expression, albeit a somewhat-unusual one…

2 Likes

Thanks for your patience! I’ll have a read and a think.

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!

2 Likes

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:

…there I used a similar definition for “action”.


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?

2 Likes

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.

(It’s a wonderful talk btw.)

10 Likes

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’).

1 Like

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).

1 Like

That’s interesting:

So there you have it:

  • a simple explanation of what an effect system is (or at least simpler than mine was),

  • and why most effect systems are monadic (to obtain that predictable evaluation order).

1 Like

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.

3 Likes

I think you’ll have you’ll have trouble getting a definition of “effect”.

For example:

So it seems that a (more) rigorous definition of “effect” is required…

2 Likes

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: