2014-11-23 85 views
0

我已經定義了以下功能Haskell中[1 .. 0]與[1 .. -1]的區別和原因?

let repl x n = [x | _ <- [1..n]] 

模仿內置的複製功能。

雖然用它進行試驗,我發現一個奇怪的事情:repl 10 0評估爲[],而repl 10 -1產生一個錯誤:

No instance for (Show (t10 -> [t0])) arising from a use of ‘print’ 
In a stmt of an interactive GHCi command: print it 

在另一方面,無論[1 .. 0][1 .. -1]評估爲[]而不會產生任何錯誤。

此外,[42 | _ <- [1 .. 0]][42 | _ <- [1 .. -1]]都評估爲[]沒有錯誤。

那麼,爲什麼我的函數調用會導致錯誤,其中顯式替換不會?更重要的是,[1 .. 0][1 .. -1]之間的明顯區別在哪裏?

而最後一個問題:當我寫:

repl 42 -1 

錯誤是完全一樣與repl 10 -1,即它仍然有(Show (t10 -> [t0]))位在裏面。我期待它有類似((Show (t42 -> [t0])))。這是什麼10?

+1

您可能會發現這些問題的答案有所幫助:[前綴一元運算符(http://stackoverflow.com/questions/3406320/前綴外形的-一元 - 操作者在-哈斯克爾/ 3406692#3406692); [爲什麼我不能乘以沒有括號的負數](http://stackoverflow.com/questions/26073878/); [有趣的參數有趣的haskell行爲](http://stackoverflow.com/questions/14741552/)。 – 2014-11-23 16:55:38

回答

4

其他答案指出,你需要用圓括號包裝-1。這是出乎意料地跳出去的an odd corner of the Haskell 98 spec。這是而不是這種情況下,你永遠不會寫一個負數沒有括號:-1 * 5是好的。只是一元前綴運算符沒有比二元中綴運算符更高的優先級,所以-經常被解析爲後者。 Haskell中,運算符周圍的空白不重要。

而令人難以理解的類型類錯誤沒有幫助。順便提一句,t10t0只是由編譯器組成的佔位符類型變量;我不認爲它與你使用的實際數字文字有什麼關係。而非正式地,像Could not deduce (Num (a0 -> t))這樣的錯誤通常會告訴我,函數應用於太少的參數。

或者,GHC 7.8中的(未記錄的)NegativeLiterals語言擴展改變了-1的含義以解決此問題。

> :set -XNegativeLiterals 
> :t repl 10 -1 
repl 10 -1 :: Num t => [t] 
+2

這種情況並非如此 - 功能評估在運算符之前,所以'repl 10 -1'相當於'(repl 10) - 1'而不是'repl 9' – Benesh 2014-11-23 16:35:07

+1

這通常不是一個好主意,因爲啓用語言擴展在Haskell。首先,因爲它使代碼與Haskell98不兼容。其次,因爲沒有必要。一組額外的括號不是一個大問題,它不保證使用語言擴展。 – 2014-11-23 16:36:47

+1

@AaditMShah - 這是一種極端的看法。當然,在這種情況下,用圓括號修復它很容易。但從一開始,Haskell的哲學部分就是對語言本身進行不斷的實驗。有幾個擴展被廣泛地移動,例如'IncoherentInstances',但是我沒有聽說過那個燈中提到的'NegativeLiterals'。 (更大的問題是,它還沒有文檔!) – 2014-11-23 16:43:43

1

你試過[1..(-1)]?在Haskell中,您不能直接編寫像-1這樣的負數。你需要把它們放在括號內。原因是Haskell沒有前綴一元運算符,因爲Haskell中的運算符總是中綴。因此-1被解析爲[operator (-)] [numeric 1]而不是[numeric -1]

這是導致問題的原因。爲了避免這個問題,負數必須始終放在括號內。這確保(-1)被解析爲[numeric -1]。這是爲Haskell提供偏頭痛的少數幾個角落案例之一。

2

您還沒有包含在你的問題錯誤消息,如果你有,你會看到repl 10 -1被解析爲(repl 10) - (1)這並非您的本意。

你會得到與repl 10 +1相同的錯誤。

通過仔細查看錯誤消息,您通常可以找到關於如何解析程序代碼的線索。在你學習的同時,過度使用括號也沒有什麼壞處。

The program

repl x n = [x | _ <- [1..n]]  -- line 1 

main = print (repl 10 -1)   -- line 3 

消息:

 
prog.hs:3:8: 
    No instance for (Show (t1 -> [t0])) arising from a use of `print' 
    Possible fix: add an instance declaration for (Show (t1 -> [t0])) 
    In the expression: print (repl 10 - 1) 
    In an equation for `main': main = print (repl 10 - 1) 

prog.hs:3:15: 
    No instance for (Num t1) arising from a use of `repl' 
    The type variable `t1' is ambiguous 
    Possible fix: add a type signature that fixes these type variable(s) 
    Note: there are several potential instances: 
     instance Num Double -- Defined in `GHC.Float' 
     instance Num Float -- Defined in `GHC.Float' 
     instance Integral a => Num (GHC.Real.Ratio a) 
     -- Defined in `GHC.Real' 
     ...plus three others 
    In the first argument of `(-)', namely `repl 10'   --------- NB! 
    In the first argument of `print', namely `(repl 10 - 1)' 
    In the expression: print (repl 10 - 1) 

prog.hs:3:20: 
    No instance for (Num t0) arising from the literal `10' 
    The type variable `t0' is ambiguous 
    Possible fix: add a type signature that fixes these type variable(s) 
    Note: there are several potential instances: 
     instance Num Double -- Defined in `GHC.Float' 
     instance Num Float -- Defined in `GHC.Float' 
     instance Integral a => Num (GHC.Real.Ratio a) 
     -- Defined in `GHC.Real' 
     ...plus three others 
    In the first argument of `repl', namely `10' 
    In the first argument of `(-)', namely `repl 10'   --------- NB! 
    In the first argument of `print', namely `(repl 10 - 1)' 

prog.hs:3:23: 
    No instance for (Num (t1 -> [t0])) arising from a use of `-' 
    Possible fix: add an instance declaration for (Num (t1 -> [t0])) 
    In the first argument of `print', namely `(repl 10 - 1)' 
    In the expression: print (repl 10 - 1) 
    In an equation for `main': main = print (repl 10 - 1) 
相關問題