MyNixOS website logo
Description

Generic programming without too many type classes.

This library provides a representation build on top of GHC.Generics, which can be used to describe generic operations on a single function, instead of having each case defined in an instance of a type class.

simplistic-generics: generic programming without too many type classes

This library provides a way to do data type-generic programming in GHC, re-using almost all the machinery from GHC.Generics, but without the need to define a different generic type class for each new operation.

Say that you want to define an operation op in a generic fashion. The docs of GHC.Generics tell you that you need to create a new type class whose argument is the set of pattern functors that may generate the data type. Then by means of a default declaration you bridge the gap between both versions. Furthermore, in almost every case the instances of this class follow the same pattern:

class GOp (f :: * -> *) where
  gop :: ...
instance GOp U1 where ...
instance (GOp f, GOp g) => GOp (f :+: g) where ...
instance (GOp f, GOp g) => GOp (f :*: g) where ...
instance (GOp f) => GOp (M1 i p f) where ...
instance Op t => GOp (K1 r t) where ...

class Op a where
  op :: ...
  default op :: (Generic a, GOp (Rep a)) => ...
  op = ... gop ...

When using simplistic-generics you do not introduce such a type class; you just write all the cases of the generic function in one go! The only thing you need to remember is that you have to pattern match on values of the type SRep w f, where f is the pattern functor from GHC.Generics. The definition of the previous operation looks then:

gop :: ... SRep w f ...
gop ... S_U1       ... = ...
gop ... (S_L1 x)   ... = ...
gop ... (S_R1 x)   ... = ...
gop ... (x :**: y) ... = ...
gop ... (S_M1 x)   ... = ...
gop ... (S_K1 x)   ... = ...

There is only one missing link here. In the definition of GOp using type classes we tied the knot by asking the K1 instance to satisfy Op recursively. In the case of SRep we have a special OnLeaves combinator which requires a constraint from each K1 node. The signature for gop should read then:

gop :: OnLeaves Op f => ... SRep w f ...

The final touch is that instead of using from and to to convert back and forth generic representations, you use fromS and toS to get a SRep w f.

For real examples, check the Derive folder in the repo.

Inspiration

This library is inspired by several previous work:

Metadata

Version

2.0.0

Platforms (77)

    Darwin
    FreeBSD
    Genode
    GHCJS
    Linux
    MMIXware
    NetBSD
    none
    OpenBSD
    Redox
    Solaris
    WASI
    Windows
Show all
  • aarch64-darwin
  • aarch64-freebsd
  • aarch64-genode
  • aarch64-linux
  • aarch64-netbsd
  • aarch64-none
  • aarch64-windows
  • 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