Skip to content

Commit 3f4362c

Browse files
author
Alex Gryzlov
committed
nicer syntax for Lists
1 parent c2ae0a7 commit 3f4362c

File tree

1 file changed

+62
-64
lines changed

1 file changed

+62
-64
lines changed

src/Lists.lidr

Lines changed: 62 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
> %hide Prelude.Basics.fst
88
> %hide Prelude.Basics.snd
99
> %hide Prelude.Nat.pred
10+
> %hide Prelude.List.(++)
1011

1112
> %access public export
1213
> %default total
@@ -124,27 +125,20 @@ and another list."
124125
125126
> data NatList : Type where
126127
> Nil : NatList
127-
> Cons : Nat -> NatList -> NatList
128+
> (::) : Nat -> NatList -> NatList
128129
129130
For example, here is a three-element list:
130131
131132
> mylist : NatList
132-
> mylist = Cons 1 (Cons 2 (Cons 3 Nil))
133+
> mylist = (::) 1 ((::) 2 ((::) 3 Nil))
134+
135+
\todo[inline]{Edit the section - Idris's list sugar automatically works for
136+
anything with constructors \idr{Nil} and \idr{(::)}}
133137
134138
As with pairs, it is more convenient to write lists in familiar programming
135139
notation. The following declarations allow us to use \idr{::} as an infix Cons
136140
operator and square brackets as an "outfix" notation for constructing lists.
137141
138-
> syntax [x] "::" [l] = Cons x l
139-
> syntax "[ ]" = Nil
140-
141-
\todo[inline]{Seems it's impossible to make an Idris \idr{syntax} to overload
142-
the list notation. Edit the section.}
143-
144-
```coq
145-
Notation "[ x ; .. ; y ]" := ( cons x .. ( cons y nil ) ..).
146-
```
147-
148142
It is not necessary to understand the details of these declarations, but in case
149143
you are interested, here is roughly what's going on. The right associativity
150144
annotation tells Coq how to parenthesize expressions involving several uses of
@@ -155,9 +149,10 @@ thing:
155149
> mylist1 = 1 :: (2 :: (3 :: Nil))
156150
157151
> mylist2 : NatList
158-
> mylist2 = 1::2::3::Nil
152+
> mylist2 = 1::2::3::[]
159153
160-
Definition mylist3 := [1;2;3].
154+
> mylist3 : NatList
155+
> mylist3 = [1,2,3]
161156
162157
The at level 60 part tells Coq how to parenthesize expressions that involve both
163158
:: and some other infix operator. For example, since we defined + as infix
@@ -190,7 +185,7 @@ A number of functions are useful for manipulating lists. For example, the
190185
list of length \idr{count} where every element is \idr{n}.
191186
192187
> repeat : (n, count : Nat) -> NatList
193-
> repeat n Z = Nil
188+
> repeat n Z = []
194189
> repeat n (S k) = n :: repeat n k
195190
196191
@@ -199,7 +194,7 @@ list of length \idr{count} where every element is \idr{n}.
199194
The \idr{length} function calculates the length of a list.
200195
201196
> length : (l : NatList) -> Nat
202-
> length Nil = Z
197+
> length [] = Z
203198
> length (h :: t) = S (length t)
204199
205200
@@ -208,21 +203,24 @@ The \idr{length} function calculates the length of a list.
208203
The \idr{app} function concatenates (appends) two lists.
209204
210205
> app : (l1, l2 : NatList) -> NatList
211-
> app Nil l2 = l2
206+
> app [] l2 = l2
212207
> app (h :: t) l2 = h :: app t l2
213208
214209
Actually, \idr{app} will be used a lot in some parts of what follows, so it is
215210
convenient to have an infix operator for it.
216211
217-
> syntax [x] "++" [y] = app x y
212+
> infixr 7 ++
213+
214+
> (++) : (x, y : NatList) -> NatList
215+
> (++) = app
218216
219-
> test_app1 : ((1::2::3::[]) ++ (4::5::[])) = (1::2::3::4::5::[])
217+
> test_app1 : [1,2,3] ++ [4,5,6] = [1,2,3,4,5,6]
220218
> test_app1 = Refl
221219
222-
> test_app2 : ([] ++ (4::5::[])) = (4::5::[])
220+
> test_app2 : [] ++ [4,5] = [4,5]
223221
> test_app2 = Refl
224222
225-
> test_app3 : ((1::2::3::[]) ++ []) = (1::2::3::[])
223+
> test_app3 : [1,2,3] ++ [] = [1,2,3]
226224
> test_app3 = Refl
227225
228226
@@ -234,20 +232,20 @@ everything but the first element (the "tail"). Of course, the empty list has no
234232
first element, so we must pass a default value to be returned in that case.
235233
236234
> hd : (default : Nat) -> (l : NatList) -> Nat
237-
> hd default Nil = default
235+
> hd default [] = default
238236
> hd default (h :: t) = h
239237
240238
> tl : (l : NatList) -> NatList
241-
> tl Nil = Nil
239+
> tl [] = []
242240
> tl (h :: t) = t
243241
244-
> test_hd1 : hd 0 (1::2::3::[]) = 1
242+
> test_hd1 : hd 0 [1,2,3] = 1
245243
> test_hd1 = Refl
246244
247245
> test_hd2 : hd 0 [] = 0
248246
> test_hd2 = Refl
249247
250-
> test_tl : tl (1::2::3::[]) = (2::3::[])
248+
> test_tl : tl [1,2,3] = [2,3]
251249
> test_tl = Refl
252250
253251
@@ -263,19 +261,19 @@ functions should do.
263261
> nonzeros : (l : NatList) -> NatList
264262
> nonzeros l = ?nonzeros_rhs
265263
266-
> test_nonzeros : nonzeros (0::1::0::2::3::0::0::[]) = (1::2::3::[])
264+
> test_nonzeros : nonzeros [0,1,0,2,3,0,0] = [1,2,3]
267265
> test_nonzeros = ?test_nonzeros_rhs
268266
269267
> oddmembers : (l : NatList) -> NatList
270268
> oddmembers l = ?oddmembers_rhs
271269
272-
> test_oddmembers : oddmembers (0::1::0::2::3::0::0::[]) = (1::3::[])
270+
> test_oddmembers : oddmembers [0,1,0,2,3,0,0] = [1,3]
273271
> test_oddmembers = ?test_oddmembers_rhs
274272
275273
> countoddmembers : (l : NatList) -> Nat
276274
> countoddmembers l = ?countoddmembers_rhs
277275
278-
> test_countoddmembers1 : countoddmembers (1::0::3::1::4::5::[]) = 4
276+
> test_countoddmembers1 : countoddmembers [1,0,3,1,4,5] = 4
279277
> test_countoddmembers1 = ?test_countoddmembers1_rhs
280278
281279
$\square$
@@ -296,17 +294,17 @@ solution requires defining a new kind of pairs, but this is not the only way.)
296294
> alternate : (l1, l2 : NatList) -> NatList
297295
> alternate l1 l2 = ?alternate_rhs
298296
299-
> test_alternate1 : alternate (1::2::3::[]) (4::5::6::[]) =
300-
> (1::4::2::5::3::6::[])
297+
> test_alternate1 : alternate [1,2,3] [4,5,6] =
298+
> [1,4,2,5,3,6]
301299
> test_alternate1 = ?test_alternate1_rhs
302300
303-
> test_alternate2 : alternate (1::[]) (4::5::6::[]) = (1::4::5::6::[])
301+
> test_alternate2 : alternate [1] [4,5,6] = [1,4,5,6]
304302
> test_alternate2 = ?test_alternate2_rhs
305303
306-
> test_alternate3 : alternate (1::2::3::[]) (4::[]) = (1::4::2::3::[])
304+
> test_alternate3 : alternate [1,2,3] [4] = [1,4,2,3]
307305
> test_alternate3 = ?test_alternate3_rhs
308306
309-
> test_alternate4 : alternate [] (20::30::[]) = (20::30::[])
307+
> test_alternate4 : alternate [] [20,30] = [20,30]
310308
> test_alternate4 = ?test_alternate4_rhs
311309
312310
$\square$
@@ -332,10 +330,10 @@ Complete the following definitions for the functions \idr{count}, \idr{sum},
332330
333331
All these proofs can be done just by \idr{Refl}.
334332
335-
> test_count1 : count 1 (1::2::3::1::4::1::[]) = 3
333+
> test_count1 : count 1 [1,2,3,1,4,1] = 3
336334
> test_count1 = ?test_count1_rhs
337335
338-
> test_count2 : count 6 (1::2::3::1::4::1::[]) = 0
336+
> test_count2 : count 6 [1,2,3,1,4,1] = 0
339337
> test_count2 = ?test_count2_rhs
340338
341339
Multiset \idr{sum} is similar to set \idr{union}: \idr{sum a b} contains all the
@@ -355,25 +353,25 @@ functions that have already been defined.
355353
> sum : Bag -> Bag -> Bag
356354
> sum x y = ?sum_rhs
357355
358-
> test_sum1 : count 1 (sum (1::2::3::[]) (1::4::1::[])) = 3
356+
> test_sum1 : count 1 (sum [1,2,3] [1,4,1]) = 3
359357
> test_sum1 = ?test_sum1_rhs
360358
361359
> add : (v : Nat) -> (s : Bag) -> Bag
362360
> add v s = ?add_rhs
363361
364-
> test_add1 : count 1 (add 1 (1::4::1::[])) = 3
362+
> test_add1 : count 1 (add 1 [1,4,1]) = 3
365363
> test_add1 = ?test_add1_rhs
366364
367-
> test_add2 : count 5 (add 1 (1::4::1::[])) = 0
365+
> test_add2 : count 5 (add 1 [1,4,1]) = 0
368366
> test_add2 = ?test_add2_rhs
369367
370368
> member : (v : Nat) -> (s : Bag) -> Bool
371369
> member v s = ?member_rhs
372370
373-
> test_member1 : member 1 (1::4::1::[]) = True
371+
> test_member1 : member 1 [1,4,1] = True
374372
> test_member1 = ?test_member1_rhs
375373
376-
> test_member2 : member 2 (1::4::1::[]) = False
374+
> test_member2 : member 2 [1,4,1] = False
377375
> test_member2 = ?test_member2_rhs
378376
379377
$\square$
@@ -389,41 +387,41 @@ should return the same bag unchanged.
389387
> remove_one : (v : Nat) -> (s : Bag) -> Bag
390388
> remove_one v s = ?remove_one_rhs
391389
392-
> test_remove_one1 : count 5 (remove_one 5 (2::1::5::4::1::[])) = 0
390+
> test_remove_one1 : count 5 (remove_one 5 [2,1,5,4,1]) = 0
393391
> test_remove_one1 = ?test_remove_one1_rhs
394392
395-
> test_remove_one2 : count 5 (remove_one 5 (2::1::4::1::[])) = 0
393+
> test_remove_one2 : count 5 (remove_one 5 [2,1,4,1]) = 0
396394
> test_remove_one2 = ?test_remove_one2_rhs
397395
398-
> test_remove_one3 : count 4 (remove_one 5 (2::1::5::4::1::4::[])) = 2
396+
> test_remove_one3 : count 4 (remove_one 5 [2,1,5,4,1,4]) = 2
399397
> test_remove_one3 = ?test_remove_one3_rhs
400398
401-
> test_remove_one4 : count 5 (remove_one 5 (2::1::5::4::5::1::4::[])) = 1
399+
> test_remove_one4 : count 5 (remove_one 5 [2,1,5,4,5,1,4]) = 1
402400
> test_remove_one4 = ?test_remove_one4_rhs
403401
404402
> remove_all : (v : Nat) -> (s : Bag) -> Bag
405403
> remove_all v s = ?remove_all_rhs
406404
407-
> test_remove_all1 : count 5 (remove_all 5 (2::1::5::4::1::[])) = 0
405+
> test_remove_all1 : count 5 (remove_all 5 [2,1,5,4,1]) = 0
408406
> test_remove_all1 = ?test_remove_all1_rhs
409407
410-
> test_remove_all2 : count 5 (remove_all 5 (2::1::4::1::[])) = 0
408+
> test_remove_all2 : count 5 (remove_all 5 [2,1,4,1]) = 0
411409
> test_remove_all2 = ?test_remove_all2_rhs
412410
413-
> test_remove_all3 : count 4 (remove_all 5 (2::1::5::4::1::4::[])) = 2
411+
> test_remove_all3 : count 4 (remove_all 5 [2,1,5,4,1,4]) = 2
414412
> test_remove_all3 = ?test_remove_all3_rhs
415413
416414
> test_remove_all4 : count 5
417-
> (remove_all 5 (2::1::5::4::5::1::4::5::1::4::[])) = 0
415+
> (remove_all 5 [2,1,5,4,5,1,4,5,1,4]) = 0
418416
> test_remove_all4 = ?test_remove_all4_rhs
419417
420418
> subset : (s1 : Bag) -> (s2 : Bag) -> Bool
421419
> subset s1 s2 = ?subset_rhs
422420
423-
> test_subset1 : subset (1::2::[]) (2::1::4::1::[]) = True
421+
> test_subset1 : subset [1,2] [2,1,4,1] = True
424422
> test_subset1 = ?test_subset1_rhs
425423
426-
> test_subset2 : subset (1::2::2::[]) (2::1::4::1::[]) = False
424+
> test_subset2 : subset [1,2,2] [2,1,4,1] = False
427425
> test_subset2 = ?test_subset2_rhs
428426
429427
$\square$
@@ -459,8 +457,8 @@ Also, as with numbers, it is sometimes helpful to perform case analysis on the
459457
possible shapes (empty or non-empty) of an unknown list.
460458
461459
> tl_length_pred : (l : NatList) -> pred (length l) = length (tl l)
462-
> tl_length_pred Nil = Refl
463-
> tl_length_pred (Cons n l') = Refl
460+
> tl_length_pred [] = Refl
461+
> tl_length_pred (n::l') = Refl
464462
465463
Here, the \idr{Nil} case works because we've chosen to define \idr{tl Nil =
466464
Nil}. Notice that the case for \idr{Cons} introduces two names, \idr{n} and
@@ -508,8 +506,8 @@ Since larger lists can only be built up from smaller ones, eventually reaching
508506
lists \idr{l}. Here's a concrete example:
509507
510508
> app_assoc : (l1, l2, l3 : NatList) -> ((l1 ++ l2) ++ l3) = (l1 ++ (l2 ++ l3))
511-
> app_assoc Nil l2 l3 = Refl
512-
> app_assoc (Cons n l1') l2 l3 =
509+
> app_assoc [] l2 l3 = Refl
510+
> app_assoc (n::l1') l2 l3 =
513511
> let inductiveHypothesis = app_assoc l1' l2 l3 in
514512
> rewrite inductiveHypothesis in Refl
515513
@@ -562,9 +560,9 @@ use \idr{app} to define a list-reversing function \idr{rev}:
562560
563561
> rev : (l : NatList) -> NatList
564562
> rev Nil = Nil
565-
> rev (h :: t) = (rev t) ++ (h::[])
563+
> rev (h :: t) = (rev t) ++ [h]
566564
567-
> test_rev1 : rev (1::2::3::[]) = (3::2::1::[])
565+
> test_rev1 : rev [1,2,3] = [3,2,1]
568566
> test_rev1 = Refl
569567
570568
> test_rev2 : rev Nil = Nil
@@ -614,7 +612,7 @@ Now we can complete the original proof.
614612
> rev_length : (l : NatList) -> length (rev l) = length l
615613
> rev_length Nil = Refl
616614
> rev_length (n :: l') =
617-
> rewrite app_length (rev l') (n::[]) in
615+
> rewrite app_length (rev l') [n] in
618616
> -- Prelude's version of `Induction.plus_comm`
619617
> rewrite plusCommutative (length (rev l')) 1 in
620618
> let inductiveHypothesis = rev_length l' in
@@ -762,10 +760,10 @@ equality. Prove that \idr{beq_NatList l l} yields \idr{True} for every list
762760
> test_beq_NatList1 : beq_NatList Nil Nil = True
763761
> test_beq_NatList1 = ?test_beq_NatList1_rhs
764762
765-
> test_beq_NatList2 : beq_NatList (1::2::3::[]) (1::2::3::[]) = True
763+
> test_beq_NatList2 : beq_NatList [1,2,3] [1,2,3] = True
766764
> test_beq_NatList2 = ?test_beq_NatList2_rhs
767765
768-
> test_beq_NatList3 : beq_NatList (1::2::3::[]) (1::2::4::[]) = False
766+
> test_beq_NatList3 : beq_NatList [1,2,3] [1,2,4] = False
769767
> test_beq_NatList3 = ?test_beq_NatList3_rhs
770768
771769
> beq_NatList_refl : (l : NatList) -> True = beq_NatList l l
@@ -855,13 +853,13 @@ to indicate that it may result in an error.
855853
> True => Some a
856854
> False => nth_error l' (pred n)
857855
858-
> test_nth_error1 : nth_error (4::5::6::7::[]) 0 = Some 4
856+
> test_nth_error1 : nth_error [4,5,6,7] 0 = Some 4
859857
> test_nth_error1 = Refl
860858
861-
> test_nth_error2 : nth_error (4::5::6::7::[]) 3 = Some 7
859+
> test_nth_error2 : nth_error [4,5,6,7] 3 = Some 7
862860
> test_nth_error2 = Refl
863861
864-
> test_nth_error3 : nth_error (4::5::6::7::[]) 9 = None
862+
> test_nth_error3 : nth_error [4,5,6,7] 9 = None
865863
> test_nth_error3 = Refl
866864
867865
This example is also an opportunity to introduce one more small feature of Idris
@@ -900,10 +898,10 @@ pass a default element for the \idr{Nil} case.
900898
> test_hd_error1 : hd_error [] = None
901899
> test_hd_error1 = ?test_hd_error1_rhs
902900
903-
> test_hd_error2 : hd_error (1::[]) = Some 1
901+
> test_hd_error2 : hd_error [1] = Some 1
904902
> test_hd_error2 = ?test_hd_error2_rhs
905903
906-
> test_hd_error3 : hd_error (5::6::[]) = Some 5
904+
> test_hd_error3 : hd_error [5,6] = Some 5
907905
> test_hd_error3 = ?test_hd_error3_rhs
908906
909907
$\square$

0 commit comments

Comments
 (0)