Haskell的类型系统将数值视为函数?

时间:2010-03-22 23:20:28

标签: haskell types numeric typeclass

在玩了一下haskell后,我偶然发现了这个功能:

Prelude Data.Maclaurin> :t ((+) . ($) . (+))
((+) . ($) . (+)) :: (Num a) => a -> (a -> a) -> a -> a

(Data.Maclaurin由包向量空间导出。)因此它需要一个Num,一个函数,另一个Num并最终返回一个Num。下面的工作有什么神奇之处?

Prelude Data.Maclaurin> ((+) . ($) . (+)) 1 2 3
6

2显然不是一个功能(a-> a)或者我错过了什么?

2 个答案:

答案 0 :(得分:16)

返回数字的函数的同一个包Data.NumInstancesNum实例的defines模块:

instance Num b => Num (a->b) where
  (+)         = liftA2 (+)
  (*)         = liftA2 (*)
  fromInteger = pure . fromInteger
  ...

在Haskell中,像2这样的整数文字是通用的,因此它可以代表Num的任何实例的数字:

Prelude> :t 2
2 :: (Num t) => t

要将其转换为特定上下文中所需类型的实际数量,将调用fromInteger类中的Num

由于上面提到的辅助模块为函数定义了Num的实例,现在可以将 2转换为函数,并在其中指定fromInteger方法。 所以ghci调用fromInteger 2来获取所需的函数作为问题中构造的第二个参数。然后整个表达式恰好评估为6

答案 1 :(得分:1)

你有充分的理由感到困惑。使用GHC中的Data.NumInstances模块(由Data.Maclaurin加载),可以将Num强制转换为常量函数。

Prelude Data.NumInstances> :t (2 :: (Num a) => a -> a)
(2 :: (Num a) => a -> a) :: (Num a) => a -> a
Prelude Data.NumInstances> (2 :: (Num a) => a -> a) 0          
2
Prelude Data.NumInstances> (2 :: (Num a) => a -> a) 1000
2

表达式的评估基本上是

((+) . ($) . (+)) 1 2 3 = ((+) . ($) . (1+)) 2 3
                        = ((+) (1+)) 2 3
                        -- (+) is defined for functions that return a Num
                        = ((+) (1+) (\_ -> 2)) 3  
                        = ((+2) . (1+)) 3
                        = 6