2014-11-23 89 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) 
相关问题