Types 为什么可以';'n'和'plus n0'之间的约束不能解决吗?

Types 为什么可以';'n'和'plus n0'之间的约束不能解决吗?,types,identity,tail-recursion,idris,dependent-type,Types,Identity,Tail Recursion,Idris,Dependent Type,我正在尝试在REPL上重新加载包含以下Idris 2函数的源文件: ||| Apply a function across all elements of a vector. ||| @function The function to apply. ||| @input_vector The vector whose elements will be given as an argument to the function. my_vect_map : (function : a -> b

我正在尝试在REPL上重新加载包含以下Idris 2函数的源文件:

||| Apply a function across all elements of a vector.
||| @function The function to apply.
||| @input_vector The vector whose elements will be given as an argument to the function.
my_vect_map : (function : a -> b) -> (input_vector : Vect n a) -> Vect n b
my_vect_map function Nil = Nil
my_vect_map function (head :: tail) =
  (my_vect_map' ((function head) :: Nil) tail) where
    my_vect_map' : (accumulator : Vect length_b b) -> Vect length_a a -> Vect (length_b + length_a) b
    my_vect_map' accumulator Nil = accumulator
    my_vect_map' accumulator (head' :: tail') =
      my_vect_map' (accumulator ++ ((function head') :: Nil)) tail'
但它无法键入check,错误为:

Error: While processing right hand side of my_vect_map. While processing right hand side
of my_vect_map,my_vect_map'. Can't solve constraint
between: length_b (implicitly bound at page_75_section_3_2_exercises_solutions.idr:89:5--89:47) and plus length_b 0.

page_75_section_3_2_exercises_solutions.idr:89:36--89:47
    |
 89 |     my_vect_map' accumulator Nil = accumulator
    |                                    ^^^^^^^^^^^

Error(s) building file page_75_section_3_2_exercises_solutions.idr
为什么类型检查器不能解决
长度\u b
加长度\u b 0
之间的约束?我做错了什么?我该如何纠正?我试着用手研究一些例子,结果似乎是:

my_vect_map id [] => Nil => []

my_vect_map id ['a'] => my_vect_map id ('a' :: Nil) => my_vect_map' ((id 'a') :: Nil) Nil => my_vect_map' ('a' :: Nil) Nil => ('a' :: Nil) => ['a']
                                                                                                          ^length_b=1  ^length_a=0            ^length=1=length_b+length_a

my_vect_map id ['a', 'b'] => my_vect_map id ('a' :: ('b' :: Nil)) => my_vect_map' ((id 'a') :: Nil) ('b' :: Nil) => my_vect_map' ('a' :: Nil) ('b' :: Nil) => my_vect_map' (('a' :: Nil) ++ ((id 'b') :: Nil)) Nil => my_vect_map' (('a' :: Nil) ++ ('b' :: Nil)) Nil => my_vect_map' ('a' :: ('b' :: Nil)) Nil => ('a' :: ('b' :: Nil)) => ['a', 'b']
                                                                                                                                 ^length_b=1  ^length_a=1                                                                                                                             ^length_b=2           ^length_a=0                     ^length=2=length_b+length_a

另外,我如何让类型检查器意识到
length\u b+length\u a
等于
n
(因为我认为我没有将这种关系编码到函数中)

您可以通过使用in
Data.Nat
来证明
n+0=n

不过,您可能需要重新考虑一下这个函数

您可以非常轻松地创建矢量贴图:

my_vect_map : (a -> b) -> Vect n a -> Vect n b
my_vect_map fn [] = []
my_vect_map fn (x :: xs) = fn x :: my_vect_map fn xs
编辑

下面是
映射的尾部递归版本

mutual
  rhs : {m : Nat} -> (a -> b) -> a -> Vect m b -> Vect len a -> Vect (plus m (S len)) b
  rhs f x acc xs = rewrite sym $ plusSuccRightSucc m len in my_vect_map' f (f x :: acc) xs

  my_vect_map' : {m : Nat} -> (a -> b) -> Vect m b -> Vect n a -> Vect (m + n) b
  my_vect_map' f acc [] = rewrite plusZeroRightNeutral m in acc
  my_vect_map' f acc (x :: xs) = rhs f x acc xs

my_vect_map : (a -> b) -> Vect n a -> Vect n b
my_vect_map f = reverse . my_vect_map' f []
rhs
的唯一目的是公开
len
,即
xs
的大小

我们还使用了
{}
将类型变量引入值级别的作用域


希望这能有所帮助。

感谢您让我了解
plusZeroRightNeutral
和重写规则。Fwiw,我知道向量映射可以用普通递归实现,但我尝试用尾部递归来实现它。啊,我很感激你写了一个尾部递归实现,这是一个值得学习的有用示例!有趣的是,您将函数的一部分提升到了顶层,而不是像我一样使用闭包(Idris不允许相互递归闭包吗?),并且您的函数似乎预先添加了元素,以创建一个反向向量,然后将其反转到正确的顺序,而不是添加元素(预结束+反转是否比追加便宜?)。您应该能够使用
where
块,但您可能必须在函数体之前写入签名(您必须检查)。Idris向量是链表,因此追加是
O(n)
。您试图编写的
map
版本最终将是
O(n^2)
,相反的版本是
O(n)