Skip to content

The distributivity law for Alternative rules out effectful instances #63

Open
@hdgarrood

Description

@hdgarrood

Alternative has this distributivity law:

  • (f <|> g) <*> x == (f <*> x) <|> (g <*> x)

However, this law rules out a few instances, most notably "effectful" ones like Effect or Aff. For example:

f :: Aff (Unit -> Unit)
f = pure identity

g :: Aff (Unit -> Unit)
g = pure identity

x :: Aff Unit
x = log "hi" *> empty

for which (f <|> g) <*> x will log "hi" once, whereas (f <*> x) <|> (g <*> x) will log "hi" twice.

Note that Effect has no Alt instance right now (and therefore no Plus or Alternative either), whereas Aff does have all of those instances.

I think it would be good to decide whether we want to keep this law and say that the problem lies with Aff's instance, or condone the Aff instance by dropping the distributivity law from the Alternative class.

It would be useful to see a concrete example of a case where the distributivity law is useful for ensuring that something behaves sensibly, because I'm not aware of any (and I think Aff's instance is used quite widely in practice, and I'm not aware of this having had any real consequences).

If we did drop the Alternative distributivity law, we'd be left with just the annihilation law, empty <*> f = empty. I think this makes sense as a class: I'd argue it gives you exactly what you need to write a sensible version of guard, since the annihilation law ensures that subsequent effects after a failed guard are nullified, and you need pure from Applicative and empty from Plus (see also #62).

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: needs more infoThis issue needs more info before any action can be done.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions