代码是:
filter-pos : {A : Set} → A → (ℕ → ) → A
filter-pos = {!!}
filter-pos-test : filter-pos ('a' :: 'b' :: 'c' :: 'd' :: 'e' :: 'f' :: []) is-even ≡ 'a' :: 'c' :: 'e' :: []
filter-pos-test = refl
我的想法是使用nth
输出nth
索引,使用map
函数将它们放入列表中,如果它是偶数n
,它将会返回。但是,这不能正常工作。
有人可以告诉我应该如何解决这个问题吗?我认为编写帮助函数来解决问题会很有帮助。
答案 0 :(得分:2)
我将使用标准库。
一个愚蠢的解决方案是使用索引元素压缩列表,使用通常的filter
然后删除索引。 E.g。
'a' :: 'b' :: 'c' :: 'd' :: 'e' :: 'f' :: []
变为
('a', 0) :: ('b', 1) :: ('c', 2) :: ('d', 3) :: ('e', 4) :: ('f', 5) :: []
filter (is-even ∘ snd)
返回
('a', 0) :: ('c', 2) :: ('e', 4) :: []
和map fst
会产生
'a' :: 'c' :: 'e' :: []
更自然的解决方案是遍历列表并在每次递归调用时递增计数器:
filter-pos : {A : Set} → List A → (ℕ → Bool) → List A
filter-pos {A} xs p = go 0 xs where
go : ℕ -> List A -> List A
go i [] = []
go i (x ∷ xs) = if p i then x ∷ r else r where
r = go (suc i) xs
此处i
是元素的索引。但是现在,无论何时您需要证明filter-pos
的某些内容,您都需要首先证明有关go
的引理,因为它go
执行实际工作,而filter-pos
只是它的包装。惯用解决方案如下所示:
filter-pos : {A : Set} → List A → (ℕ → Bool) → List A
filter-pos [] p = []
filter-pos (x ∷ xs) p = if p 0 then x ∷ r else r where
r = filter-pos xs (p ∘ suc)
这里不是递增计数器,而是调整谓词并用suc
组合。因此,在第一个元素上,我们检查p 0
是否为真,在第二个元素上我们检查(p ∘ suc) 0
(立即减少到p 1
)是否为真,在第三个元素上我们检查是否{ {1}}(立即缩减为(p ∘ suc ∘ suc) 0
)为真,依此类推。即这与计数器的解决方案相同,但只使用一个函数。
也可以调整最后一个版本以使用p 2
代替Fin
ℕ