zip中的concat“没有这样的变量”

时间:2016-01-13 17:00:43

标签: idris

使用zipWith添加如下代码,工作正常:

zipWith (\x,y => x + y) [1,2,3] [4,5,6]

但是,使用串联而不是两个列表列表失败:

zipWith (\xs,ys => xs ++ ys) [[1],[2],[3]] [[4],[5],[6]]

有错误:

When checking argument x to constructor Prelude.List.:::
        No such variable a

我观察到可以毫无错误地执行以下操作:

zipWith (++) [[1],[2],[3]] [[4],[5],[6]]

但是,我很困惑为什么与lambda表达式的连接失败..?

1 个答案:

答案 0 :(得分:2)

Idris> :t (++)
Prelude.List.(++) : List a -> List a -> List a

这是编译器无法确定a的值的地方。如果您只是在REPL中键入[1,2,3],它将为其指定List Integer类型。但[1,2,3]也可以是List IntList Nat类型或某些数字的任何其他列表。如果你用['a','b','c']尝试你的例子,这种歧义消失了,repl会愉快地接受它:

Idris> zipWith (\xs, ys => xs ++ ys) [['a'],['b'],['c']] [['a'],['b'],['c']]
[['a', 'a'], ['b', 'b'], ['c', 'c']] : List (List Char)

您可以通过向类型检查器提供信息来解决初始问题:

zipWith (\xs, ys => (++) xs ys {a=Integer}) [[1],[2],[3]] [[4],[5],[6]]
zipWith (\xs, ys => the (List Integer) (xs ++ ys)) [[1],[2],[3]] [[4],[5],[6]]
the (List (List Integer)) (zipWith (\xs, ys => xs ++ ys) [[1],[2],[3]] [[4],[5],[6]])

在大多数情况下,但最简单的情况是统一需要一些类型声明。这就是(++)工作但不是lambda表达式的原因。前者更容易,后者更具抽象性(即额外的功能)。

但是当在文件中编写实际代码时,编译器不会像REPL那样友好,并且无论如何都会要求类型声明:

-- test : List (List Integer)
test = zipWith (\xs, ys => xs ++ ys) [[1],[2],[3]] [[4],[5],[6]]

Type checking ./test.idr
test.idr:1:1:No type declaration for Main.test