Skip to content

Commit 9be7cea

Browse files
MatthewDaggittjamesmckinna
authored andcommitted
Make decidable versions of sublist functions the default (agda#2186)
* Make decdable versions of sublist functions the default * Remove imports Bool.Properties * Address comments
1 parent 200ef72 commit 9be7cea

File tree

4 files changed

+133
-114
lines changed

4 files changed

+133
-114
lines changed

src/Data/List/Base.agda

+114-95
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ open import Data.These.Base as These using (These; this; that; these)
2323
open import Function.Base
2424
using (id; _∘_ ; _∘′_; _∘₂_; _$_; const; flip)
2525
open import Level using (Level)
26-
open import Relation.Nullary.Decidable.Core using (does; ¬?)
2726
open import Relation.Unary using (Pred; Decidable)
2827
open import Relation.Binary.Core using (Rel)
2928
import Relation.Binary.Definitions as B
3029
open import Relation.Binary.PropositionalEquality.Core using (_≡_)
30+
open import Relation.Nullary.Decidable.Core using (T?; does; ¬?)
3131

3232
private
3333
variable
@@ -346,141 +346,160 @@ removeAt : (xs : List A) → Fin (length xs) → List A
346346
removeAt (x ∷ xs) zero = xs
347347
removeAt (x ∷ xs) (suc i) = x ∷ removeAt xs i
348348

349-
-- The following are functions which split a list up using boolean
350-
-- predicates. However, in practice they are difficult to use and
351-
-- prove properties about, and are mainly provided for advanced use
352-
-- cases where one wants to minimise dependencies. In most cases
353-
-- you probably want to use the versions defined below based on
354-
-- decidable predicates. e.g. use `takeWhile (_≤? 10) xs`
355-
-- instead of `takeWhileᵇ (_≤ᵇ 10) xs`
349+
------------------------------------------------------------------------
350+
-- Operations for filtering lists
351+
352+
-- The following are a variety of functions that can be used to
353+
-- construct sublists using a predicate.
354+
--
355+
-- Each function has two forms. The first main variant uses a
356+
-- proof-relevant decidable predicate, while the second variant uses
357+
-- a irrelevant boolean predicate and are suffixed with a `ᵇ` character,
358+
-- typed as \^b.
359+
--
360+
-- The decidable versions have several advantages: 1) easier to prove
361+
-- properties, 2) better meta-variable inference and 3) most of the rest
362+
-- of the library is set-up to work with decidable predicates. However,
363+
-- in rare cases the boolean versions can be useful, mainly when one
364+
-- wants to minimise dependencies.
365+
--
366+
-- In summary, in most cases you probably want to use the decidable
367+
-- versions over the boolean versions, e.g. use `takeWhile (_≤? 10) xs`
368+
-- rather than `takeWhileᵇ (_≤ᵇ 10) xs`.
369+
370+
takeWhile : {P : Pred A p} Decidable P List A List A
371+
takeWhile P? [] = []
372+
takeWhile P? (x ∷ xs) with does (P? x)
373+
... | true = x ∷ takeWhile P? xs
374+
... | false = []
356375

357376
takeWhileᵇ : (A Bool) List A List A
358-
takeWhileᵇ p [] = []
359-
takeWhileᵇ p (x ∷ xs) = if p x then x ∷ takeWhileᵇ p xs else []
377+
takeWhileᵇ p = takeWhile (T? ∘ p)
378+
379+
dropWhile : {P : Pred A p} Decidable P List A List A
380+
dropWhile P? [] = []
381+
dropWhile P? (x ∷ xs) with does (P? x)
382+
... | true = dropWhile P? xs
383+
... | false = x ∷ xs
360384

361385
dropWhileᵇ : (A Bool) List A List A
362-
dropWhileᵇ p [] = []
363-
dropWhileᵇ p (x ∷ xs) = if p x then dropWhileᵇ p xs else x ∷ xs
386+
dropWhileᵇ p = dropWhile (T? ∘ p)
387+
388+
filter : {P : Pred A p} Decidable P List A List A
389+
filter P? [] = []
390+
filter P? (x ∷ xs) with does (P? x)
391+
... | false = filter P? xs
392+
... | true = x ∷ filter P? xs
364393

365394
filterᵇ : (A Bool) List A List A
366-
filterᵇ p [] = []
367-
filterᵇ p (x ∷ xs) = if p x then x ∷ filterᵇ p xs else filterᵇ p xs
395+
filterᵇ p = filter (T? ∘ p)
396+
397+
partition : {P : Pred A p} Decidable P List A (List A × List A)
398+
partition P? [] = ([] , [])
399+
partition P? (x ∷ xs) with does (P? x) | partition P? xs
400+
... | true | (ys , zs) = (x ∷ ys , zs)
401+
... | false | (ys , zs) = (ys , x ∷ zs)
368402

