Skip to content

Commit fa3f398

Browse files
Added boolean versions of List/Vec functions that use predicates (#1714)
1 parent dcd3666 commit fa3f398

File tree

7 files changed

+204
-137
lines changed

7 files changed

+204
-137
lines changed

CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,6 +1019,20 @@ Other minor changes
10191019
^-monoid-morphism : IsMonoidMorphism ℕ.+-0-monoid *-1-monoid (i ^_)
10201020
```
10211021

1022+
* Added new functions in `Data.List`:
1023+
```agda
1024+
takeWhileᵇ : (A → Bool) → List A → List A
1025+
dropWhileᵇ : (A → Bool) → List A → List A
1026+
filterᵇ : (A → Bool) → List A → List A
1027+
partitionᵇ : (A → Bool) → List A → List A × List A
1028+
spanᵇ : (A → Bool) → List A → List A × List A
1029+
breakᵇ : (A → Bool) → List A → List A × List A
1030+
linesByᵇ : (A → Bool) → List A → List (List A)
1031+
wordsByᵇ : (A → Bool) → List A → List (List A)
1032+
derunᵇ : (A → A → Bool) → List A → List A
1033+
deduplicateᵇ : (A → A → Bool) → List A → List A
1034+
```
1035+
10221036
* Added new proofs in `Data.List.Relation.Binary.Lex.Strict`:
10231037
```agda
10241038
xs≮[] : ¬ xs < []
@@ -1174,6 +1188,12 @@ Other minor changes
11741188
*-abelianGroup : AbelianGroup 0ℓ 0ℓ
11751189
```
11761190

1191+
* Added new functions in `Data.String.Base`:
1192+
```agda
1193+
wordsByᵇ : (Char → Bool) → String → List String
1194+
linesByᵇ : (Char → Bool) → String → List String
1195+
```
1196+
11771197
* Added new proofs in `Data.String.Properties`:
11781198
```
11791199
≤-isDecTotalOrder-≈ : IsDecTotalOrder _≈_ _≤_
@@ -1198,6 +1218,7 @@ Other minor changes
11981218
11991219
foldr′ : (A → B → B) → B → Vec A n → B
12001220
foldl′ : (B → A → B) → B → Vec A n → B
1221+
countᵇ : (A → Bool) → Vec A n → ℕ
12011222
12021223
iterate : (A → A) → A → Vec A n
12031224

src/Data/List/Base.agda

Lines changed: 141 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ open import Data.Bool.Base as Bool
1616
open import Data.Fin.Base using (Fin; zero; suc)
1717
open import Data.Maybe.Base as Maybe using (Maybe; nothing; just; maybe′)
1818
open import Data.Nat.Base as ℕ using (ℕ; zero; suc; _+_; _*_ ; _≤_ ; s≤s)
19-
open import Data.Product as Prod using (_×_; _,_)
19+
open import Data.Product as Prod using (_×_; _,_; map₁; map₂′)
2020
open import Data.Sum.Base as Sum using (_⊎_; inj₁; inj₂)
2121
open import Data.These.Base as These using (These; this; that; these)
22-
open import Function.Base using (id; _∘_ ; _∘′_; const; flip)
22+
open import Function.Base using (id; _∘_ ; _∘′_; _∘₂_; const; flip)
2323
open import Level using (Level)
2424
open import Relation.Nullary using (does)
2525
open import Relation.Nullary.Negation.Core using (¬?)
@@ -52,7 +52,7 @@ mapMaybe : (A → Maybe B) → List A → List B
5252
mapMaybe p [] = []
5353
mapMaybe p (x ∷ xs) with p x
5454
... | just y = y ∷ mapMaybe p xs
55-
... | nothing = mapMaybe p xs
55+
... | nothing = mapMaybe p xs
5656

5757
infixr 5 _++_
5858

@@ -238,6 +238,51 @@ unfold P f {n = suc n} s with f s
238238
... | nothing = []
239239
... | just (x , s′) = x ∷ unfold P f s′
240240

241+
------------------------------------------------------------------------
242+
-- Operations for reversing lists
243+
244+
reverseAcc : List A List A List A
245+
reverseAcc = foldl (flip _∷_)
246+
247+
reverse : List A List A
248+
reverse = reverseAcc []
249+
250+
-- "Reverse append" xs ʳ++ ys = reverse xs ++ ys
251+
252+
infixr 5 _ʳ++_
253+
254+
_ʳ++_ : List A List A List A
255+
_ʳ++_ = flip reverseAcc
256+
257+
-- Snoc: Cons, but from the right.
258+
259+
infixl 6 _∷ʳ_
260+
261+
_∷ʳ_ : List A A List A
262+
xs ∷ʳ x = xs ++ [ x ]
263+
264+
265+
266+
-- Backwards initialisation
267+
268+
infixl 5 _∷ʳ′_
269+
270+
data InitLast {A : Set a} : List A Set a where
271+
[] : InitLast []
272+
_∷ʳ′_ : (xs : List A) (x : A) InitLast (xs ∷ʳ x)
273+
274+
initLast : (xs : List A) InitLast xs
275+
initLast [] = []
276+
initLast (x ∷ xs) with initLast xs
277+
... | [] = [] ∷ʳ′ x
278+
... | ys ∷ʳ′ y = (x ∷ ys) ∷ʳ′ y
279+
280+
-- uncons, but from the right
281+
unsnoc : List A Maybe (List A × A)
282+
unsnoc as with initLast as
283+
... | [] = nothing
284+
... | xs ∷ʳ′ x = just (xs , x)
285+
241286
------------------------------------------------------------------------
242287
-- Operations for deconstructing lists
243288

@@ -273,55 +318,117 @@ drop zero xs = xs
273318
drop (suc n) [] = []
274319
drop (suc n) (x ∷ xs) = drop n xs
275320

276-
splitAt : List A (List A × List A)
321+
splitAt : List A List A × List A
277322
splitAt zero xs = ([] , xs)
278323
splitAt (suc n) [] = ([] , [])
279-
splitAt (suc n) (x ∷ xs) with splitAt n xs
280-
... | (ys , zs) = (x ∷ ys , zs)
324+
splitAt (suc n) (x ∷ xs) = Prod.map₁ (x ∷_) (splitAt n xs)
325+
326+
-- The following are functions which split a list up using boolean
327+
-- predicates. However, in practice they are difficult to use and
328+
-- prove properties about, and are mainly provided for advanced use
329+
-- cases where one wants to minimise dependencies. In most cases
330+
-- you probably want to use the versions defined below based on
331+
-- decidable predicates. e.g. use `takeWhile (_≤? 10) xs`
332+
-- instead of `takeWhileᵇ (_≤ᵇ 10) xs`
333+
334+
takeWhileᵇ : (A Bool) List A List A
335+
takeWhileᵇ p [] = []
336+
takeWhileᵇ p (x ∷ xs) = if p x then x ∷ takeWhileᵇ p xs else []
337+
338+
dropWhileᵇ : (A Bool) List A List A
339+
dropWhileᵇ p [] = []
340+
dropWhileᵇ p (x ∷ xs) = if p x then dropWhileᵇ p xs else x ∷ xs
341+
342+
filterᵇ : (A Bool) List A List A
343+
filterᵇ p [] = []
344+
filterᵇ p (x ∷ xs) = if p x then x ∷ filterᵇ p xs else filterᵇ p xs
345+
346+
partitionᵇ : (A Bool) List A List A × List A
347+
partitionᵇ p [] = ([] , [])
348+
partitionᵇ p (x ∷ xs) = (if p x then Prod.map₁ else Prod.map₂′) (x ∷_) (partitionᵇ p xs)
349+
350+
spanᵇ : (A Bool) List A List A × List A
351+
spanᵇ p [] = ([] , [])
352+
spanᵇ p (x ∷ xs) = if p x
353+
then Prod.map₁ (x ∷_) (spanᵇ p xs)
354+
else ([] , x ∷ xs)
355+
356+
breakᵇ : (A Bool) List A List A × List A
357+
breakᵇ p = spanᵇ (not ∘ p)
358+
359+
linesByᵇ : (A Bool) List A List (List A)
360+
linesByᵇ {A = A} p = go nothing
361+
where
362+
go : Maybe (List A) List A List (List A)
363+
go acc [] = maybe′ ([_] ∘′ reverse) [] acc
364+
go acc (c ∷ cs) with p c
365+
... | true = reverse (Maybe.fromMaybe [] acc) ∷ go nothing cs
366+
... | false = go (just (c ∷ Maybe.fromMaybe [] acc)) cs
367+
368+
wordsByᵇ : (A Bool) List A List (List A)
369+
wordsByᵇ {A = A} p = go []
370+
where
371+
cons : List A List (List A) List (List A)
372+
cons [] ass = ass
373+
cons as ass = reverse as ∷ ass
374+
375+
go : List A List A List (List A)
376+
go acc [] = cons acc []
377+
go acc (c ∷ cs) with p c
378+
... | true = cons acc (go [] cs)
379+
... | false = go (c ∷ acc) cs
380+
381+
derunᵇ : (A A Bool) List A List A
382+
derunᵇ r [] = []
383+
derunᵇ r (x ∷ []) = x ∷ []
384+
derunᵇ r (x ∷ y ∷ xs) = if r x y
385+
then derunᵇ r (y ∷ xs)
386+
else x ∷ derunᵇ r (y ∷ xs)
387+
388+
deduplicateᵇ : (A A Bool) List A List A
389+
deduplicateᵇ r [] = []
390+
deduplicateᵇ r (x ∷ xs) = x ∷ filterᵇ (not ∘ r x) (deduplicateᵇ r xs)
391+
392+
-- Equivalent functions that use a decidable predicate instead of a
393+
-- boolean function.
281394

282395
takeWhile : {P : Pred A p} Decidable P List A List A
283-
takeWhile P? [] = []
284-
takeWhile P? (x ∷ xs) with does (P? x)
285-
... | true = x ∷ takeWhile P? xs
286-
... | false = []
396+
takeWhile P? = takeWhileᵇ (does ∘ P?)
287397

288398
dropWhile : {P : Pred A p} Decidable P List A List A
289-
dropWhile P? [] = []
290-
dropWhile P? (x ∷ xs) with does (P? x)
291-
... | true = dropWhile P? xs
292-
... | false = x ∷ xs
399+
dropWhile P? = dropWhileᵇ (does ∘ P?)
293400

294401
filter : {P : Pred A p} Decidable P List A List A
295-
filter P? [] = []
296-
filter P? (x ∷ xs) with does (P? x)
297-
... | false = filter P? xs
298-
... | true = x ∷ filter P? xs
402+
filter P? = filterᵇ (does ∘ P?)
299403

300404
partition : {P : Pred A p} Decidable P List A (List A × List A)
301-
partition P? [] = ([] , [])
302-
partition P? (x ∷ xs) with does (P? x) | partition P? xs
303-
... | true | (ys , zs) = (x ∷ ys , zs)
304-
... | false | (ys , zs) = (ys , x ∷ zs)
405+
partition P? = partitionᵇ (does ∘ P?)
305406

306407
span : {P : Pred A p} Decidable P List A (List A × List A)
307-
span P? [] = ([] , [])
308-
span P? (x ∷ xs) with does (P? x)
309-
... | true = Prod.map (x ∷_) id (span P? xs)
310-
... | false = ([] , x ∷ xs)
408+
span P? = spanᵇ (does ∘ P?)
311409

312410
break : {P : Pred A p} Decidable P List A (List A × List A)
313-
break P? = span (∁? P?)
411+
break P? = breakᵇ (does ∘ P?)
412+
413+
-- The predicate `P` represents the notion of newline character for the
414+
-- type `A`. It is used to split the input list into a list of lines.
415+
-- Some lines may be empty if the input contains at least two
416+
-- consecutive newline characters.
417+
linesBy : {P : Pred A p} Decidable P List A List (List A)
418+
linesBy P? = linesByᵇ (does ∘ P?)
419+
420+
-- The predicate `P` represents the notion of space character for the
421+
-- type `A`. It is used to split the input list into a list of words.
422+
-- All the words are non empty and the output does not contain any space
423+
-- characters.
424+
wordsBy : {P : Pred A p} Decidable P List A List (List A)
425+
wordsBy P? = wordsByᵇ (does ∘ P?)
314426

315427
derun : {R : Rel A p} B.Decidable R List A List A
316-
derun R? [] = []
317-
derun R? (x ∷ []) = x ∷ []
318-
derun R? (x ∷ y ∷ xs) with does (R? x y) | derun R? (y ∷ xs)
319-
... | true | ys = ys
320-
... | false | ys = x ∷ ys
428+
derun R? = derunᵇ (does ∘₂ R?)
321429

322430
deduplicate : {R : Rel A p} B.Decidable R List A List A
323-
deduplicate R? [] = []
324-
deduplicate R? (x ∷ xs) = x ∷ filter (¬? ∘ R? x) (deduplicate R? xs)
431+
deduplicate R? = deduplicateᵇ (does ∘₂ R?)
325432

326433
------------------------------------------------------------------------
327434
-- Actions on single elements
@@ -340,28 +447,6 @@ _─_ : (xs : List A) → Fin (length xs) → List A
340447
(x ∷ xs) ─ suc k = x ∷ (xs ─ k)
341448

342449
------------------------------------------------------------------------
343-
-- Operations for reversing lists
344-
345-
reverseAcc : List A List A List A
346-
reverseAcc = foldl (flip _∷_)
347-
348-
reverse : List A List A
349-
reverse = reverseAcc []
350-
351-
-- "Reverse append" xs ʳ++ ys = reverse xs ++ ys
352-
353-
infixr 5 _ʳ++_
354-
355-
_ʳ++_ : List A List A List A
356-
_ʳ++_ = flip reverseAcc
357-
358-
-- Snoc: Cons, but from the right.
359-
360-
infixl 6 _∷ʳ_
361-
362-
_∷ʳ_ : List A A List A
363-
xs ∷ʳ x = xs ++ [ x ]
364-
365450
-- Conditional versions of cons and snoc
366451

367452
infixr 5 _?∷_
@@ -373,59 +458,6 @@ _∷ʳ?_ : List A → Maybe A → List A
373458
xs ∷ʳ? x = maybe′ (xs ∷ʳ_) xs x
374459

375460

376-
-- Backwards initialisation
377-
378-
infixl 5 _∷ʳ′_
379-
380-
data InitLast {A : Set a} : List A Set a where
381-
[] : InitLast []
382-
_∷ʳ′_ : (xs : List A) (x : A) InitLast (xs ∷ʳ x)
383-
384-
initLast : (xs : List A) InitLast xs
385-
initLast [] = []
386-
initLast (x ∷ xs) with initLast xs
387-
... | [] = [] ∷ʳ′ x
388-
... | ys ∷ʳ′ y = (x ∷ ys) ∷ʳ′ y
389-
390-
-- uncons, but from the right
391-
unsnoc : List A Maybe (List A × A)
392-
unsnoc as with initLast as
393-
... | [] = nothing
394-
... | xs ∷ʳ′ x = just (xs , x)
395-
396-
------------------------------------------------------------------------
397-
-- Splitting a list
398-
399-
-- The predicate `P` represents the notion of newline character for the type `A`
400-
-- It is used to split the input list into a list of lines. Some lines may be
401-
-- empty if the input contains at least two consecutive newline characters.
402-
403-
linesBy : {P : Pred A p} Decidable P List A List (List A)
404-
linesBy {A = A} P? = go nothing where
405-
406-
go : Maybe (List A) List A List (List A)
407-
go acc [] = maybe′ ([_] ∘′ reverse) [] acc
408-
go acc (c ∷ cs) with does (P? c)
409-
... | true = reverse (Maybe.fromMaybe [] acc) ∷ go nothing cs
410-
... | false = go (just (c ∷ Maybe.fromMaybe [] acc)) cs
411-
412-
-- The predicate `P` represents the notion of space character for the type `A`.
413-
-- It is used to split the input list into a list of words. All the words are
414-
-- non empty and the output does not contain any space characters.
415-
416-
wordsBy : {P : Pred A p} Decidable P List A List (List A)
417-
wordsBy {A = A} P? = go [] where
418-
419-
cons : List A List (List A) List (List A)
420-
cons [] ass = ass
421-
cons as ass = reverse as ∷ ass
422-
423-
go : List A List A List (List A)
424-
go acc [] = cons acc []
425-
go acc (c ∷ cs) with does (P? c)
426-
... | true = cons acc (go [] cs)
427-
... | false = go (c ∷ acc) cs
428-
429461
------------------------------------------------------------------------
430462
-- DEPRECATED
431463
------------------------------------------------------------------------

src/Data/List/Relation/Unary/Unique/DecSetoid/Properties.agda

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ open import Data.List.Relation.Unary.All.Properties using (all-filter)
1212
open import Data.List.Relation.Unary.Unique.Setoid.Properties
1313
open import Level
1414
open import Relation.Binary using (DecSetoid)
15+
open import Relation.Nullary.Negation using (¬?)
1516

1617
module Data.List.Relation.Unary.Unique.DecSetoid.Properties where
1718

@@ -29,4 +30,5 @@ module _ (DS : DecSetoid a ℓ) where
2930

3031
deduplicate-! : xs Unique (deduplicate _≟_ xs)
3132
deduplicate-! [] = []
32-
deduplicate-! (x ∷ xs) = all-filter _ (deduplicate _ xs) ∷ filter⁺ S _ (deduplicate-! xs)
33+
deduplicate-! (x ∷ xs) = all-filter (λ y ¬? (x ≟ y)) (deduplicate _≟_ xs)
34+
∷ filter⁺ S (λ y ¬? (x ≟ y)) (deduplicate-! xs)

src/Data/Product.agda

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,9 @@ curry′ = curry
177177
uncurry′ : (A B C) (A × B C)
178178
uncurry′ = uncurry
179179

180+
map₂′ : (B C) A × B A × C
181+
map₂′ f = map₂ f
182+
180183
dmap′ : {x y} {X : A Set x} {Y : B Set y}
181184
((a : A) X a) ((b : B) Y b)
182185
((a , b) : A × B) X a × Y b

0 commit comments

Comments
 (0)