当前位置: 首页 > 知识库问答 >
问题:

需要帮助了解Haskell的懒惰评估行为

璩俊雅
2023-03-14

我已经写了两个版本的nqueens问题,我认为它们应该有相似的效率,但事实并非如此。我认为这是由于哈斯克尔的懒惰评估行为。有人能解释一下下面的例子是如何工作的吗,

nqueens1 n 1 = [[i] | i <- [1..n]]
nqueens1 n k = [ i:q | i <- [1..n], q <- (nqueens1 n (k - 1)), isSafe i q k]

isSafe i q n  = isSafeHelper i (zip q [(n-1),(n-2)..1]) 
         where isSafeHelper i []  = True
               isSafeHelper i (x:xs) = (i /= fst x) && abs(i - (fst x)) /= abs(n - (snd x)) && 
                                       isSafeHelper i xs
nqueens2 n 1 = [[i] | i <- [1..n]]
nqueens2 n k = [ i:q | i <- [1..n], q <- boards, isSafe i q k]
           where boards = nqueens2  n (k-1)

您可以通过调用nqueens1 8 8或nqueens2 8 8对其进行评估,以对大小为8的板进行评估。

虽然nqueens2工作效率很高,但nqueens1存在性能问题。我相信这是因为递归调用(nqueens n(k-1))被多次评估。根据我对Haskell懒惰评估的理解,情况不应该是这样。

请帮助我理解这种行为。

提前谢谢。

共有1个答案

齐鹏程
2023-03-14

是的,递归调用会被计算多次。具体而言,对于i的每个值,都会对其进行一次评估。

如果您想避免这种情况,您可以重新排列生成器,以便q

[ i:q | q <- nqueens2 n (k - 1), i <- [1..n], isSafe i q k]

但是,这将更改结果的顺序。如果这是不可接受的,您可以使用let计算一次递归调用的结果,然后像这样使用它:

[ i:q | let rec = nqueens2 n (k - 1), i <- [1..n], q <- rec, isSafe i q k]

 类似资料:
  • 我正在阅读HadleyWickhams关于Github的书,特别是关于懒惰评估的这一部分。在那里,他给出了一个懒惰求值结果的例子,在函数的添加部分。让我引用这一点: 这个[惰性评估]在使用lApplication或循环创建闭包时很重要: x在您第一次调用其中一个加法器函数时被延迟计算。此时,循环完成,x的最终值为10。因此,所有加法器函数都会在其输入中添加10,可能不是您想要的!手动强制评估解决了

  • 问题内容: 我最近读到了Python 3的一个好处是它很懒。那就更好了 而不是 我很好奇的是如何使用这种懒惰。如果生成映射对象,例如,如何访问生成的操作/列表中的特定元素。在我所见过的几乎所有文档中,他们都会做类似或的事情(据我所知),它放弃了惰性概念,因为它隐式将地图转换为列表。 我想我正在寻找的是能够以与我可以懒惰地懒惰地生成地图对象类似的方式使用地图对象的能力,并且可以在没有巨大计算量的情况

  • 评估项目': tflite'时出现问题。 没有方法的签名:build _ 29 ou 9 K6 cal 0 PML 6 qvuo 3 exmb 2 . Android()适用于参数类型:(build _ 29 ou 9 K6 cal 0 PML 6 qvuo 3 exmb 2 $ _ run _ closure 2)值:[build _ 29 ou 9 K6 cal 0 PML 6 qvuo 3

  • 我使用ACR122读卡器已经有一段时间了,它在读取Mifare 1K或Mifare Ultralight NFC卡时都没有问题。 将读卡器升级到最新版本(ACR1251)后,我的程序无法读取Mifare 1K卡的UID。 这是我用来阅读的片段: 使用新版rad阅读器: ResponseAPDU.getSW1()函数返回98 而getSW2()返回130 我试着在网上和读卡器文档中搜索响应代码的解释

  • 我试图写一个代码为每个股票价值是75美元或更多添加一个"*"在STK_FLAG列。 ORA-06550:第15行,第21列:PLS-00201:标识符“STK\U FLG”必须声明ORA-06550:第15行,第5列:PL/SQL:SQL语句忽略ORA-06550:第23行,第7列:PL/SQL:ORA-00904:“STK\U FLG”:无效标识符ORA-06550:第17行,第5列:PL/SQ

  • 问题内容: 例如,如果我有以下语句: 如果foo1为true,python将检查foo2的条件吗? 问题答案: 是的,Python懒惰地评估布尔条件。 该文件说, 表达式x和y首先计算x;如果x为假,则返回其值;否则,将评估y并返回结果值。 表达式x或y首先计算x; 如果x为true,则返回其值;否则,将评估y并返回结果值。