2017-06-12 35 views
2

我有以下表现:列表连接有例外

[1*** Exception: Prelude.undefined 
CallStack (from HasCallStack): 
    error, called at libraries\base\GHC\Err.hs:79:14 in base:GHC.Err 
    undefined, called at <interactive>:39:16 in interactive:Ghci20 

由于对应上述表达式:

let x = [1] ++ undefined ++ [3] 

我已经有了例外以下

Prelude> let x = [undefined, undefined, undefined ] 
Prelude> length x 

这里,我得到的结果是3不是一个例外,因为值得到评估,直到它得到ca LLED。

为什么早期表达式引发异常?

+0

请注意,这两个表达式是不一样的。为简洁起见,假设'u = undefined':[u,u,u]'是'[u] ++ [u] ++ [u]',而不是'[u] ++ u ++ [u]'。在你的第一个例子中,你有一个未定义的*列表*,而在第二个例子中,你只有未定义的*元素*,所以'长度'工作正常。 –

回答

3

如果你写:

let x = [1] ++ undefined ++ [3] 

然后x不计算。它存储为必须进行评估的表达式。但是,你查询x。换句话说,你想要show x。现在为了显示列表,必须评估整个列表(及其元素)

现在毗连运算(++) :: [a] -> [a] -> [a]定义为:

(++) :: [a] -> [a] -> [a] 
(++) (x:xs) ys = x : xs ++ ys 
(++) [] ys = ys 

例如[1,2] ++ [3,4]:将导致:

[1,2] ++ [3,4] 
-> 1 : ([2] ++ [3,4]) 
-> 1 : 2 : ([] ++ [3,4]) 
-> 1 : 2 : [3,4] 

undefined工作时:

[1,2] ++ undefined 
-> 1 : ([2] ++ undefined) 
-> 1 : 2 : ([] ++ undefined) 
-> 1 : 2 : undefined 

注意这是懒惰地完成:如果你需要更多的元素,你只能进一步concat。此外(++)确实不是关心单个元素:如果一个元素包含一个计算上昂贵的操作,那么该操作被推迟直到有必要计算它为止。

所以只要第一个列表仍然可以发出元素,我们不关心第二个列表。当第一个列表结束时,我们只需返回第二个列表。

我们看到,这部分的工作原理:解释打印[1*** Exception: Prelude.undefined所以在操作者(++)的评价,[1]第一元件被发射,评估和打印。但后来我们达到undefined,并且Haskell无法处理它以打印它(它的元素)并终止。

如果你写在另一方面let x = [undefined,undefined,undefined]和你打电话length x,然后列表的元素不被评估length的定义如下:在该函数

length :: [a] -> Int 
length [] = 0 
length (_:xs) = 1 + length xs 

头脑下划线(_)。length不关心个别元素。它将简单地遍历列表直到它遇到空列表[],并返回该计数,所以3

如果在另一方面,你会写

length $ [1] ++ undefined ++ [2,3] 

,你会得到同样的问题:

Prelude> length $ [1] ++ undefined ++ [2,3] 
*** Exception: Prelude.undefined 

因为为了在列表中行走,我们必须Concat的[1]undefined

+0

我无法想象,'++'如何工作。你可以请扩展例如'[1,2,3] ++ [3,4,5]' –

+0

完美,非常感谢您的帮助。 –