Haskell:试图理解 fmap 的类型(+)(一)

标签 haskell

我想了解为什么 fmap (+) (1)

没有类型错误

我确实理解以下顺序:

Prelude> :t  fmap 
fmap :: Functor f => (a -> b) -> f a -> f b
Prelude> :t  (+)  
(+) :: Num a => a -> a -> a                          # like a-> b with b = a -> a
Prelude> :t  fmap (+)
fmap (+) :: (Functor f, Num a) => f a -> f (a -> a)
Prelude> :t  fmap (+) (Just 1)                       
fmap (+) (Just 1) :: Num a => Maybe (a -> a)         # f=Maybe is implied by the Just constructor
Prelude>

我预计 fmap (+) (1) 会出现类型错误,因为 (1) 没有隐含仿函数,而是得到:

Prelude> :t (1)
(1) :: Num p => p
Prelude> :t  (+)  
(+) :: Num a => a -> a -> a                          
Prelude> :t  fmap (+)
fmap (+) :: (Functor f, Num a) => f a -> f (a -> a)
Prelude> :t  fmap (+) (1)
fmap (+) (1) :: (Functor f, Num a, Num (f a)) => f (a -> a)  ## why ??
Prelude>

这是为什么?

同样,我不明白 fmap (+) id 的类型:

Prelude> :t  fmap (+)   
fmap (+) :: (Functor f, Num a) => f a -> f (a -> a)
Prelude> :t  id      
id :: a -> a
Prelude> :t  fmap (+) id
fmap (+) id :: Num a => a -> a -> a       ## why no error ?
Prelude>

最佳答案

数字字面值可以适合任何类型,前提是它是数字类型(在 Num 类中)。

GHC 在一个开放世界的假设下工作,即使一个类型现在不属于一个实例,它也可能在未来。这是因为可以编写一个新模块并在那里声明一个实例,而我们需要单独编译。

对于数字类型,这意味着即使一个类型现在不是数字,以后也可能是。

假设我们写reverse 1。它看起来不对,因为 reverse 需要一个列表,而 1 不是一个列表。或者是吗?即使 [a] 现在不是数字,将来也可能是,因此 reverse 1 的类型是 Num [a] => [a] ,而不是类型错误。当然,在正常情况下我们不会有一个 Num [a] 实例,但 GHC 不能假设。

在您的具体示例中,fmap 想要一个 f a 并且您传递了 (1),这与 1。在这里,这个数字文字被实例化为 Num (f a) => f a,这样类型检查就可以工作了。

fmap (+) (1) :: (Functor f, Num a, Num (f a)) => f (a -> a)

需要上述约束 Num (f a) 以允许 1 在类型 f a 中被解释。那么 f 必须是一个仿函数,因为 fmap 需要它,我们必须有 Num a 因为 (+) 需要它的参数是数字((+) 的参数类型为 a,其结果类型为 a -> a,其中 a 必须是数字)。由于 (+) 的返回类型,我们再次得到 f (a -> a) 的结果。


关于fmap(+)id,这个比较简单。这里的id::(->) a a,也就是id::f a,其中f = (->) a,正好是一个仿函数。对于这个仿函数,我们有 fmap = (.),函数组合运算符。因此,fmap (+) id 表示 (.) (+) id(+) 。 id 就是 (+)

关于Haskell:试图理解 fmap 的类型(+)(一),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59224275/

相关文章:

haskell - 如何在 Haskell 中扩展矩阵

haskell - 在 Haskell 中将 "->"s 替换为 "→"s,将 "=>"s 替换为 "⇒"s 等等

Haskell:函数签名

list - 证明流的平等

haskell - 如何在 GHCi 中导入 Haskell 模块?

macos - OS X 上的 wxHaskell

Haskell 从文件 IO 返回惰性字符串

haskell - Haskell 是否真正纯粹(是否有任何语言处理系统外的输入和输出)?

haskell - 同态中的森林砍伐

haskell - 如何调试抖动规则执行?