summaryrefslogtreecommitdiff
path: root/src/Data/Term.idr
blob: 973ff3d55da754477678d064db7b0da87e162347 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
module Data.Term

import public Data.DPair
import public Data.Vect
import Data.Vect.Properties.Map
import Syntax.PreorderReasoning

%prefix_record_projections off

-- Definition ------------------------------------------------------------------

public export
record Signature where
  constructor MkSignature
  Operator : Nat -> Type

%name Signature sig

public export
(.Op) : Signature -> Type
sig .Op = Exists sig.Operator

public export
interface DecOp (0 sig : Signature) where
  decOp : (op, op' : sig.Op) -> Dec (op = op')

public export
data Term : Signature -> Nat -> Type where
  Var : Fin n -> Term sig n
  Op : sig.Operator k -> Vect k (Term sig n) -> Term sig n

%name Term t, u, v

export
Uninhabited (Op op ts = Var x) where uninhabited prf impossible

-- Substitution ----------------------------------------------------------------

export
pure : (Fin k -> Fin n) -> Fin k -> Term sig n
pure r = Var . r

public export
(<$>) : (Fin k -> Term sig n) -> Term sig k -> Term sig n
f <$> Var i = f i
f <$> Op op ts = Op op (map (\t => f <$> assert_smaller ts t) ts)

-- Extensional Equality --------------------------------------------------------

public export
0 (.=.) : Rel (Fin k -> Term sig n)
f .=. g = (i : Fin k) -> f i = g i

export
subExtensional : {f, g : Fin k -> Term sig n} -> f .=. g -> (t : Term sig k) -> f <$> t = g <$> t
subExtensional prf (Var i) = prf i
subExtensional prf (Op op ts) =
  cong (Op op) $
  mapExtensional (f <$>) (g <$>) (\t => subExtensional prf (assert_smaller ts t)) ts

-- Substitution is Monadic -----------------------------------------------------

public export
(.) : (Fin k -> Term sig n) -> (Fin j -> Term sig k) -> Fin j -> Term sig n
f . g = (f <$>) . g

-- Properties

export
subUnit : (t : Term sig n) -> Var <$> t = t
subUnit (Var i) = Refl
subUnit (Op op ts) = cong (Op op) $ Calc $
  |~ map (Var <$>) ts
  ~~ map id ts        ...(mapExtensional (Var <$>) id (\t => subUnit (assert_smaller ts t)) ts)
  ~~ ts               ...(mapId ts)

export
subAssoc :
  (f : Fin k -> Term sig n) ->
  (g : Fin j -> Term sig k) ->
  (t : Term sig j) ->
  (f . g) <$> t = f <$> g <$> t
subAssoc f g (Var i) = Refl
subAssoc f g (Op op ts) = cong (Op op) $ Calc $
  |~ map ((f . g) <$>) ts
  ~~ map ((f <$>) . (g <$>)) ts   ...(mapExtensional ((f . g) <$>) ((f <$>) . (g <$>)) (\t => subAssoc f g (assert_smaller ts t)) ts)
  ~~ map (f <$>) (map (g <$>) ts) ..<(mapFusion (f <$>) (g <$>) ts)

export
subComp :
  (f : Fin k -> Term sig n) ->
  (r : Fin j -> Fin k) ->
  f . pure r .=. f . r
subComp f r i = Refl

export
compCong2 :
  {0 f1, f2 : Fin k -> Term sig n} ->
  {0 g1, g2 : Fin j -> Term sig k} ->
  f1 .=. f2 ->
  g1 .=. g2 ->
  f1 . g1 .=. f2 . g2
compCong2 prf1 prf2 i = Calc $
  |~ f1 <$> g1 i
  ~~ f1 <$> g2 i ...(cong (f1 <$>) $ prf2 i)
  ~~ f2 <$> g2 i ...(subExtensional prf1 (g2 i))

compCongL :
  {0 f1, f2 : Fin k -> Term sig n} ->
  f1 .=. f2 ->
  (0 g : Fin j -> Term sig k) ->
  f1 . g .=. f2 . g
compCongL prf g = compCong2 prf (\_ => Refl)

compCongR :
  (0 f : Fin k -> Term sig n) ->
  {0 g1, g2 : Fin j -> Term sig k} ->
  g1 .=. g2 ->
  f . g1 .=. f . g2
compCongR f prf = compCong2 (\_ => Refl) prf

-- Injectivity -----------------------------------------------------------------

export
opInjectiveLen : (prf : Op {k} op ts = Op {k = n} op' us) -> k = n
opInjectiveLen Refl = Refl

export
opInjectiveOp :
  (prf : Op {sig, k} op ts = Op {sig, k = n} op' us) ->
  the sig.Op (Evidence k op) = Evidence n op'
opInjectiveOp Refl = Refl

export
opInjectiveTs' : {0 ts, us : Vect k (Term sig n)} -> (prf : Op op ts = Op op us) -> ts = us
opInjectiveTs' Refl = Refl

export
opInjectiveTs :
  {0 ts : Vect k (Term sig n)} ->
  {0 us : Vect j (Term sig n)} ->
  (prf : Op op ts = Op op' us) -> ts = (rewrite opInjectiveLen prf in us)
opInjectiveTs Refl = Refl