哈斯克尔奇怪的表达

时间:2015-09-07 17:56:10

标签: haskell

我想了解为什么以下是Haskell中的有效表达式:

mysql

更奇怪的是表格中的任何表达

Prelude> let e = (+) (-)
Prelude> :type e
e :: (Num (a -> a -> a), Num a) => (a -> a -> a) -> a -> a -> a

无论N都是不可理解类型的有效表达式。例如,

e 1 2 3 4 ... N

这是干扰和类型推断的不幸结果吗?

欢迎澄清。

1 个答案:

答案 0 :(得分:20)

这不是“不幸的后果”。事实上,有些人可能会将其视为一项功能! (+)(-)的类型为

> :t (+)
(+) :: Num a => a -> a -> a
> :t (-)
(-) :: Num a => a -> a -> a

重要的是要意识到这对任何类型a都有效,即使a是函数类型也是如此。因此,例如,如果类型b -> b -> bNum个实例,那么您可以将(+)限制为

(+) :: Num (b -> b -> b) => (b -> b -> b) -> (b -> b -> b) -> b -> b -> b

只需设置a = b -> b -> b即可。由于curry,最后三个b周围的括号是不必要的(你可以写它们但它们会是多余的)。

现在,Num b => b -> b -> b正是(-)的类型(附带条件b本身必须有Num个实例),因此函数{{1} }填写(-)的第一个“广告位”,(+)的类型为

(+) (-)

这是你观察到的。

这提出了一个问题,即为什么在函数上有一个(+) (-) :: (Num b, Num (b -> b -> b)) -> (b -> b -> b) -> b -> b -> b 实例可能是有用的。事实上,为函数定义Num实例是否有意义?

我声称确实如此!你可以定义

Num

作为instance Num a => Num (r -> a) where (f + g) r = f r + g r (f - g) r = f r - g r (f * g) r = f r * g r abs f r = abs (f r) signum f r = signum (f r) fromInteger n r = fromInteger n 实例非常有意义。事实上,这正是您需要解释表达式Num -

的实例
e

寮步?!?

发生的事情如下。由于> let e = (+) (-) > e 3 2 1 4 是任何(Num a) => r -> a的有效Num实例,因此您可以将r替换为r,这表明a -> a也是有效的(Num a) => a -> a -> a个实例。你有

Num

有点令人费解(特别是,确保你理解为什么-- Remember that (+) f = \g r -> f r + g r (+) (-) 3 2 1 = (\g r s -> (-) r s + g r s) 3 2 1 -- definition of (+) on functions = (\ r s -> (-) r s + 3 r s) 2 1 -- beta reduction = (\ s -> (-) 2 s + 3 2 s) 1 -- beta reduction = (-) 2 1 + 3 2 1 -- beta reduction = (2 - 1) + 3 -- since (3 2) = 3 and (3 1) = 3 = 1 + 3 = 4 )但是一旦你扩展了所有的定义就不会太混乱!

您要求推导Haskell使用的3 2 = 3类型。它依赖于类型变量“统一”的概念。它是这样的 -

  1. 您知道(+) (-)(+) :: Num a => a -> a -> a(我使用不同的字母,因为我们希望将它们混合在一起)。
  2. 如果您要将(-) :: Num b => b -> b -> b放入(-)的第一个广告位,则必须(+),因此合并后的类型为
  3. a ~ b -> b -> b
  4. 现在,您将(+) (-) :: (Num a, Num b, a ~ b -> b -> b) => (b -> b -> b) -> (b -> b -> b)a“统一”(如胖箭头左侧所示,b -> b -> b符号)
  5. ~
  6. 如果我们删除最右边的括号(因为它们是多余的)并将(+) (-) :: (Num (b -> b -> b), Num b) => (b -> b -> b) -> (b -> b -> b)重命名为b,则这是Haskell推断的类型签名。