2014-02-17 20 views
0

我正在寫,其基於起始號碼在Collat​​z鏈的功能,但我已經遇到意想不到的問題

下面的代碼:

-- original, works 
collatzA :: Integer -> [Integer] 
collatzA 1 = [1] 
collatzA n 
     | even n = n:collatzA (n `div` 2) 
     | odd n = n:collatzA (n * 3 + 1) 

-- what I'm trying to do, won't compile, gives nasty errors 
collatzB :: Integer -> [Integer] 
collatzB 1 = [1] 
collatzB n 
     | even n = n:collatzB $ n `div` 2 
     | odd n = n:collatzB $ n * 3 + 1 

-- attempted solution, works but re-adds the parentheses I tried to get rid of 
collatzC :: Integer -> [Integer] 
collatzC 1 = [1] 
collatzC n 
     | even n = n: (collatzC $ n `div` 2) 
     | odd n = n: (collatzC $ n * 3 + 1) 

那麼爲什麼collatzAcollatzC工作,但collatzB沒有?

回答

4

此問題是由於運算符優先級或固定性

例如(+)(從RWH,我強烈建議採取),爲左結合與固定性6和(*)聲明聲明爲左結合與固定性7.這意味着表達

8 + 7 + 6 * 5 * 4 

是解析爲

(8 + 7) + ((6 * 5) * 4) 

同樣,在你的榜樣,在cons操作(:)是右結合的,具有固定性5,而應用operato ř($)是右結合並具有固定性0 由於($)具有比(:)較低固定性,以collatzB遞歸調用「抓住」由(:)

n = (n:collatzB) $ (n `div` 2) 

This link包含了前奏功能固定性的信息,和你也可以看到this post瞭解更多信息。

1

問題是f $ g被編譯器視爲(f) $ (g)。如果你有f $ g $ h,編譯器將它看作(f) $ ((g) $ (h)),並且你可以擴展這個模式。所以,當你有

n : collatzB $ n `div` 2` 

編譯器認爲這是

(n : collatzB) $ (n `div` 2) 

而且(n : collatzB)不鍵入檢查。

這是由於$和它的右聯合(infixr)的固定性。


如果括號打擾你那麼多(這是他們不應該),你可以定義一個新的運營商作爲

infixr 1 $: 
($:) :: a -> (b -> [a]) -> b -> [a] 
a $: f = \x -> a : f x 

collatzB :: Integer -> [Integer] 
collatzB 1 = [1] 
collatzB n 
    | even n = n $: collatzB $ n `div` 2 
    | odd n = n $: collatzB $ n * 3 + 1 

但這種誠實會引起更多的混亂比它的價值。我會堅持個人parens。

+0

非常巧妙的解決方案;但我認爲你是對的,它確實會對校對員造成更多的困惑,而不是它的幫助,所以我認爲我會按照你的建議並堅持括號 –