Haskell 哈斯克尔惰性评价

Haskell 哈斯克尔惰性评价,haskell,lazy-evaluation,Haskell,Lazy Evaluation,如果我调用以下Haskell代码 find_first_occurrence :: (Eq a) => a -> [a] -> Int find_first_occurrence elem list = (snd . head) [x | x <- zip list [0..], fst x == elem] 压缩列表中有多少要构建 更新: 我试着跑 find_first_occurrence 10 [1..] 并且几乎立即返回9,所以我想它至少在简单的情况下使用了惰

如果我调用以下Haskell代码

find_first_occurrence :: (Eq a) => a -> [a] -> Int
find_first_occurrence elem list = (snd . head) [x | x <- zip list [0..], fst x == elem]
压缩列表中有多少要构建

更新:

我试着跑

find_first_occurrence 10 [1..]
并且几乎立即返回
9
,所以我想它至少在简单的情况下使用了惰性求值?答案也会在我跑步时“立即”计算出来

let f n = 100 - n
find_first_occurrence 10 (map f [1..])
所有这些

因为StackOverflow不会让我发布这么简短的回答:如果你要找的东西不在那里,你就不能做比查看整个列表更少的工作

编辑:现在这个问题问了一些更有趣的问题。简单的回答是,我们将建立以下列表:

('a',0):('b',1):('c',2):('d',3):('X',4):<thunk>
('a',0):('b',1):('c',2:('d',3):('X',4):

(实际上,这个答案非常微妙。您的类型签名使用单态返回类型
Int
,这在基本上所有操作中都是严格的,因此上面元组中的所有数字都将得到完全计算。
Num
肯定有一些实现,您可以通过更多的thunk获得一些东西,对吗

简短回答:它将只构建到您正在搜索的元素。这意味着只有在最坏的情况下,您才需要构建整个列表,即没有元素满足条件时

详细回答:让我用两个例子来解释原因:

ghci> head [a | (a,b) <- zip [1..] [1..], a > 10]
11

由于未构建整个压缩列表,haskell显然甚至不会计算列表中出现的每个表达式,因此当元素位于
div 1 0
之前时,该函数的计算结果是正确的,不会引发异常:没有出现被零除的情况。

您可以通过引入
undein轻松回答此类问题ed
s在这里和那里。在我们的情况下,更改输入就足够了:

find_first_occurrence 'X' ("abcdX" ++ undefined)
您可以看到它生成了结果,这意味着它甚至不会查看找到的“X”之外的内容(否则它会引发异常)。显然,如果不查看原始列表,就无法构建压缩列表

另一种(可能不太可靠)分析懒惰的方法是使用
Debug.trace
中的
trace
函数:

> let find_first_occurrence elem list = (snd . head) [x | x <- map (\i -> trace (show i) i) $ zip list [0..], fst x == elem]
> find_first_occurrence 'X' "abcdXkjdkljklfjdlfksjdljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj"

但我只查找第一个出现的“x”。而不是最后一个。一旦我找到了“x”,我就不需要分析列表中的其余部分。懒惰的评估是否会让我相信这一点,还是应该让代码更智能?@quant\u dev如果“x”不在列表中(如在您的示例中,请注意“x”/=“x”)然后,查找第一次出现的事件将扫描整个列表。如果列表中有“x”,则一旦遇到第一个“x”,评估将停止。对不起,我想在那里放“x”,而不是“x”。我的错误没有任何意义。好的,更新我对新的、更有趣的问题的答案。谢谢!我是Haskell新手,你的答案是什么“是”或“否”?更正:第二个表达式前面应该有“X”,而不是“X”。Re“我想它确实使用了惰性求值,至少在简单的情况下是这样的“:Haskell对所有情况都使用惰性求值;唯一的例外是存在
seq
@Daniel Wagner,另一个例外是模式匹配,对吗?@Rotsor:我不确定,Haskell通常可以在不完全求值的情况下模式匹配表达式。
case-zip[1..][2..]:->True
计算结果为
True
,因为我们只需要列表的第一个元素与
匹配(a,b):
@Rotsor模式匹配是推动评估的因素,但是说Haskell在进行模式匹配时不使用惰性是非常误导的。无论您是将
foo
与模式
x
,还是
,或
(:\uuu)匹配:
,运行时对
foo
的求值不会超过决定哪种模式匹配所需的时间。
find_first_occurrence 'X' ("abcdX" ++ undefined)
> let find_first_occurrence elem list = (snd . head) [x | x <- map (\i -> trace (show i) i) $ zip list [0..], fst x == elem]
> find_first_occurrence 'X' "abcdXkjdkljklfjdlfksjdljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj"
('a',0)
('b',1)
('c',2)
('d',3)
('X',4)
4