列表连接异常
List concatenation with exception
我有以下表达式:
let x = [1] ++ undefined ++ [3]
我遇到了以下异常:
[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
与上面的表达式对应:
Prelude> let x = [undefined, undefined, undefined ]
Prelude> length x
在这里,我得到的结果 3
不是异常,因为值在调用之前不会被评估。
为什么前面的表达式引发异常?
如果你写:
let x = [1] ++ undefined ++ [3]
则x
不计算。它存储为必须计算的表达式。但随后您查询 x
。也就是说,你想要show x
。现在 为了显示列表,必须评估整个列表(及其元素)。
现在 concat 运算符 (++) :: [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
请注意,这是 lazily 完成的:只有在需要更多元素时才进一步连接。此外,(++)
不 关心单个元素:如果一个元素包含计算量大的操作,该操作将推迟到需要计算它时才进行。
所以只要第一个列表还能发出元素,我们就不用管第二个列表。当到达第一个列表的末尾时,我们只需 return 第二个列表。
我们看到这部分有效:解释器打印 <b>[1</b>*** 异常:Prelude.undefined
所以在(++)
运算符的评估,[1]
的第一个元素 被发出 ,评估并打印。但是随后我们到达 undefined
并且 Haskell 无法处理它以打印它(它的元素)并终止。
如果你写 let x = [undefined,undefined,undefined]
而调用 length x
,那么 列表的 元素 不会被评估。 length
定义如下:
length :: [a] -> Int
length [] = 0
length (_:xs) = 1 + length xs
注意函数中的下划线 (_
)。 length
不关心单个元素。它会简单地遍历列表,直到它到达空列表 []
,并且 return 算在内,所以 3
.
如果另一方面你会写
length $ [1] ++ undefined ++ [2,3]
你会遇到同样的问题:
Prelude> length $ [1] ++ undefined ++ [2,3]
*** Exception: Prelude.undefined
因为为了遍历列表,我们必须将 [1]
与 undefined
连接起来。
我有以下表达式:
let x = [1] ++ undefined ++ [3]
我遇到了以下异常:
[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
与上面的表达式对应:
Prelude> let x = [undefined, undefined, undefined ]
Prelude> length x
在这里,我得到的结果 3
不是异常,因为值在调用之前不会被评估。
为什么前面的表达式引发异常?
如果你写:
let x = [1] ++ undefined ++ [3]
则x
不计算。它存储为必须计算的表达式。但随后您查询 x
。也就是说,你想要show x
。现在 为了显示列表,必须评估整个列表(及其元素)。
现在 concat 运算符 (++) :: [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
请注意,这是 lazily 完成的:只有在需要更多元素时才进一步连接。此外,(++)
不 关心单个元素:如果一个元素包含计算量大的操作,该操作将推迟到需要计算它时才进行。
所以只要第一个列表还能发出元素,我们就不用管第二个列表。当到达第一个列表的末尾时,我们只需 return 第二个列表。
我们看到这部分有效:解释器打印 <b>[1</b>*** 异常:Prelude.undefined
所以在(++)
运算符的评估,[1]
的第一个元素 被发出 ,评估并打印。但是随后我们到达 undefined
并且 Haskell 无法处理它以打印它(它的元素)并终止。
如果你写 let x = [undefined,undefined,undefined]
而调用 length x
,那么 列表的 元素 不会被评估。 length
定义如下:
length :: [a] -> Int
length [] = 0
length (_:xs) = 1 + length xs
注意函数中的下划线 (_
)。 length
不关心单个元素。它会简单地遍历列表,直到它到达空列表 []
,并且 return 算在内,所以 3
.
如果另一方面你会写
length $ [1] ++ undefined ++ [2,3]
你会遇到同样的问题:
Prelude> length $ [1] ++ undefined ++ [2,3]
*** Exception: Prelude.undefined
因为为了遍历列表,我们必须将 [1]
与 undefined
连接起来。