我试图理解为什么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>发布于 2019-12-07 08:51:03
数字文字可以适合任何类型,只要它是数字类型(在类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。
发布于 2019-12-07 08:43:17
这是一个简单的结果,因为数字文本(如1 )是多态的--它们的类型是(Num a) => a。此外,没有固定的数值类型列表,因为Haskell允许您为任何类(包括Num )创建自己的实例。
因此,在适用这一原则时:
Prelude> :t fmap (+)
fmap (+) :: (Functor f, Num a) => f a -> f (a -> a)对于文本1,类型检查器只需要检查是否可以将1类型与输入类型f a统一。考虑到上面提到的1的多态类型,这显然是可能的,前提是有一个Num实例可以用于f a --就像f a是1的有效类型一样。这解释了最后一种类型。
至于fmap (+) id,这是完全不同的。这里,GHC需要将f a (对于函子f和数值a)与a -> a统一,这导致了f唯一可能的选择,即“函数函子”((->) a) ( fmap只是组合)。f b在这里的意思是a -> b,所以f (a -> a)是a -> a -> a。
https://stackoverflow.com/questions/59224275
复制相似问题