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

发布于 2024-08-26 12:08:37 字数 385 浏览 8 评论 0原文

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

After playing around with haskell a bit I stumbled over this function:

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

(Data.Maclaurin is exported by the package vector-space.) So it takes a Num, a function, another Num and ultimately returns a Num. What magic makes the following work?

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

2 is obviously not a function (a->a) or did I miss out on something?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

红颜悴 2024-09-02 12:08:37

同一包的 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

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

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

The Data.NumInstances module of the same package defines a Num instance for functions that return numbers:

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

In Haskell an integer literal like 2 is generic so that it can represent a number for any instance of Num:

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

To convert it to an actual number of the type required in a specific context, fromInteger from the Num class is called.

Since the helper module mentioned above defines an instance of Num for functions, 2 can now be converted to a function with the fromInteger method specified there.
So ghci calls fromInteger 2 to get the function required as the second parameter of the construct in the question. The whole expression then happens to evaluate to 6.

云柯 2024-09-02 12:08:37

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

You have good reason to be confused. Using the Data.NumInstances module in GHC (which is loaded by Data.Maclaurin) it is possible to coerce a Num to a constant function.

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

The evaluation of the expression is, essentially,

((+) . ($) . (+)) 1 2 3 = ((+) . ($) . (1+)) 2 3
                        = ((+) (1+)) 2 3
                        -- (+) is defined for functions that return a Num
                        = ((+) (1+) (\_ -> 2)) 3  
                        = ((+2) . (1+)) 3
                        = 6
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文