mirror of
https://github.com/idris-lang/Idris2.git
synced 2024-12-23 03:32:09 +03:00
89 lines
2.3 KiB
Idris
89 lines
2.3 KiB
Idris
module Data.Linear.Interface
|
|
|
|
import Data.Linear.Notation
|
|
import Data.Linear.Bifunctor
|
|
import public Data.Linear.Copies
|
|
|
|
%default total
|
|
|
|
||| An interface for consumable types
|
|
public export
|
|
interface Consumable a where
|
|
consume : a -@ ()
|
|
|
|
||| Void and the unit type are trivially consumable
|
|
export
|
|
Consumable Void where consume v impossible
|
|
|
|
export
|
|
Consumable () where consume u = u
|
|
|
|
||| Unions can be consumed by pattern matching
|
|
export
|
|
Consumable Bool where
|
|
consume True = ()
|
|
consume False = ()
|
|
|
|
export
|
|
Consumable (!* a) where
|
|
consume (MkBang v) = ()
|
|
|
|
||| We can cheat to make built-in types consumable
|
|
export
|
|
Consumable Int where
|
|
consume = believe_me (\ 0 i : Int => ())
|
|
|
|
-- But crucially we don't have `Consumable World` or `Consumable Handle`.
|
|
|
|
infixr 5 `seq`
|
|
||| We can sequentially compose a computation returning a value that is
|
|
||| consumable with another computation. This is done by first consuming
|
|
||| the result of the first computation and then returning the second one.
|
|
export
|
|
seq : Consumable a => a -@ b -@ b
|
|
a `seq` b = let 1 () = consume a in b
|
|
|
|
public export
|
|
interface Duplicable a where
|
|
duplicate : (1 v : a) -> 2 `Copies` v
|
|
|
|
export
|
|
Duplicable Void where
|
|
duplicate v impossible
|
|
|
|
export
|
|
Duplicable () where
|
|
duplicate () = [(), ()]
|
|
|
|
export
|
|
Duplicable Bool where
|
|
duplicate True = [True, True]
|
|
duplicate False = [False, False]
|
|
|
|
export
|
|
Duplicable (!* a) where
|
|
duplicate (MkBang v) = [MkBang v, MkBang v]
|
|
|
|
||| Comonoid is the dual of Monoid, it can consume a value linearly and duplicate a value linearly
|
|
||| `comult` returns a pair instead of 2 copies, because we do not guarantee that the two values
|
|
||| are identical, unlike with `duplicate`. For example if we build a comonoid out of a group, with
|
|
||| comult returning both the element given and its inverse:
|
|
||| comult x = x # inverse x
|
|
||| It is not necessarily the case that x equals its inverse. For example the finite groupe of size
|
|
||| 3, has 1 and 2 as inverses of each other wrt to addition, but are not the same.
|
|
public export
|
|
interface Comonoid a where
|
|
counit : a -@ ()
|
|
comult : a -@ LPair a a
|
|
|
|
||| If a value is consumable and duplicable we can make an instance of Comonoid for it
|
|
export
|
|
[AutoComonoid] Consumable a => Duplicable a => Comonoid a where
|
|
counit = consume
|
|
comult x = pair (duplicate x)
|
|
|
|
export
|
|
Comonoid (!* a) where
|
|
counit (MkBang _) = ()
|
|
comult (MkBang v) = MkBang v # MkBang v
|