确定 Vect n Nat 的总和是否能整除 5?

Determine if Sum of Vect n Nat's Evenly Divides 5?

Cactus demonstrated how to address my question: .

他写道:

onlyModBy5 : (n : Nat) -> {auto prf : n `modNat` 5 = 0} -> Nat
onlyModBy5 n = n

然后,我尝试使用该函数将 onlyModBy5 应用于 Vect n Nat 的总和。

foo : (n : Nat) -> Vect n Nat -> Nat
foo n xs = onlyModBy5 $ sum xs

但是我得到了这个编译时错误:

When checking right hand side of foo with expected type
        Nat

When checking argument prf to function Main.onlyModBy5:
        Can't find a value of type 
                Prelude.Nat.modNatNZ, mod' (foldrImpl (\meth =>
                                                         \meth =>
                                                           plus meth meth)
                                                      0
                                                      id
                                                      xs)
                                           4
                                           SIsNotZ
                                           (foldrImpl (\meth =>
                                                         \meth =>
                                                           plus meth meth)
                                                      0
                                                      id
                                                      xs)
                                           (foldrImpl (\meth =>
                                                         \meth =>
                                                           plus meth meth)
                                                      0
                                                      id
                                                      xs)
                                           4 =
                0
Holes: Main.foo

如何将上述 onlyModBy5 函数与 foo 一起使用?

这取决于你想要达到的目标。 foo : (n : Nat) -> Vect n Nat -> Nat 表示您可以将任何 Nat 应用于 foo,以及 Nat 的任何 Vect(如果 Vect 的大小为 n) 和 foo 将 return 一个 Nat.

首先,您不需要明确的 (n : Nat) 参数。如果你只写 foo : Vect n Nat -> Nat,Idris 会在内部将 n 变成一个隐式参数:foo : {n : Nat} -> Vect n Nat -> Nat.

参数中没有关于 Vect 的元素,因此也没有关于它的 sum 的元素。您也可以应用 [1,2,2] 以及 [1,1],而后者没有 prf : (sum [1,1]) `modNat` 5 == 0) 的证明,因此显然您不能应用总和为 onlyModBy5.

您可以像以前一样要求证明这一点作为论据:

bar : (xs : Vect n Nat) -> {auto prf : (sum xs) `modNat` 5 = 0} -> Nat
bar xs = onlyModBy5 (sum xs)

或者让它根据总和来决定:

foo : Vect n Nat -> Maybe Nat
foo xs = foo' (sum xs)
  where
    foo' : Nat -> Maybe Nat
    foo' k with (decEq (k `modNat` 5) 0)
      | Yes prf = Just (onlyModBy5 k {prf})
      | No _ = Nothing

decEq 决定两个值在命题上是否相等(在这种情况下,如果它们相同 Nat),以及 return 或 Yes(prf : n `modNat` 5 = 0) 它们相等,或 No 证明它们不相等。然后可以用 {prf} 将此证明提供给 onlyModBy5。这扩展到 {prf=prf},它为隐式参数提供 Yes 的证明,因为两者都被命名为 prf.