6

在玩了一下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) 还是我错过了什么?

4

2 回答 2

16

Data.NumInstances同一包的模块为返回数字的函数定义了一个实例:Num

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

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

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

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

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

于 2010-03-22T23:56:31.337 回答
1

你有充分的理由感到困惑。使用Data.NumInstancesGHC 中的模块(由 加载Data.Maclaurin)可以将 a 强制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
于 2010-03-23T00:37:31.410 回答