MyNixOS website logo
Description

Lawful list and set monad transformers based on free monads.

This package provides a lawful ListT implementation based on free monads. It also provides an _Applicative_ list transformer, which is a lawful Applicative, and isomorphic to the old ListT.

Free ListT

This package provides a lawful ListT implementation based on free monads. It also provides an Applicative list transformer, which is a lawful Applicative, and isomorphic to the old ListT.

Background

The old ListT transformer from transformers < 0.6 was unlawful: For a noncommutative monad, ListT m was not a monad. It was implemented simply as the composition of list and m:

newtype ListT m a = ListT (m [a])

As such, it is automatically a lawful Functor and Applicative in a canonical way. But famously, a composition of two monads is not always a monad, and in this case, it in fact isn't.

Previous approaches

Streaming

There is one popular approach to ListT, representing the transformer as a stream:

newtype ListT m a = ListT (m (Maybe (a, ListT m a)))

This approach is implemented in https://hackage.haskell.org/package/list-t and https://hackage.haskell.org/package/list-transformer, and it is a great choice in many cases.

Basically, to go through the list, one has to perform one effect in m at each step, and one discovers whether the list now ends or produces a further element. But this also means that the list structure enforces all earlier m effects before a later element can be accessed.

Church-encoding

Another possibility is Church-encoding the list, which is implemented in logict.

Free approach

A simple algebraic approach that does not enforce the linear structure of streaming ListT is a free monad:

newtype ListT m a = ListT (FreeT [] m a)

This gives a branching rose tree of computations, where at every step in m, arbitrarily many branches can arise.

Unfolding the definition of FreeT as an algebraic datatype would result in something like:

data ListT m a = OneLayer (m a) | TwoLayers (m [m a]) | ThreeLayers (m [m [m a]]) | ...

Applicative transformer

As mentioned already, the old ListT is a valid Applicative transformer, which means that ListT m is a lawful Applicative as long as m is. This is useful and sufficient in many situations, which is why it is reinstated here.

Also, values of type m [a] occur very often in the wild (for example when using mapM), so it makes sense to give them a proper type that captures their properties.

To give some more examples, all lawful ListT implementations have some kind of "running" function that maps it to m [a]. The free ListT is no exception here. In a sense, one can "flatten" or "concatenate" all free list layers into a single one. While this is a natural transformation, this is of course not a monad morphism.

Metadata

Version

0.1.0.1

License

Platforms (75)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64_be-none
  • arm-none
  • armv5tel-linux
  • armv6l-linux
  • armv6l-netbsd
  • armv6l-none
  • armv7a-darwin
  • armv7a-linux
  • armv7a-netbsd
  • armv7l-linux
  • armv7l-netbsd
  • avr-none
  • i686-cygwin
  • i686-darwin
  • i686-freebsd
  • i686-genode
  • i686-linux
  • i686-netbsd
  • i686-none
  • i686-openbsd
  • i686-windows
  • javascript-ghcjs
  • loongarch64-linux
  • m68k-linux
  • m68k-netbsd
  • m68k-none
  • microblaze-linux
  • microblaze-none
  • microblazeel-linux
  • microblazeel-none
  • mips-linux
  • mips-none
  • mips64-linux
  • mips64-none
  • mips64el-linux
  • mipsel-linux
  • mipsel-netbsd
  • mmix-mmixware
  • msp430-none
  • or1k-none
  • powerpc-netbsd
  • powerpc-none
  • powerpc64-linux
  • powerpc64le-linux
  • powerpcle-none
  • riscv32-linux
  • riscv32-netbsd
  • riscv32-none
  • riscv64-linux
  • riscv64-netbsd
  • riscv64-none
  • rx-none
  • s390-linux
  • s390-none
  • s390x-linux
  • s390x-none
  • vc4-none
  • wasm32-wasi
  • wasm64-wasi
  • x86_64-cygwin
  • x86_64-darwin
  • x86_64-freebsd
  • x86_64-genode
  • x86_64-linux
  • x86_64-netbsd
  • x86_64-none
  • x86_64-openbsd
  • x86_64-redox
  • x86_64-solaris
  • x86_64-windows