369403
partitionᵇ : (A Bool) List A List A × List A
370-
partitionᵇ p [] = ([] , [])
371-
partitionᵇ p (x ∷ xs) = (if p x then Prod.map₁ else Prod.map₂′) (x ∷_) (partitionᵇ p xs)
404+
partitionᵇ p = partition (T? ∘ p)
405+
406+
span : {P : Pred A p} Decidable P List A (List A × List A)
407+
span P? [] = ([] , [])
408+
span P? ys@(x ∷ xs) with does (P? x)
409+
... | true = Prod.map (x ∷_) id (span P? xs)
410+
... | false = ([] , ys)
411+
372412

373413
spanᵇ : (A Bool) List A List A × List A
374-
spanᵇ p [] = ([] , [])
375-
spanᵇ p (x ∷ xs) = if p x
376-
then Prod.map₁ (x ∷_) (spanᵇ p xs)
377-
else ([] , x ∷ xs)
414+
spanᵇ p = span (T? ∘ p)
415+
416+
break : {P : Pred A p} Decidable P List A (List A × List A)
417+
break P? = span (¬? ∘ P?)
378418

379419
breakᵇ : (A Bool) List A List A × List A
380-
breakᵇ p = spanᵇ (not ∘ p)
420+
breakᵇ p = break (T? ∘ p)
421+
422+
-- The predicate `P` represents the notion of newline character for the
423+
-- type `A`. It is used to split the input list into a list of lines.
424+
-- Some lines may be empty if the input contains at least two
425+
-- consecutive newline characters.
426+
linesBy : {P : Pred A p} Decidable P List A List (List A)
427+
linesBy {A = A} P? = go nothing where
381428

382-
linesByᵇ : (A Bool) List A List (List A)
383-
linesByᵇ {A = A} p = go nothing
384-
where
385429
go : Maybe (List A) List A List (List A)
386430
go acc [] = maybe′ ([_] ∘′ reverse) [] acc
387-
go acc (c ∷ cs) with p c
431+
go acc (c ∷ cs) with does (P? c)
388432
... | true = reverse (Maybe.fromMaybe [] acc) ∷ go nothing cs
389433
... | false = go (just (c ∷ Maybe.fromMaybe [] acc)) cs
390434

391-
wordsByᵇ : (A Bool) List A List (List A)
392-
wordsByᵇ {A = A} p = go []
393-
where
435+
linesByᵇ : (A Bool) List A List (List A)
436+
linesByᵇ p = linesBy (T? ∘ p)
437+
438+
-- The predicate `P` represents the notion of space character for the
439+
-- type `A`. It is used to split the input list into a list of words.
440+
-- All the words are non empty and the output does not contain any space
441+
-- characters.
442+
wordsBy : {P : Pred A p} Decidable P List A List (List A)
443+
wordsBy {A = A} P? = go [] where
444+
394445
cons : List A List (List A) List (List A)
395446
cons [] ass = ass
396447
cons as ass = reverse as ∷ ass
397448

398449
go : List A List A List (List A)
399450
go acc [] = cons acc []
400-
go acc (c ∷ cs) with p c
451+
go acc (c ∷ cs) with does (P? c)
401452
... | true = cons acc (go [] cs)
402453
... | false = go (c ∷ acc) cs
403454

455+
wordsByᵇ : (A Bool) List A List (List A)
456+
wordsByᵇ p = wordsBy (T? ∘ p)
457+
458+
derun : {R : Rel A p} B.Decidable R List A List A
459+
derun R? [] = []
460+
derun R? (x ∷ []) = x ∷ []
461+
derun R? (x ∷ xs@(y ∷ _)) with does (R? x y) | derun R? xs
462+
... | true | ys = ys
463+
... | false | ys = x ∷ ys
464+
404465
derunᵇ : (A A Bool) List A List A
405-
derunᵇ r [] = []
406-
derunᵇ r (x ∷ []) = x ∷ []
407-
derunᵇ r (x ∷ y ∷ xs) = if r x y
408-
then derunᵇ r (y ∷ xs)
409-
else x ∷ derunᵇ r (y ∷ xs)
466+
derunᵇ r = derun (T? ∘₂ r)
467+
468+
deduplicate : {R : Rel A p} B.Decidable R List A List A
469+
deduplicate R? [] = []
470+
deduplicate R? (x ∷ xs) = x ∷ filter (¬? ∘ R? x) (deduplicate R? xs)
410471

