summaryrefslogtreecommitdiff
path: root/src/Inky/Context.idr
blob: b0393f33b7e07dd63404f7a8faec6b04c16a9075 (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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
module Inky.Context

import public Data.Singleton
import public Data.So

import Data.Bool.Decidable
import Data.Maybe.Decidable
import Data.DPair
import Data.Nat

-- Contexts --------------------------------------------------------------------

export
infix 2 :-

export
prefix 2 %%

public export
record Assoc (a : Type) where
  constructor (:-)
  name : String
  value : a

public export
Functor Assoc where
  map f x = x.name :- f x.value

namespace Irrelevant
  public export
  record Assoc0 (a : Type) where
    constructor (:-)
    0 name : String
    value : a

  public export
  Functor Assoc0 where
    map f x = x.name :- f x.value

public export
data Context : Type -> Type where
  Lin : Context a
  (:<) : Context a -> Assoc a -> Context a

public export
Functor Context where
  map f [<] = [<]
  map f (ctx :< x) = map f ctx :< map f x

public export
Foldable Context where
  foldr f x [<] = x
  foldr f x (ctx :< (_ :- y)) = foldr f (f y x) ctx

  foldl f x [<] = x
  foldl f x (ctx :< (_ :- y)) = f (foldl f x ctx) y

  null [<] = True
  null (ctx :< x) = False

%name Context ctx

public export
data Length : Context a -> Type where
  Z : Length [<]
  S : Length ctx -> Length (ctx :< x)

%name Length len

public export
(++) : Context a -> Context a -> Context a
ctx ++ [<] = ctx
ctx ++ ctx' :< x = (ctx ++ ctx') :< x

export
lengthAppend : Length ctx1 -> Length ctx2 -> Length (ctx1 ++ ctx2)
lengthAppend len1 Z = len1
lengthAppend len1 (S len2) = S (lengthAppend len1 len2)

length : Context a -> Nat
length [<] = 0
length (ctx :< x) = S (length ctx)

-- Variables -------------------------------------------------------------------

public export
data VarPos : Context a -> (0 x : String) -> a -> Type where
  [search x]
  Here : VarPos (ctx :< (x :- v)) x v
  There : VarPos ctx x v -> VarPos (ctx :< y) x v

public export
record Var (ctx : Context a) (v : a) where
  constructor (%%)
  0 name : String
  {auto pos : VarPos ctx name v}

%name VarPos pos
%name Var i, j, k

public export
toVar : VarPos ctx x v -> Var ctx v
toVar pos = (%%) x {pos}

public export
toNat : VarPos ctx x v -> Nat
toNat Here = 0
toNat (There pos) = S (toNat pos)

public export
ThereVar : Var ctx v -> Var (ctx :< x) v
ThereVar i = toVar (There i.pos)

-- Basic Properties

export
thereCong :
  {0 i : VarPos ctx x v} -> {0 j : VarPos ctx y v} -> i = j ->
  There {y = z} i = There {y = z} j
thereCong Refl = Refl

export
toVarCong : {0 i : VarPos ctx x v} -> {0 j : VarPos ctx y w} -> i = j -> toVar i = toVar j
toVarCong Refl = Refl

export
toNatCong : {0 i : VarPos ctx x v} -> {0 j : VarPos ctx y w} -> i = j -> toNat i = toNat j
toNatCong Refl = Refl

export
toNatCong' : {0 i, j : Var ctx v} -> i = j -> toNat i.pos = toNat j.pos
toNatCong' Refl = Refl

export
toNatInjective : {i : VarPos ctx x v} -> {j : VarPos ctx y w} -> (0 _ : toNat i = toNat j) -> i = j
toNatInjective {i = Here} {j = Here} prf = Refl
toNatInjective {i = There i} {j = There j} prf with (toNatInjective {i} {j} $ injective prf)
  toNatInjective {i = There i} {j = There .(i)} prf | Refl = Refl

export
toVarInjective : {i : VarPos ctx x v} -> {j : VarPos ctx y v} -> (0 _ : toVar i = toVar j) -> i = j
toVarInjective prf = toNatInjective $ toNatCong' prf

-- Decidable Equality

export
eq : Var ctx v -> Var ctx w -> Bool
eq i j = toNat i.pos == toNat j.pos

