【问题标题】:Haskell's type system treats a numerical value as function?Haskell 的类型系统将数值视为函数?
【发布时间】:2010-03-22 23:20:27
【问题描述】:

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

【问题讨论】:

标签: haskell types numeric typeclass


【解决方案1】:

同一包definesData.NumInstances 模块Num 返回数字的函数的实例:

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

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

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

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

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

【讨论】:

  • 此外,all 应用函子承认数字类的这些实例。请参阅 applicative-numbers 包,了解为您想要的任何应用函子定义此类实例的简单方法。
【解决方案2】:

你有充分的理由感到困惑。使用 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

【讨论】:

  • 不,这是不可能的,除非您加载了一些为a -> a 定义Num 实例的非标准模块。
  • 好吧,该死的,我可以发誓这在没有加载 Data.Maclaurin 的情况下有效,但事实并非如此。正如@sth 所指出的,这种魔法是由 Data.NumInstances 启用的。
猜你喜欢
  • 2012-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多