2012-06-08 81 views
2

我有一個關於Haskell的快速​​問題。我一直在關注Learn You a Haskell,對於以下代碼片段的執行順序/邏輯,用於計算三角形的邊長,當所有邊等於或小於10以及總邊長爲三角形是24:瞭解一點Haskell

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

的一部分是混淆對我來說是綁定在ba結合上方擴展。從我收集的內容來看,..c..b用於刪除同一組三角形邊的其他排列(組合?)。

當我與..c/b運行它,我得到了答案:

[(6,8,10)]

當我沒有..c/b

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

,因爲我沒有當我最初鍵入它,我得到:

[(8,6,10),(6,8,10)]

哪一個明顯代表了同一個三角形,除了ab的值已被交換。

那麼,有人可以通過邏輯/執行/評估這裏發生了什麼嗎?

回答

7

原始版本考慮所有三元組(a,b,c),其中c是1到10之間的數字,b是1到c之間的數字,a是1到b之間的數字。 (6,8,10)符合該標準,(8,6,10)不(因爲這裏a是8,b是6,所以a不在0和6之間)。

在你的版本中,你考慮所有三元組(a,b,c),其中a,b和c在1和10之間。你對a,b和c如何相互關聯沒有限制,所以(8, 6,10)不排除,因爲在所有的數字的確是1和10

如果你的當務之急for循環方面認爲這之間,你的版本則是:

for c from 1 to 10: 
    for b from 1 to 10: 
    for a from 1 to 10: 
     if a^2 + b^2 == c^2 and a+b+c==24: 
     add (a,b,c) to the result 

而原始版本是這樣的:

for c from 1 to 10: 
    for b from 1 to c: 
    for c from 1 to b: 
     if a^2 + b^2 == c^2 and a+b+c==24: 
     add (a,b,c) to the result 
+0

哎呀,謝謝! – Josh

1

這不是關於執行順序。在第一個示例中,您看不到簡併解決方案

[(8,6,10)] 

a <= b <= c。在第二種情況下,a > b包含在列表理解中。

1

列表解析可以用其他函數來編寫,如concatMap,它闡明瞭綁定的範圍。作爲一個內膽,你的榜樣變成這樣的事情:

concatMap (\c -> concatMap (\b -> concatMap (\a -> if a^2 + b^2 == c^2 then (if a+b+c == 24 then [(a,b,c)] else []) else []) (enumFromTo 1 b)) (enumFromTo 1 c)) (enumFromTo 1 10) 

是啊,相貌醜陋,但它類似於哈斯克爾desugars你的內涵之中。變量a,bc中的每個變量的範圍應該從這一點明顯。

或可替代地,這可以與List單子寫成:

import Control.Monad 

example = do c <- [1..10] 
      b <- [1..c] 
      a <- [1..b] 
      guard (a^2 + b^2 == c^2) 
      guard (a+b+c == 24) 
      return (a,b,c) 

這實際上是如上述一襯墊很相似,給出的List單子的定義和guard

instance Monad [] where 
    return x = [x] 
    xs >>= f = concatMap f xs 

instance MonadPlus [] where 
    mzero = [] 
    mconcat = (++) 

guard bool = if bool then return() else mzero 
+0

儘管我不能說我遵循所有這些,但我可以非常感謝你,並且希望在幾周內我能清楚地理解它。謝謝! – Josh

+0

你是否至少遵循一行? 'concatMap f xs'就像'map f xs',不同之處在於'f'產生一個項目列表,'concatMap'附加它們:'map(\ n - > [1..n])[1..3]'是[[1],[1,2],[1,2,3]]','concatMap(\ n - > [1..n])[1..3]'是[1,1 ,2,1,2,3]'。基本上,單線程使用[1..10],[1..c]和[1..b]上的嵌套'concatMap'來生成三元組,返回'[]'來拒絕三元組, (a,b,c)]'接受三重。最終結果連接所有單身'[(a,b,c)]'列表爲好的三元組,空列表爲壞的列表。 –