我试图通过使用Σ
函数来绕过filterVec
类型,类似于可用于列表的filter
函数。请参阅下面的实施:
-- Some imports we will need later
open import Data.Bool
open import Data.Nat
open import Data.Product
open import Data.Vec
-- The filterVec function
filterVec : {n : ℕ} -> (ℕ -> Bool) -> Vec ℕ n -> Σ ℕ (λ length → Vec ℕ length)
filterVec _ [] = 0 , []
filterVec f (x ∷ xs) with filterVec f xs
... | length , filtered = if f x then (suc length , x ∷ filtered) else (length , filtered)
对我的功能感到满意,我决定测试它
dummyVec : Vec ℕ 5
dummyVec = 1 ∷ 2 ∷ 3 ∷ 4 ∷ 5 ∷ []
dummyFn : Vec ℕ 5
dummyFn with filterVec (λ _ → true) dummyVec
dummyFn | length , xs = {!!} -- I would like to return xs here, but Agda throws a type error
出于某种原因,Agda无法判断length
是5
,因此不允许我返回xs
。但是,下面的代码确实有效:
open import Relation.Binary.PropositionalEquality
dummyProof : proj₁ (filterVec (λ _ → true) dummyVec) ≡ 5
dummyProof = refl
我对这种行为感到十分困惑。在dummyFn
的情况下,Agda无法判断长度为5,但在dummyProof
的情况下,Agda证明它没有任何问题。
我错过了什么?如何让dummyFn
工作?
答案 0 :(得分:4)
with
将值绑定到名称。如果要进行计算,可以使用let
:
dummyFn′ : Vec ℕ 5
dummyFn′ = let length , xs = filterVec (λ _ → true) dummyVec
in xs
让我们看看下面的例子:
dummy : Set
dummy with 5
dummy | x = {!!}
x
是否应该在洞中神奇地减少到5
?不,你给了5
另一个名字 - x
,这些表达既不是在判断上也不是在命题上相等。
现在在你的例子中:
dummyFn : Vec ℕ 5
dummyFn with filterVec (λ _ → true) dummyVec
dummyFn | length , xs = {!!}
您已将length
名称指定为xs
的长度。并且它不会减少到5
。这是一个名字。如果你想要两者都给出一个名字并记住这个名字是什么,那就有inspect
成语:
dummyFn′′ : Vec ℕ 5
dummyFn′′ with filterVec (λ _ → true) dummyVec | inspect (filterVec (λ _ → true)) dummyVec
dummyFn′′ | length , xs | [ refl ] = xs