411472
deduplicateᵇ : (A A Bool) List A List A
412-
deduplicateᵇ r [] = []
413-
deduplicateᵇ r (x ∷ xs) = x ∷ filterᵇ (not ∘ r x) (deduplicateᵇ r xs)
473+
deduplicateᵇ r = deduplicate (T? ∘₂ r)
414474

415475
-- Finds the first element satisfying the boolean predicate
476+
find : {P : Pred A p} Decidable P List A Maybe A
477+
find P? [] = nothing
478+
find P? (x ∷ xs) = if does (P? x) then just x else find P? xs
479+
416480
findᵇ : (A Bool) List A Maybe A
417-
findᵇ p [] = nothing
418-
findᵇ p (x ∷ xs) = if p x then just x else findᵇ p xs
481+
findᵇ p = find (T? ∘ p)
419482

420483
-- Finds the index of the first element satisfying the boolean predicate
421-
findIndexᵇ : (A Bool) (xs : List A) Maybe $ Fin (length xs)
422-
findIndexᵇ p [] = nothing
423-
findIndexᵇ p (x ∷ xs) = if p x
484+
findIndex : {P : Pred A p} Decidable P (xs : List A) Maybe $ Fin (length xs)
485+
findIndex P? [] = nothing
486+
findIndex P? (x ∷ xs) = if does (P? x)
424487
then just zero
425-
else Maybe.map suc (findIndexᵇ p xs)
488+
else Maybe.map suc (findIndex P? xs)
489+
490+
findIndexᵇ : (A Bool) (xs : List A) Maybe $ Fin (length xs)
491+
findIndexᵇ p = findIndex (T? ∘ p)
426492

427493
-- Finds indices of all the elements satisfying the boolean predicate
428-
findIndicesᵇ : (A Bool) (xs : List A) List $ Fin (length xs)
429-
findIndicesᵇ p [] = []
430-
findIndicesᵇ p (x ∷ xs) = if p x
494+
findIndices : {P : Pred A p} Decidable P (xs : List A) List $ Fin (length xs)
495+
findIndices P? [] = []
496+
findIndices P? (x ∷ xs) = if does (P? x)
431497
then zero ∷ indices
432498
else indices
433-
where indices = map suc (findIndicesᵇ p xs)
434-
435-
-- Equivalent functions that use a decidable predicate instead of a
436-
-- boolean function.
437-
438-
takeWhile : {P : Pred A p} Decidable P List A List A
439-
takeWhile P? = takeWhileᵇ (does ∘ P?)
440-
441-
dropWhile : {P : Pred A p} Decidable P List A List A
442-
dropWhile P? = dropWhileᵇ (does ∘ P?)
499+
where indices = map suc (findIndices P? xs)
443500

444-
filter : {P : Pred A p} Decidable P List A List A
445-
filter P? = filterᵇ (does ∘ P?)
446-
447-
partition : {P : Pred A p} Decidable P List A (List A × List A)
448-
partition P? = partitionᵇ (does ∘ P?)
449-
450-
span : {P : Pred A p} Decidable P List A (List A × List A)
451-
span P? = spanᵇ (does ∘ P?)
452-
453-
break : {P : Pred A p} Decidable P List A (List A × List A)
454-
break P? = breakᵇ (does ∘ P?)
455-
456-
-- The predicate `P` represents the notion of newline character for the
457-
-- type `A`. It is used to split the input list into a list of lines.
458-
-- Some lines may be empty if the input contains at least two
459-
-- consecutive newline characters.
460-
linesBy : {P : Pred A p} Decidable P List A List (List A)
461-
linesBy P? = linesByᵇ (does ∘ P?)
462-
463-
-- The predicate `P` represents the notion of space character for the
464-
-- type `A`. It is used to split the input list into a list of words.
465-
-- All the words are non empty and the output does not contain any space
466-
-- characters.
467-
wordsBy : {P : Pred A p} Decidable P List A List (List A)
468-
wordsBy P? = wordsByᵇ (does ∘ P?)
469-
470-
derun : {R : Rel A p} B.Decidable R List A List A
471-
derun R? = derunᵇ (does ∘₂ R?)
472-
473-
deduplicate : {R : Rel A p} B.Decidable R List A List A
474-
deduplicate R? = deduplicateᵇ (does ∘₂ R?)
475-
476-
find : {P : Pred A p} Decidable P List A Maybe A
477-
find P? = findᵇ (does ∘ P?)
478-
479-
findIndex : {P : Pred A p} Decidable P (xs : List A) Maybe $ Fin (length xs)
480-
findIndex P? = findIndexᵇ (does ∘ P?)
481-
482-
findIndices : {P : Pred A p} Decidable P (xs : List A) List $ Fin (length xs)
483-
findIndices P? = findIndicesᵇ (does ∘ P?)
501+
findIndicesᵇ : (A Bool) (xs : List A) List $ Fin (length xs)
502+
findIndicesᵇ p = findIndices (T? ∘ p)
484503

