刚开始学习Haskell并遇到了这个问题。 如果我有一个列表理解与条件,如
[x*2 | x<- [1..10], x `mod` 3 ==2]
我得到了
[4,10,16]
正如所料。但是,如果我有了
[x**2 | x<- [1..10], x `mod` 3 ==2]
mod函数的类型变量不明确。我认为这是因为x 2 将整数提升为浮点数,但为什么这会影响条件?在这种情况下,为什么类型不明确?它是否计算x 2 ,然后平方根呢? (这似乎非常不可能)它是否以某种方式跟踪生成每个x 2 项的x?
也许这是势在必行的心态,但在内部,我认为执行将是[在python中]
lst=[]
for x in range(10):
if x%3==2:
lst.append(x**2)
有人可以澄清/纠正我的理解吗?
答案 0 :(得分:6)
我们来看看mod
和(**)
的类型:
mod :: Integral n => n -> n -> n
(**) :: Floating a => a -> a -> a
-- hm......
mod
和(**)
对使用的类型设置了其他限制。 mod
需要整数类型(Int
,Integer
),而(**)
需要浮动类型(Float
,Double
)。由于没有类型的积分和都是浮点数,GHC放弃了。
相反,请使用(^)
:
(^) :: (Integral n, Num a) => a -> n -> a
E.g。
[x ^ 2 | x <- [1..10], x `mod` 3 == 2]
顺便说一下,如果你试图给结果一个类型,你可以更容易地发现这样的错误:
ghci> [x ** 2 | x <- [1..10], x `mod` 3 == 2] :: [Int]
<interactive>:1:4:
No instance for (Floating Int) arising from a use of `**'
In the expression: x ** 2
...
答案 1 :(得分:3)
第一个例子因默认而起作用。该表达式被推断为具有类型
Integral a => [a]
然后将a
类型变量默认为Integer
以方便使用。
在第二个表达式中,使用**
强制x
为Floating
而mod
强制它为Integral
。所以GHC推断表达式有类型
(Integral a, Floating a) => [a]
没有Integral
和Floating
的标准数字类型,更不用说参与默认的数据类型了。
您在提问中提到了数字推广的概念。 C,C ++,Java,也许还有其他一些语言都有这样的东西。 Haskell没有,而我们这些使用它的人往往对此感激不尽。从一种数字类型到另一种数字类型的所有转换都必须使用显式转换函数完成,例如fromIntegral
,fromRational
,round
,floor
,%
等。< / p>
您可能打算使用^
代替**
,这只会留下Integral a
约束。在实际程序中,您通常应该通过包含类型签名来避免默认机制。您可以使用
default ()
你模块中的某个地方。
答案 2 :(得分:0)
使用列表monad将haskell desugars中的列表理解列表到do-block。在您的示例中,它将类似于:
x <- [1..10]
guard $ (x `mod` 3) == 2
return $ x**2
在这种情况下,它会尝试统一失败的(**) x 2
和mod x 3
类型,因为您can't统一了具有Integral类型的Floating类型,而没有在两者之间明确转换。
您有以下几种选择:如果您希望(^^)
成为整数类型,请使用(**)
代替((fromIntegral x) ** 2)
或x
,或以某种方式围绕x
1}}如果你想要它是一个浮动类型,那就是一个整数类型。