Skip to content

Add Invariant Abstraction #104

Description

@jhbertra

Description

Add support for an abstraction that combines a Functor and a Contravariant in a way similar to a Profunctor, but where the output parameter is constrained to the input parameter.

From Haskell:

class Invariant f where
  invmap :: (a -> b) -> (b -> a) -> f a -> f b

This is a useful abstraction when dealing with bidirectional programming, for example:

type Decoder<'a> = (string -> Result<'a, string>)
type Encoder<'a> = ('a -> string)
type Codec<'a> =
  { decoder : Decoder<'a>
    encoder : Encoder<'a> }

type Decoder<'a> with
    static member Map(d : Decoder<'a>, f : 'a -> 'b) : Decoder<'b> = map f << d

type Encoder<'a> with
    static member Contramap(e : Encoder<'a>, f : 'b -> 'a) : Decoder<'b> = f >> e

type Codec<'a> with
    static member Invmap({ decoder = d; encoder = e } : Codec<'a>, f : 'a -> 'b, g : 'b -> 'a) : Codec<'b> =
        { decoder = map f d
          encoder = contramap g e }

A similar related abstraction is an Invariant2, a sort of Bifunctor analog of Invariant

class Invariant2 f where
  invmap2 :: (a -> c) -> (c -> a) -> (b -> d) -> (d -> b) -> f a b -> f c d

Which has a similar application, except that it allows the definition of types like Codec<'a, 'b>, where the encoded type is parametric in addition to the decoded type.

If you like the suggested additions, I would be happy to submit a PR with these abstractions added.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions