|
| 1 | +------------------------------------------------------------------------ |
| 2 | +-- The Agda standard library |
| 3 | +-- |
| 4 | +-- Illustration of the `NonNull predicate over `List` |
| 5 | +------------------------------------------------------------------------ |
| 6 | + |
| 7 | +module README.Data.List.Relation.Unary.Null where |
| 8 | + |
| 9 | +open import Data.List.Base using (List; []; _∷_; head) |
| 10 | +open import Data.List.Relation.Unary.Null |
| 11 | +open import Data.Product.Base using (Σ; _,_; proj₁; proj₂) |
| 12 | +open import Level using (Level) |
| 13 | +open import Relation.Binary.PropositionalEquality |
| 14 | +open import Relation.Unary.Null |
| 15 | +open import Relation.Unary.Refinement |
| 16 | + |
| 17 | +private |
| 18 | + variable |
| 19 | + |
| 20 | + a b : Level |
| 21 | + A : Set a |
| 22 | + B : Set b |
| 23 | + x : A |
| 24 | + xs : List A |
| 25 | + ys : List B |
| 26 | + |
| 27 | +------------------------------------------------------------------------ |
| 28 | +-- Example deployment: a safe head function |
| 29 | + |
| 30 | +safe-head : (xs : List A) → .{{NonNull xs}} → A |
| 31 | +safe-head (x ∷ _) = x |
| 32 | + |
| 33 | +------------------------------------------------------------------------ |
| 34 | +-- Example deployments: scans |
| 35 | + |
| 36 | +-- ScanL |
| 37 | + |
| 38 | +module ScanL (f : A → B → A) where |
| 39 | + |
| 40 | + scanl : A → List B → List A |
| 41 | + scanl e [] = e ∷ [] |
| 42 | + scanl e (x ∷ xs) = e ∷ scanl (f e x) xs |
| 43 | + |
| 44 | + instance scanlNonNull : {e : A} {xs : List B} → NonNull (scanl e xs) |
| 45 | + scanlNonNull {xs = []} = _ |
| 46 | + scanlNonNull {xs = x ∷ xs} = _ |
| 47 | + |
| 48 | + scanl⁺ : A → List B → [ List A ]⁺ |
| 49 | + scanl⁺ e xs = refine⁺ (scanl e xs) |
| 50 | + |
| 51 | + |
| 52 | +-- ScanR |
| 53 | + |
| 54 | +module ScanRΣ (f : A → B → B) (e : B) where |
| 55 | + |
| 56 | +-- design pattern: refinement types via Σ-types |
| 57 | + |
| 58 | + scanrΣ : List A → Σ (List B) NonNull |
| 59 | + scanrΣ [] = e ∷ [] , _ |
| 60 | + scanrΣ (x ∷ xs) with ys@(y ∷ _) , _ ← scanrΣ xs = f x y ∷ ys , _ |
| 61 | + |
| 62 | + scanr : List A → List B |
| 63 | + scanr xs = proj₁ (scanrΣ xs) |
| 64 | + |
| 65 | + instance scanrNonNull : {xs : List A} → NonNull (scanr xs) |
| 66 | + scanrNonNull {xs = xs} = proj₂ (scanrΣ xs) |
| 67 | + |
| 68 | + unfold-scanr-∷ : ∀ xs → |
| 69 | + let ys = scanr xs in |
| 70 | + let instance _ = scanrNonNull {xs = xs} in |
| 71 | + scanr (x ∷ xs) ≡ f x (safe-head ys) ∷ ys |
| 72 | + unfold-scanr-∷ xs with ys@(y ∷ _) , _ ← scanrΣ xs = refl |
| 73 | + |
| 74 | +module ScanR (f : A → B → B) (e : B) where |
| 75 | + |
| 76 | +-- design pattern: refinement types via mutual recursion |
| 77 | + |
| 78 | +-- to simulate the refinement type { xs : List A | NonNull xs } |
| 79 | +-- define two functions by mutual recursion: |
| 80 | +-- `f` : the bare, 'extracted' underlying function |
| 81 | +-- `fNonNull` : the (irrelevant instance) witness to the refinement predicate |
| 82 | + |
| 83 | +-- but for now, again we seem to have to go via a third function |
| 84 | +-- essentially `scanrΣ` but with an irrelevant instance field instead |
| 85 | + |
| 86 | + scanr⁺ : List A → [ List B ]⁺ |
| 87 | + |
| 88 | + refine⁻ (scanr⁺ []) = e ∷ [] |
| 89 | + refined (scanr⁺ []) = _ |
| 90 | + |
| 91 | + scanr⁺ (x ∷ xs) with refine⁺ ys ← scanr⁺ xs with y ∷ _ ← ys |
| 92 | + = refine⁺ (f x y ∷ ys) |
| 93 | + |
| 94 | + scanr : List A → List B |
| 95 | + scanr xs = refine⁻ (scanr⁺ xs) |
| 96 | + |
| 97 | + instance scanrNonNull : {xs : List A} → NonNull (scanr xs) |
| 98 | + scanrNonNull {xs = xs} with refine⁺ ys ← scanr⁺ xs with y ∷ _ ← ys = _ |
| 99 | + |
| 100 | + unfold-scanr-∷ : ∀ xs → |
| 101 | + let ys = scanr xs in |
| 102 | + let instance _ = scanrNonNull {xs = xs} in |
| 103 | + scanr (x ∷ xs) ≡ f x (safe-head ys) ∷ ys |
| 104 | + unfold-scanr-∷ xs with refine⁺ ys ← scanr⁺ xs with y ∷ _ ← ys = refl |
| 105 | + |
| 106 | + |
| 107 | + |
| 108 | + |
0 commit comments