mirror of
https://github.com/idris-lang/Idris2.git
synced 2024-12-24 20:23:11 +03:00
152 lines
5.0 KiB
Idris
152 lines
5.0 KiB
Idris
module Data.DPair
|
|
|
|
import Decidable.Equality
|
|
|
|
%default total
|
|
|
|
namespace Pair
|
|
|
|
||| Constructive choice: a function producing pairs of a value and a proof
|
|
||| can be split into a function producing a value and a family of proofs
|
|
||| for the images of that function.
|
|
public export
|
|
choice :
|
|
{0 p : a -> b -> Type} ->
|
|
((x : a) -> (b ** p x b)) ->
|
|
(f : (a -> b) ** (x : a) -> p x (f x))
|
|
choice pr = ((\ x => fst (pr x)) ** \ x => snd (pr x))
|
|
|
|
namespace DPair
|
|
|
|
||| Constructive choice: a function producing pairs of a value and a proof
|
|
||| can be split into a function producing a value and a family of proofs
|
|
||| for the images of that function.
|
|
public export
|
|
choice :
|
|
{0 b : a -> Type} ->
|
|
{0 p : (x : a) -> b x -> Type} ->
|
|
((x : a) -> (y : b x ** p x y)) ->
|
|
(f : ((x : a) -> b x) ** (x : a) -> p x (f x))
|
|
choice pr = ((\ x => fst (pr x)) ** \ x => snd (pr x))
|
|
|
|
||| A function taking a pair of a value and a proof as an argument can be turned
|
|
||| into a function taking a value and a proof as two separate arguments.
|
|
||| Use `uncurry` to go in the other direction
|
|
public export
|
|
curry : {0 p : a -> Type} -> ((x : a ** p x) -> c) -> ((x : a) -> p x -> c)
|
|
curry f x y = f (x ** y)
|
|
|
|
||| A function taking a value and a proof as two separates arguments can be turned
|
|
||| into a function taking a pair of that value and its proof as a single argument.
|
|
||| Use `curry` to go in the other direction.
|
|
public export
|
|
uncurry : {0 p : a -> Type} -> ((x : a) -> p x -> c) -> ((x : a ** p x) -> c)
|
|
uncurry f s = f s.fst s.snd
|
|
|
|
||| Given a function on values and a family of proofs that this function takes
|
|
||| p-respecting inputs to q-respecting outputs,
|
|
||| we can turn: a pair of a value and a proof it is p-respecting
|
|
||| into: a pair of a value and a proof it is q-respecting
|
|
public export
|
|
bimap : {0 p : a -> Type} -> {0 q : b -> Type} ->
|
|
(f : a -> b) ->
|
|
(prf : forall x. p x -> q (f x)) ->
|
|
(x : a ** p x) -> (y : b ** q y)
|
|
bimap f g (x ** y) = (f x ** g y)
|
|
|
|
public export
|
|
DecEq k => ({x : k} -> Eq (v x)) => Eq (DPair k v) where
|
|
(k1 ** v1) == (k2 ** v2) = case decEq k1 k2 of
|
|
Yes Refl => v1 == v2
|
|
No _ => False
|
|
|
|
namespace Exists
|
|
|
|
||| A dependent pair in which the first field (witness) should be
|
|
||| erased at runtime.
|
|
|||
|
|
||| We can use `Exists` to construct dependent types in which the
|
|
||| type-level value is erased at runtime but used at compile time.
|
|
||| This type-level value could represent, for instance, a value
|
|
||| required for an intrinsic invariant required as part of the
|
|
||| dependent type's representation.
|
|
|||
|
|
||| @type The type of the type-level value in the proof.
|
|
||| @this The dependent type that requires an instance of `type`.
|
|
public export
|
|
record Exists {0 type : Type} this where
|
|
constructor Evidence
|
|
0 fst : type
|
|
snd : this fst
|
|
|
|
public export
|
|
curry : {0 p : a -> Type} -> (Exists p -> c) -> ({0 x : a} -> p x -> c)
|
|
curry f = f . Evidence _
|
|
|
|
public export
|
|
uncurry : {0 p : a -> Type} -> ({0 x : a} -> p x -> c) -> Exists p -> c
|
|
uncurry f ex = f ex.snd
|
|
|
|
export
|
|
evidenceInjectiveFst : Evidence x p = Evidence y q -> x = y
|
|
evidenceInjectiveFst Refl = Refl
|
|
|
|
export
|
|
evidenceInjectiveSnd : Evidence x p = Evidence x q -> p = q
|
|
evidenceInjectiveSnd Refl = Refl
|
|
|
|
public export
|
|
bimap : (0 f : a -> b) -> (forall x. p x -> q (f x)) -> Exists {type=a} p -> Exists {type=b} q
|
|
bimap f g (Evidence x y) = Evidence (f x) (g y)
|
|
|
|
namespace Subset
|
|
|
|
||| A dependent pair in which the second field (evidence) should not
|
|
||| be required at runtime.
|
|
|||
|
|
||| We can use `Subset` to provide extrinsic invariants about a
|
|
||| value and know that these invariants are erased at
|
|
||| runtime but used at compile time.
|
|
|||
|
|
||| @type The type-level value's type.
|
|
||| @pred The dependent type that requires an instance of `type`.
|
|
public export
|
|
record Subset type pred where
|
|
constructor Element
|
|
fst : type
|
|
0 snd : pred fst
|
|
|
|
public export
|
|
curry : {0 p : a -> Type} -> (Subset a p -> c) -> (x : a) -> (0 _ : p x) -> c
|
|
curry f x y = f $ Element x y
|
|
|
|
public export
|
|
uncurry : {0 p : a -> Type} -> ((x : a) -> (0 _ : p x) -> c) -> Subset a p -> c
|
|
uncurry f s = f s.fst s.snd
|
|
|
|
export
|
|
elementInjectiveFst : Element x p = Element y q -> x = y
|
|
elementInjectiveFst Refl = Refl
|
|
|
|
export
|
|
elementInjectiveSnd : Element x p = Element x q -> p = q
|
|
elementInjectiveSnd Refl = Refl
|
|
|
|
public export
|
|
bimap : (f : a -> b) -> (0 _ : forall x. p x -> q (f x)) -> Subset a p -> Subset b q
|
|
bimap f g (Element x y) = Element (f x) (g y)
|
|
|
|
public export
|
|
Eq type => Eq (Subset type pred) where
|
|
(==) = (==) `on` fst
|
|
|
|
public export
|
|
Ord type => Ord (Subset type pred) where
|
|
compare = compare `on` fst
|
|
|
|
||| This Show implementation replaces the (erased) invariant
|
|
||| with an underscore.
|
|
export
|
|
Show type => Show (Subset type pred) where
|
|
showPrec p (Element v _) = showCon p "Element" $ showArg v ++ " _"
|