public export
Eq (Var {a} ctx v) where
  (==) = eq

reflectPosEq :
  (i : VarPos ctx x v) ->
  (j : VarPos ctx y w) ->
  (i = j) `Reflects` (toNat i == toNat j)
reflectPosEq Here Here = RTrue Refl
reflectPosEq Here (There j) = RFalse (\case Refl impossible)
reflectPosEq (There i) Here = RFalse (\case Refl impossible)
reflectPosEq (There i) (There j) with (reflectPosEq i j) | (toNat i == toNat j)
  reflectPosEq (There i) (There .(i)) | RTrue Refl | _ = RTrue Refl
  _ | RFalse neq | _ = RFalse (\case Refl => neq Refl)

export
reflectEq : (i : Var {a} ctx v) -> (j : Var ctx w) -> (i = j) `Reflects` (i `eq` j)
reflectEq ((%%) x {pos = pos1}) ((%%) y {pos = pos2})
  with (reflectPosEq pos1 pos2) | (toNat pos1 == toNat pos2)
  _ | RTrue eq | _ = RTrue (toVarCong eq)
  _ | RFalse neq | _ = RFalse (\case Refl => neq Refl)

-- Weakening

wknLPos : VarPos ctx1 x v -> Length ctx2 -> VarPos (ctx1 ++ ctx2) x v
wknLPos pos Z = pos
wknLPos pos (S len) = There (wknLPos pos len)

wknRPos : VarPos ctx2 x v -> VarPos (ctx1 ++ ctx2) x v
wknRPos Here = Here
wknRPos (There pos) = There (wknRPos pos)

splitPos : Length ctx2 -> VarPos (ctx1 ++ ctx2) x v -> Either (VarPos ctx1 x v) (VarPos ctx2 x v)
splitPos Z pos = Left pos
splitPos (S len) Here = Right Here
splitPos (S len) (There pos) = mapSnd There $ splitPos len pos

export
wknL : {auto len : Length ctx2} -> Var ctx1 v -> Var (ctx1 ++ ctx2) v
wknL i = toVar $ wknLPos i.pos len

export
wknR : Var ctx2 v -> Var (ctx1 ++ ctx2) v
wknR i = toVar $ wknRPos i.pos

export
split : {auto len : Length ctx2} -> Var (ctx1 ++ ctx2) x -> Either (Var ctx1 x) (Var ctx2 x)
split i = bimap toVar toVar $ splitPos len i.pos

export
lift :
  {auto len : Length ctx} ->
  (forall x. Var ctx1 x -> Var ctx2 x) ->
  Var (ctx1 ++ ctx) x -> Var (ctx2 ++ ctx) x
lift f = either (wknL {len} . f) wknR . split {len}

-- Names

nameOfPos : {ctx : Context a} -> VarPos ctx x v -> Singleton x
nameOfPos Here = Val x
nameOfPos (There pos) = nameOfPos pos

export
nameOf : {ctx : Context a} -> (i : Var ctx v) -> Singleton i.name
nameOf i = nameOfPos i.pos

-- Environments ----------------------------------------------------------------

namespace Quantifier
  public export
  data All : (0 p : a -> Type) -> Context a -> Type where
    Lin : All p [<]
    (:<) :
      All p ctx -> (px : Assoc0 (p x.value)) ->
      {auto 0 prf : px.name = x.name}->
      All p (ctx :< x)

  %name Quantifier.All env

  indexAllPos : VarPos ctx x v -> All p ctx -> p v
  indexAllPos Here (env :< px) = px.value
  indexAllPos (There pos) (env :< px) = indexAllPos pos env

  export
  indexAll : Var ctx v -> All p ctx -> p v
  indexAll i env = indexAllPos i.pos env

  export
  mapProperty : ({0 x : a} -> p x -> q x) -> All p ctx -> All q ctx
  mapProperty f [<] = [<]
  mapProperty f (env :< (x :- px)) = mapProperty f env :< (x :- f px)

  export
  (++) : All p ctx1 -> All p ctx2 -> All p (ctx1 ++ ctx2)
  env1 ++ [<] = env1
  env1 ++ env2 :< px = (env1 ++ env2) :< px

