簡體   English   中英

如何在找到正確的三角形時使用Haskells懶惰

[英]How to use Haskells laziness when finding right triangles

我正在http://learnyouahaskell.com/starting-out上關注(優秀的)Haskell教程,並嘗試使用正確的三角形示例:

> let triangles = [(a,b,c) | c <- [1..10], b <- [1..10], a <- [1..10], a^2 + b^2 == c^2]

按照預期運行我得到的:

> triangles 
[(4,3,5),(3,4,5),(8,6,10),(6,8,10)]

現在,我想嘗試使用無限列表:

> let triangles = [(a,b,c) | c <- [1..], b <- [1..], a <- [1..], a^2 + b^2 == c^2] 

但是,當我嘗試它時,像:

> take 2 triangles

...程序只運行並運行,沒有輸出。 我究竟做錯了什么? 我認為Haskells懶惰會導致它找到兩個第一個三角形然后停止?

嗯,懶惰不是問題。 這是您在列表中迭代變量的順序。

基本上會發生什么:

  1. c綁定為1
  2. b必然是1
  3. a必然是1
  4. 檢查方程式
  5. a必然是2
  6. 檢查方程式
  7. a必然是3
  8. 檢查方程式

它會永遠持續下去。

因此,發電機不斷迭代和對綁定值的a ,因為它不知道你需要停下來,也增加bc一變。

所以你需要以更平衡的方式生成元組。

例如,您可以使用此方法:

triplesN :: Int -> [(Int, Int, Int)]
triplesN n = [(i, j, n - i - j) | i <- [1..n - 2], 
                                  j <- [1..n - i - 1], i>=j, 
                                  let k = n - i - j,   j>=k]

isTriangle (a, b, c) = a^2 == b^2 + c^2

triangles = filter isTriangle $ concatMap triplesN [1..]

tripleN生成所有有序三元組,其總和為n 通過在所有自然數上映射此函數,我們實際上獲得了所有有序對的流。 最后,我們只過濾那些三角形的三元組。

通過做:

take 10 triangles

我們得到:

[(5,4,3),(10,8,6),(13,12,5),(15,12,9),(17,15,8),(20,16,12),(25,24,7),(25,20,15),(26,24,10),(29,21,20)]

您可能有興趣閱讀sigfpe博客上的文章A Monad for Combinatorial Search

他定義了一個名為懲罰列表PList的新monad,類似於列表monad,但它也有更復雜解決方案的懲罰概念。 當您組合PLists時,生成結果的順序是最小罰分 - >最大罰分。

在您的示例中,與整數關聯的懲罰可能等於整數的大小,與元組關聯的懲罰是其元素的懲罰之和。 因此元組(3,4,5)懲罰為3 + 4 + 5 = 12,而元組(5,12,13)懲罰為5 + 12 + 13 = 30。

使用列表monad,生成的元組的順序是

(1,1,1), (1,1,2), (1,1,3), (1,1,4), (1,1,5) ...

你永遠不會看到一個不是形式(1,1,x)的元組。 使用PList monad,產生的元組可能是

(1,1,1), (1,1,2), (1,2,1), (2,1,1), (1,1,3), (1,3,1), (3,1,1), (1,2,2) ...

在'較大'之前生成所有'較小'元組。

對於您的特定問題,此解決方案過度,但在更復雜的問題中它非常有用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM