12
12
|||
13
13
||| We would write either of:
14
14
||| ```idris example
15
- ||| f1 : (n : Nat) -> (0 _ : HasLength xs n ) -> P xs
16
- ||| f2 : (n : Subset n (HasLength xs)) -> P xs
15
+ ||| f1 : (n : Nat) -> (0 _ : HasLength n xs ) -> P xs
16
+ ||| f2 : (n : Subset n (flip HasLength xs)) -> P xs
17
17
||| ```
18
18
|||
19
19
||| See `sucR` for an example where the update to the runtime-relevant Nat is O(1)
@@ -23,6 +23,7 @@ module Data.List.HasLength
23
23
24
24
import Data.DPair
25
25
import Data.List
26
+ import Data.Nat
26
27
27
28
%default total
28
29
@@ -31,35 +32,53 @@ import Data.List
31
32
32
33
||| Ensure that the list's length is the provided natural number
33
34
public export
34
- data HasLength : List a -> Nat -> Type where
35
- Z : HasLength [] Z
36
- S : HasLength xs n -> HasLength (x :: xs) (S n)
35
+ data HasLength : Nat -> List a -> Type where
36
+ Z : HasLength Z []
37
+ S : HasLength n xs -> HasLength (S n) (x :: xs)
38
+
39
+ ||| This specification corresponds to the length function
40
+ export
41
+ hasLength : (xs : List a) -> HasLength (length xs) xs
42
+ hasLength [] = Z
43
+ hasLength (_ :: xs) = S (hasLength xs)
44
+
45
+ export
46
+ take : (n : Nat ) -> (xs : Stream a) -> HasLength n (take n xs)
47
+ take Z _ = Z
48
+ take (S n) (x :: xs) = S (take n xs)
37
49
38
50
-- ----------------------------------------------------------------------
39
51
-- Properties
40
52
41
53
||| The length is unique
42
54
export
43
- hasLengthUnique : HasLength xs m -> HasLength xs n -> m === n
55
+ hasLengthUnique : HasLength m xs -> HasLength n xs -> m === n
44
56
hasLengthUnique Z Z = Refl
45
57
hasLengthUnique (S p) (S q) = cong S (hasLengthUnique p q)
46
58
47
- ||| This specification corresponds to the length function
48
59
export
49
- hasLength : (xs : List a) -> HasLength xs (length xs)
50
- hasLength [] = Z
51
- hasLength (_ :: xs) = S (hasLength xs)
60
+ hasLengthAppend : HasLength m xs -> HasLength n ys -> HasLength (m + n) (xs ++ ys)
61
+ hasLengthAppend Z ys = ys
62
+ hasLengthAppend (S xs) ys = S (hasLengthAppend xs ys)
63
+
64
+ hasLengthReverseOnto : HasLength m acc -> HasLength n xs -> HasLength (m + n) (reverseOnto acc xs)
65
+ hasLengthReverseOnto p Z = rewrite plusZeroRightNeutral m in p
66
+ hasLengthReverseOnto {n = S n} p (S q) = rewrite sym (plusSuccRightSucc m n) in hasLengthReverseOnto (S p) q
52
67
53
68
export
54
- map : (f : a -> b) -> HasLength xs n -> HasLength (map f xs) n
69
+ hasLengthReverse : HasLength m acc -> HasLength m (reverse acc)
70
+ hasLengthReverse = hasLengthReverseOnto Z
71
+
72
+ export
73
+ map : (f : a -> b) -> HasLength n xs -> HasLength n (map f xs)
55
74
map f Z = Z
56
75
map f (S n) = S (map f n)
57
76
58
77
||| @sucR demonstrates that snoc only increases the lenght by one
59
78
||| So performing this operation while carrying the list around would cost O(n)
60
79
||| but relying on n together with an erased HasLength proof instead is O(1)
61
80
export
62
- sucR : HasLength xs n -> HasLength (snoc xs x ) (S n )
81
+ sucR : HasLength n xs -> HasLength (S n ) (snoc xs x )
63
82
sucR Z = S Z
64
83
sucR (S n) = S (sucR n)
65
84
@@ -69,27 +88,27 @@ sucR (S n) = S (sucR n)
69
88
namespace SubsetView
70
89
71
90
||| We provide this view as a convenient way to perform nested pattern-matching
72
- ||| on values of type `Subset Nat (HasLength xs)`. Functions using this view will
91
+ ||| on values of type `Subset Nat (flip HasLength xs)`. Functions using this view will
73
92
||| be seen as terminating as long as the index list `xs` is left untouched.
74
93
||| See e.g. listTerminating below for such a function.
75
94
public export
76
- data View : (xs : List a) -> Subset Nat (HasLength xs) -> Type where
95
+ data View : (xs : List a) -> Subset Nat (flip HasLength xs) -> Type where
77
96
Z : View [] (Element Z Z)
78
- S : (p : Subset Nat (HasLength xs)) -> View (x :: xs) (Element (S (fst p)) (S (snd p)))
97
+ S : (p : Subset Nat (flip HasLength xs)) -> View (x :: xs) (Element (S (fst p)) (S (snd p)))
79
98
80
99
||| This auxiliary function gets around the limitation of the check ensuring that
81
100
||| we do not match on runtime-irrelevant data to produce runtime-relevant data.
82
- viewZ : (0 p : HasLength xs Z ) -> View xs (Element Z p)
101
+ viewZ : (0 p : HasLength Z xs ) -> View xs (Element Z p)
83
102
viewZ Z = Z
84
103
85
104
||| This auxiliary function gets around the limitation of the check ensuring that
86
105
||| we do not match on runtime-irrelevant data to produce runtime-relevant data.
87
- viewS : (n : Nat ) -> (0 p : HasLength xs (S n)) -> View xs (Element (S n) p)
106
+ viewS : (n : Nat ) -> (0 p : HasLength (S n) xs ) -> View xs (Element (S n) p)
88
107
viewS n (S p) = S (Element n p)
89
108
90
109
||| Proof that the view covers all possible cases.
91
110
export
92
- view : (p : Subset Nat (HasLength xs)) -> View xs p
111
+ view : (p : Subset Nat (flip HasLength xs)) -> View xs p
93
112
view (Element Z p) = viewZ p
94
113
view (Element (S n) p) = viewS n p
95
114
@@ -102,13 +121,13 @@ namespace CurriedView
102
121
||| separately from the HasLength proof and the Subset view is not as useful anymore.
103
122
||| See e.g. natTerminating below for (a contrived example of) such a function.
104
123
public export
105
- data View : (xs : List a) -> (n : Nat ) -> HasLength xs n -> Type where
124
+ data View : (xs : List a) -> (n : Nat ) -> HasLength n xs -> Type where
106
125
Z : View [] Z Z
107
- S : (n : Nat ) -> (0 p : HasLength xs n ) -> View (x :: xs) (S n) (S p)
126
+ S : (n : Nat ) -> (0 p : HasLength n xs ) -> View (x :: xs) (S n) (S p)
108
127
109
128
||| Proof that the view covers all possible cases.
110
129
export
111
- view : (n : Nat ) -> (0 p : HasLength xs n ) -> View xs n p
130
+ view : (n : Nat ) -> (0 p : HasLength n xs ) -> View xs n p
112
131
view Z Z = Z
113
132
view (S n) (S p) = S n p
114
133
@@ -117,22 +136,24 @@ namespace CurriedView
117
136
118
137
-- /!\ Do NOT re-export these examples
119
138
120
- listTerminating : (p : Subset Nat (HasLength xs)) -> HasLength (xs ++ [x]) (S (fst p) )
121
- listTerminating p = case view p of
122
- Z => S Z
123
- S p => S (listTerminating p )
139
+ listTerminating : (p : Subset Nat (flip HasLength xs)) -> HasLength (S (fst p)) ( xs ++ [x])
140
+ listTerminating p with ( view p)
141
+ listTerminating ( Element 0 Z ) | Z = S Z
142
+ listTerminating ( Element ( S ( fst y)) ( S ( snd y))) | ( S y) = S (listTerminating y )
124
143
125
144
data P : List Nat -> Type where
126
145
PNil : P []
127
146
PCon : P (map f xs) -> P (x :: xs)
128
147
129
148
covering
130
- notListTerminating : (p : Subset Nat (HasLength xs)) -> P xs
131
- notListTerminating p = case view p of
132
- Z => PNil
133
- S p => PCon (notListTerminating {xs = map id (tail xs)} ({ snd $= map id } p))
149
+ notListTerminating : (p : Subset Nat (flip HasLength xs)) -> P xs
150
+ notListTerminating p with (view p)
151
+ notListTerminating (Element 0 Z ) | Z = PNil
152
+ notListTerminating (Element (S (fst y)) (S (snd y))) | (S y) =
153
+ PCon (notListTerminating {xs = map id (tail xs)} ({ snd $= map id } y))
134
154
135
- natTerminating : (n : Nat ) -> (0 p : HasLength xs n ) -> P xs
155
+ natTerminating : (n : Nat ) -> (0 p : HasLength n xs ) -> P xs
136
156
natTerminating n p = case view n p of
137
157
Z => PNil
138
158
S n p => PCon (natTerminating n (map id p))
159
+
0 commit comments