列表理解过滤的执行顺序

Execution order of list comprehension filtering

刚开始学习 Haskell 遇到了这个问题。 如果我有一个条件如

的列表理解
[x*2 | x<- [1..10], x `mod` 3 ==2]

我明白了

[4,10,16]

符合预期。但是,如果我有

[x**2 | x<- [1..10], x `mod` 3 ==2]

它的类型变量对于 mod 函数是不明确的。我认为这是因为 x2 将整数提升为浮点数,但为什么这会影响条件?为什么在这种情况下类型不明确?它会计算 x2,然后对它求平方根吗? (这似乎极不可能)它是否以某种方式跟踪生成每个 x2 项的 x?

也许这是命令式的心态,但在内部,我认为执行将遵循 [in python]

lst=[]
for x in range(10):
 if x%3==2:
  lst.append(x**2)

有人能clarify/correct我的理解吗?

我们来看看mod(**)的类型:

mod  :: Integral n => n -> n -> n
(**) :: Floating a => a -> a -> a
     -- hm......

mod(**) 对使用的类型设置了其他约束。 mod 需要整数类型(IntInteger),而 (**) 需要浮点类型(FloatDouble)。由于没有类型既是整数 又是 浮点数,GHC 放弃了。

而是使用 (^):

(^) :: (Integral n, Num a) => a -> n -> a

例如

[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
    ...

haskell 中的列表理解使用列表 monad 脱糖为 do-block。在您的示例中,它将类似于:

x <- [1..10]
guard $ (x `mod` 3) == 2
return $ x**2

在这种情况下,它试图统一 (**) x 2mod x 3 的类型,但失败了,因为您 can't 统一了 Floating 类型和 Integral 类型,而没有在两者之间显式转换。

您有几个选择:使用 (^^) 而不是 (**) 或者如果您希望 x 成为整数类型,则使用 ((fromIntegral x) ** 2) x 如果您希望它是浮点类型,则为整数类型。

第一个示例由于默认设置而有效。表达式被推断为具有类型

Integral a => [a]

然后为了方便,a类型变量默认为Integer

在第二个表达式中,使用 ** 强制 xFloatingmod 强制为 Integral。所以 GHC 推断表达式的类型为

(Integral a, Floating a) => [a]

没有既是Integral又是Floating的标准数值类型,更不用说参与违约了。

您在问题中提到了数字提升的概念。 C、C++、Java,也许其他一些语言也有这样的东西。 Haskell 没有,我们这些使用它的人往往会对此心存感激。所有从一种数字类型到另一种数字类型的转换都必须使用显式转换函数完成,例如 fromIntegralfromRationalroundfloor%

您可能打算使用 ^ 而不是 **,这将只留下 Integral a 约束。在实际程序中,您通常应该通过包含类型签名来 避免 默认机制。您可以使用

完全关闭它
default ()

在你模块的某个地方。