我想了解为什么以下是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
这是干扰和类型推断的不幸结果吗?
欢迎澄清。
答案 0 :(得分:20)
这不是“不幸的后果”。事实上,有些人可能会将其视为一项功能! (+)
和(-)
的类型为
> :t (+)
(+) :: Num a => a -> a -> a
> :t (-)
(-) :: Num a => a -> a -> a
重要的是要意识到这对任何类型a
都有效,即使a
是函数类型也是如此。因此,例如,如果类型b -> b -> b
有Num
个实例,那么您可以将(+)
限制为
(+) :: 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
类型。它依赖于类型变量“统一”的概念。它是这样的 -
(+) (-)
和(+) :: Num a => a -> a -> a
(我使用不同的字母,因为我们希望将它们混合在一起)。(-) :: Num b => b -> b -> b
放入(-)
的第一个广告位,则必须(+)
,因此合并后的类型为a ~ b -> b -> b
(+) (-) :: (Num a, Num b, a ~ b -> b -> b) => (b -> b -> b) -> (b -> b -> b)
与a
“统一”(如胖箭头左侧所示,b -> b -> b
符号)~
(+) (-) :: (Num (b -> b -> b), Num b) => (b -> b -> b) -> (b -> b -> b)
重命名为b
,则这是Haskell推断的类型签名。