485504
------------------------------------------------------------------------
486505
-- Actions on single elements

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

+1-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ 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.Bundles using (DecSetoid)
15-
open import Relation.Nullary.Decidable using (¬?)
1615

1716
module Data.List.Relation.Unary.Unique.DecSetoid.Properties where
1817

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

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

src/Data/String/Base.agda

+9-9
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ open import Level using (Level; 0ℓ)
2222
open import Relation.Binary.Core using (Rel)
2323
open import Relation.Binary.PropositionalEquality.Core using (_≡_; refl)
2424
open import Relation.Unary using (Pred; Decidable)
25-
open import Relation.Nullary.Decidable.Core using (does)
25+
open import Relation.Nullary.Decidable.Core using (does; T?)
2626

2727
------------------------------------------------------------------------
2828
-- From Agda.Builtin: type and renamed primitives
@@ -160,11 +160,11 @@ fromAlignment Right = padLeft ' '
160160
------------------------------------------------------------------------
161161
-- Splitting strings
162162

163-
wordsByᵇ : (Char Bool) String List String
164-
wordsByᵇ p = List.map fromList ∘ List.wordsByᵇ p ∘ toList
165-
166163
wordsBy : {p} {P : Pred Char p} Decidable P String List String
167-
wordsBy P? = wordsByᵇ (does ∘ P?)
164+
wordsBy P? = List.map fromList ∘ List.wordsBy P? ∘ toList
165+
166+
wordsByᵇ : (Char Bool) String List String
167+
wordsByᵇ p = wordsBy (T? ∘ p)
168168

169169
words : String List String
170170
words = wordsByᵇ Char.isSpace
@@ -173,11 +173,11 @@ words = wordsByᵇ Char.isSpace
173173
_ : words " abc b ""abc""b" ∷ []
174174
_ = refl
175175

176-
linesByᵇ : (Char Bool) String List String
177-
linesByᵇ p = List.map fromList ∘ List.linesByᵇ p ∘ toList
178-
179176
linesBy : {p} {P : Pred Char p} Decidable P String List String
180-
linesBy P? = linesByᵇ (does ∘ P?)
177+
linesBy P? = List.map fromList ∘ List.linesBy P? ∘ toList
178+
179+
linesByᵇ : (Char Bool) String List String
180+
linesByᵇ p = linesBy (T? ∘ p)
181181

182182
lines : String List String
183183
lines = linesByᵇ ('\n' Char.≈ᵇ_)

src/Data/Vec/Base.agda

+9-7
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
module Data.Vec.Base where
1010

11-
open import Data.Bool.Base using (Bool; if_then_else_)
11+
open import Data.Bool.Base using (Bool; true; false; if_then_else_)
1212
open import Data.Nat.Base
1313
open import Data.Fin.Base using (Fin; zero; suc)
1414
open import Data.List.Base as List using (List)
@@ -17,7 +17,7 @@ open import Data.These.Base as These using (These; this; that; these)
1717
open import Function.Base using (const; _∘′_; id; _∘_)
1818
open import Level using (Level)
1919
open import Relation.Binary.PropositionalEquality.Core using (_≡_; refl; trans; cong)
20-
open import Relation.Nullary.Decidable.Core using (does)
20+
open import Relation.Nullary.Decidable.Core using (does; T?)
2121
open import Relation.Unary using (Pred; Decidable)
2222

2323
private
@@ -230,12 +230,14 @@ foldl₁ _⊕_ (x ∷ xs) = foldl _ _⊕_ x xs
230230
sum : Vec ℕ n
231231
sum = foldr _ _+_ 0
232232

233-
countᵇ : (A Bool) Vec A n
234-
countᵇ p [] = zero
235-
countᵇ p (x ∷ xs) = if p x then suc (countᵇ p xs) else countᵇ p xs
236-
237233
count : {P : Pred A p} Decidable P Vec A n
238-
count P? = countᵇ (does ∘ P?)
234+
count P? [] = zero
235+
count P? (x ∷ xs) with does (P? x)
236+
... | true = suc (count P? xs)
237+
... | false = count P? xs
238+
239+
countᵇ : (A Bool) Vec A n
240+
countᵇ p = count (T? ∘ p)
239241

240242
------------------------------------------------------------------------
241243
-- Operations for building vectors

0 commit comments

Comments
 (0)