-- Rows ------------------------------------------------------------------------

namespace Row
  ||| Contexts where names are unique.
  public export
  data Row : Type -> Type

  public export
  freshIn : String -> Row a -> Bool

  data Row where
    Lin : Row a
    (:<) : (row : Row a) -> (x : Assoc a) -> {auto 0 fresh : So (x.name `freshIn` row)} -> Row a

  x `freshIn` [<] = True
  x `freshIn` (row :< y) = x /= y.name && (x `freshIn` row)

  %name Row row

  public export
  map : (a -> b) -> Row a -> Row b
  export
  0 mapFresh : (f : a -> b) -> (row : Row a) -> So (x `freshIn` row) -> So (x `freshIn` map f row)

  map f [<] = [<]
  map f ((:<) row x {fresh}) = (:<) (map f row) (map f x) {fresh = mapFresh f row fresh}

  mapFresh f [<] = id
  mapFresh f (row :< (y :- _)) = andSo . mapSnd (mapFresh f row) . soAnd

  public export
  Functor Row where
    map = Row.map

  public export
  Foldable Row where
    foldr f x [<] = x
    foldr f x (row :< (_ :- y)) = foldr f (f y x) row

    foldl f x [<] = x
    foldl f x (row :< (_ :- y)) = f (foldl f x row) y

    null [<] = True
    null (row :< x) = False

  ||| Forget the freshness of names.
  public export
  forget : Row a -> Context a
  forget [<] = [<]
  forget (row :< x) = forget row :< x

  -- Equality --

  soUnique : (x, y : So b) -> x = y
  soUnique Oh Oh = Refl

  export
  snocCong2 :
    {0 row1, row2 : Row a} -> row1 = row2 ->
    {0 x, y : Assoc a} -> x = y ->
    {0 fresh1 : So (x.name `freshIn` row1)} ->
    {0 fresh2 : So (y.name `freshIn` row2)} ->
    row1 :< x = row2 :< y
  snocCong2 Refl Refl = rewrite soUnique fresh1 fresh2 in Refl

  -- Variables aren't fresh --

  -- NOTE: cannot implement
  0 strEqReflect : (x, y : String) -> (x = y) `Reflects` (x == y)
  strEqReflect x y = believe_me ()

  0 strEqRefl : (x : String) -> Not (So (x /= x))
  strEqRefl x prf with (strEqReflect x x) | (x == x)
    _ | RTrue _ | _ = absurd prf
    _ | RFalse neq | _ = neq Refl

  export
  0 varPosNotFresh : VarPos (forget row) x v -> Not (So (x `freshIn` row))
  varPosNotFresh {row = row :< (x :- v)} Here fresh = strEqRefl x (fst $ soAnd fresh)
  varPosNotFresh {row = row :< y} (There pos) fresh = varPosNotFresh pos (snd $ soAnd fresh)

  export
  varUniqueIndex : (row : Row a) -> VarPos (forget row) x v -> VarPos (forget row) x w -> v = w
  varUniqueIndex (row :< (x :- _)) Here Here = Refl
  varUniqueIndex ((:<) row (x :- _) {fresh}) Here (There pos2) = void $ varPosNotFresh pos2 fresh
  varUniqueIndex ((:<) row (x :- _) {fresh}) (There pos1) Here = void $ varPosNotFresh pos1 fresh
  varUniqueIndex (row :< (y :- _)) (There pos1) (There pos2) = varUniqueIndex row pos1 pos2

  -- Equivalence --

  export infix 6 <~>

  public export
  data Step : Row a -> Row a -> Type where
    Cong :
      Step row1 row2 -> (0 x : Assoc a) ->
      {0 fresh1 : So (x.name `freshIn` row1)} ->
      {0 fresh2 : So (x.name `freshIn` row2)} ->
      Step (row1 :< x) (row2 :< x)
    Swap :
      (0 x : Assoc a) -> (0 y : Assoc a) ->
      {0 fresh1 : So (x.name `freshIn` row)} ->
      {0 fresh2 : So (y.name `freshIn` row :< x)} ->
      {0 fresh3 : So (y.name `freshIn` row)} ->
      {0 fresh4 : So (x.name `freshIn` row :< y)} ->
      Step (row :< x :< y) (row :< y :< x)

  public export
  data (<~>) : Row a -> Row a -> Type where
    Nil : row <~> row
    (::) : Step row1 row2 -> row2 <~> row3 -> row1 <~> row3

  %name Step step
  %name (<~>) prf

  export
  trans : row1 <~> row2 -> row2 <~> row3 -> row1 <~> row3
  trans [] prf = prf
  trans (step :: prf1) prf2 = step :: trans prf1 prf2

  symStep : Step row1 row2 -> Step row2 row1
  symStep (Cong step x) = Cong (symStep step) x
  symStep (Swap x y) = Swap y x

  export
  sym : row1 <~> row2 -> row2 <~> row1
  sym [] = []
  sym (step :: prf) = trans (sym prf) [symStep step]

  equivLengthStep : Step row1 row2 -> length (forget row1) = length (forget row2)
  equivLengthStep (Cong step x) = cong S (equivLengthStep step)
  equivLengthStep (Swap x y) = Refl

  equivLength : row1 <~> row2 -> length (forget row1) = length (forget row2)
  equivLength [] = Refl
  equivLength (step :: prf) = trans (equivLengthStep step) (equivLength prf)

  export
  Uninhabited ((:<) row x {fresh} <~> [<]) where
    uninhabited prf = absurd (equivLength prf)

  export
  Uninhabited ([<] <~> (:<) row x {fresh}) where
    uninhabited prf = absurd (equivLength prf)

  0 equivFreshInStep : Step row1 row2 -> So (x `freshIn` row1) -> So (x `freshIn` row2)
  equivFreshInStep (Cong step y) = andSo . mapSnd (equivFreshInStep step) . soAnd
  equivFreshInStep (Swap {row} (y :- v) (z :- w)) =
    andSo . mapSnd andSo .
    (\(prf1, prf2, prf3) => (prf2, prf1, prf3)) .
    mapSnd (soAnd {a = x /= y, b = freshIn x row}) . soAnd

  0 equivFreshIn : row1 <~> row2 -> So (x `freshIn` row1) -> So (x `freshIn` row2)
  equivFreshIn [] = id
  equivFreshIn (step :: prf) = equivFreshIn prf . equivFreshInStep step

  cong :
    row1 <~> row2 -> (0 x : Assoc a) ->
    {0 fresh1 : So (x.name `freshIn` row1)} ->
    {0 fresh2 : So (x.name `freshIn` row2)} ->
    row1 :< x <~> row2 :< x
  cong [] x = rewrite soUnique fresh1 fresh2 in []
  cong (step :: prf) x =
    let 0 fresh' = equivFreshInStep step fresh1 in
    Cong step x {fresh2 = fresh'} :: cong prf x

  -- Removal --

  public export
  removePos : (row : Row a) -> VarPos (forget row) x v -> (Singleton v, Row a)
  export
  0 removePosFresh :
    (row : Row a) -> (pos : VarPos (forget row) x v) ->
    So (y `freshIn` row) -> So (y `freshIn` snd (removePos row pos))

  removePos (row :< (_ :- v)) Here = (Val v, row)
  removePos ((:<) row x {fresh}) (There pos) =
    ( fst (removePos row pos)
    , (:<) (snd $ removePos row pos) x {fresh = removePosFresh row pos fresh}
    )

  removePosFresh (row :< _) Here = snd . soAnd
  removePosFresh ((:<) row (z :- v) {fresh}) (There pos) =
    andSo . mapSnd (removePosFresh row pos) . soAnd

  public export
  remove : (row : Row a) -> Var (forget row) v -> (Singleton v, Row a)
  remove row i = removePos row i.pos

  -- Reflection

  -- NOTE: cannot implement
  0 soNotSym : {x, y : String} -> So (x /= y) -> So (y /= x)
  soNotSym = believe_me

  0 freshNotPos : (row : Row a) -> VarPos (forget row) x v -> So (y `freshIn` row) -> So (y /= x)
  freshNotPos (row :< _) Here = fst . soAnd
  freshNotPos (row :< x) (There pos) = freshNotPos row pos . snd . soAnd

  export
  0 removedIsFresh :
    (row : Row a) -> (pos : VarPos (forget row) x v) ->
    So (x `freshIn` snd (removePos row pos))
  removedIsFresh ((:<) row _ {fresh}) Here = fresh
  removedIsFresh ((:<) row (y :- v) {fresh}) (There pos) =
    andSo (soNotSym (freshNotPos row pos fresh), removedIsFresh row pos)

  export
  reflectRemovePos :
    (row : Row a) -> (pos : VarPos (forget row) x v) ->
    (:<) (snd $ removePos row pos) (x :- v) {fresh = removedIsFresh row pos} <~> row
  reflectRemovePos ((:<) row _ {fresh}) Here = []
  reflectRemovePos ((:<) row (y :- w) {fresh}) (There pos) =
    (  Swap (y :- w) (x :- v)
         {fresh4 = andSo (freshNotPos row pos fresh, removePosFresh row pos fresh)}
    :: cong (reflectRemovePos row pos) (y :- w))

  -- Tracing Variables --

  equivVarPosStep : Step row1 row2 -> VarPos (forget row1) x v -> VarPos (forget row2) x v
  equivVarPosStep (Cong step _) Here = Here
  equivVarPosStep (Cong step y) (There pos) = There (equivVarPosStep step pos)
  equivVarPosStep (Swap y _) Here = There Here
  equivVarPosStep (Swap _ z) (There Here) = Here
  equivVarPosStep (Swap y z) (There (There pos)) = There (There pos)

  export
  equivVarPos : row1 <~> row2 -> VarPos (forget row1) x v -> VarPos (forget row2) x v
  equivVarPos [] = id
  equivVarPos (step :: prf) = equivVarPos prf . equivVarPosStep step

  removePosInjectiveStep :
    (prf : Step row1 row2) -> (pos : VarPos (forget row1) x v) ->
    snd (removePos row1 pos) <~> snd (removePos row2 (equivVarPosStep prf pos))
  removePosInjectiveStep (Cong step _) Here = [step]
  removePosInjectiveStep (Cong step (y :- v)) (There pos) =
    cong (removePosInjectiveStep step pos) (y :- v)
  removePosInjectiveStep (Swap (y :- v) _) Here = cong [] (y :- v)
  removePosInjectiveStep (Swap _ (z :- v)) (There Here) = cong [] (z :- v)
  removePosInjectiveStep (Swap (y :- v) (z :- w)) (There (There pos)) = [Swap (y :- v) (z :- w)]

  export
  removePosInjective :
    (prf : row1 <~> row2) -> (pos : VarPos (forget row1) x v) ->
    snd (removePos row1 pos) <~> snd (removePos row2 (equivVarPos prf pos))
  removePosInjective [] pos = []
  removePosInjective (step :: prf) pos =
    trans (removePosInjectiveStep step pos) (removePosInjective prf $ equivVarPosStep step pos)

  export
  equivVarUnique :
    {0 fresh1 : So (x `freshIn` row1)} ->
    {0 fresh2 : So (x `freshIn` row2)} ->
    (prf : row1 :< (x :- v) <~> row2 :< (x :- v)) ->
    equivVarPos prf Here = Here
  equivVarUnique prf with (equivVarPos prf Here)
    _ | Here = Refl
    _ | There pos = void $ varPosNotFresh pos fresh2

  -- Partial Removal --

  FreshOrNothing : String -> Maybe (a, Row a) -> Type
  FreshOrNothing x Nothing = ()
  FreshOrNothing x (Just (a, row)) = So (x `freshIn` row)

  removeHelper :
    (m : Maybe (a, Row a)) -> (x : Assoc a) ->
    (0 fresh : FreshOrNothing x.name m) ->
    Maybe (a, Row a)
  removeHelper Nothing x fresh = Nothing
  removeHelper (Just (v, row)) x fresh = Just (v, row :< x)

  ||| Attempt to remove the value at name `x` from the row.
  export
  remove' : String -> Row a -> Maybe (a, Row a)
  removeFresh :
    (x : String) -> (row : Row a) ->
    {y : String} -> So (y `freshIn` row) -> FreshOrNothing y (remove' x row)

  remove' x [<] = Nothing
  remove' x ((:<) row (y :- v) {fresh}) =
    if y == x
    then Just (v, row)
    else removeHelper (remove' x row) (y :- v) (removeFresh x row fresh)

  removeFresh x [<] prf = ()
  removeFresh x (row :< (y :- v)) {y = z} prf with (y == x)
    _ | True = snd (soAnd prf)
    _ | False with (removeFresh x row $ snd $ soAnd prf) | (remove' x row)
      _ | _ | Nothing = ()
      _ | prf' | Just (v', row') = andSo (fst (soAnd prf), prf')

  -- Reflection

  notSoToSoNot : {b : Bool} -> Not (So b) -> So (not b)
  notSoToSoNot {b = False} nprf = Oh
  notSoToSoNot {b = True} nprf = absurd (nprf Oh)

  0 reflectRemoveHelper : {x, y : String} -> Not (x = y) -> Not (So (x == y))
  reflectRemoveHelper neq eq with (strEqReflect x y) | (x == y)
    reflectRemoveHelper neq Oh | RTrue eq | _ = neq eq

  reflectRemoveHelper' :
    {0 fresh1 : So (y `freshIn` row1)} ->
    (x : String) -> Not (y = x) ->
    (0 fresh2 : So (x `freshIn` row2)) -> (prf : row1 :< (y :- v) <~> row2 :< (x :- v')) ->
    (  pos : VarPos (forget row2) y v
    ** snd (removePos (row2 :< (x :- v')) (equivVarPos prf Here)) <~>
           (:<) (snd (removePos row2 pos)) (x :- v')
             {fresh = removePosFresh row2 pos {y = x} fresh2})
  reflectRemoveHelper' x neq fresh2 prf with (equivVarPos prf Here)
    reflectRemoveHelper' x neq fresh2 prf | Here = absurd (neq Refl)
    reflectRemoveHelper' x neq fresh2 prf | There pos =
      (pos ** [])

  public export
  Remove : String -> Row a -> a -> Row a -> Type
  Remove x row v row' =
    Exists {type = So (x `freshIn` row')} (\fresh => row <~> row' :< (x :- v))

  export
  removeUnique :
    (x : String) -> (row1 : Row a) ->
    Remove x row1 v row2 -> Remove x row1 w row3 -> (v = w, row2 <~> row3)
  removeUnique x row1 (Evidence fresh1 prf1) (Evidence fresh2 prf2) =
    let eq = varUniqueIndex row1 (equivVarPos (sym prf1) Here) (equivVarPos (sym prf2) Here) in
    let
      prf : row2 :< (x :- v) <~> row3 :< (x :- v)
      prf = trans (sym prf1) (rewrite eq in prf2)
    in
    ( eq
    , replace
        {p = \pos => row2 <~> snd (removePos (row3 :< (x :- v)) pos)}
        (equivVarUnique prf)
        (removePosInjective prf Here))

  export
  0 reflectRemove :
    (x : String) -> (row : Row a) ->
    uncurry (Remove x row) `OnlyWhen` remove' x row
  reflectRemove x [<] = RNothing (\(v, row), (Evidence _ prf) => absurd prf)
  reflectRemove x ((:<) row (y :- v) {fresh}) with (strEqReflect y x) | (y == x)
    _ | RTrue eq | _ = rewrite sym eq in RJust (Evidence fresh [])
    _ | RFalse neq | _ with (reflectRemove x row, removeFresh x row {y}) | (remove' x row)
      _ | (RJust (Evidence fresh' prf), mkFresh) | Just (v', row') =
        RJust (Evidence
          (andSo (notSoToSoNot (reflectRemoveHelper (\eq => neq $ sym eq)), fresh'))
          (trans
            (cong prf (y :- v)
              {fresh2 = andSo (notSoToSoNot (reflectRemoveHelper neq), mkFresh fresh)})
            [Swap (x :- v') (y :- v)]))
      _ | (RNothing nprf, mkFresh) | _ =
        RNothing (\(v', row'), (Evidence fresh' prf) =>
          let (pos ** prf') = reflectRemoveHelper' x neq fresh' prf in
          void $
          nprf (v', snd (remove row' ((%%) y {pos}))) $
          Evidence
            (removePosFresh row' pos fresh')
            (trans (removePosInjective prf Here) prf'))