仿函数实例声明中的箭头运算符?

Arrow operator in functor instance declarations?

我正在做 these Haskell 'intermediate' 练习,我做了以下实例:

class Fluffy f where
  furry :: (a -> b) -> f a -> f b

instance Fluffy [] where
  furry f [] = []

instance Fluffy Maybe where
  furry f (Just e) = Just (f e)
  furry f (Nothing) = Nothing

然而,第三个问题语法难倒了我:

instance Fluffy ((->) t) where
  ...

我已经阅读了箭头运算符,还阅读了 this 的答案,其中解释了 (->) 在 Monad 实例中的作用。但是我不太明白 (->) 在函子的上下文中是如何工作的?

我们有:

class Fluffy f where
  furry :: (a -> b) -> f a -> f b

我们要定义:

instance Fluffy ((->) t) where
  furry = ...

这意味着在上面的例子中 furry 应该有类型 (a -> b) -> f a -> f b 其中 f((->) t),或者换句话说:

furry :: (a -> b) -> ((->) t) a -> ((->) t) b

正如 ((+) 2) 32 + 3 相同,((->) X) YX -> Y 相同(它是柯里化运算符应用程序,它甚至可以在类型级别工作) :

furry :: (a -> b) -> (t -> a) -> (t -> b)

我们可以将上述签名解读为“给定一个从 ab 的函数和一个从 ta 的函数,return 从 tb" 的函数。

现在你只需要实施它。 :-)

我们这样定义 Functor 实例:

instance Functor ((->) a) where
    fmap f g = \a -> f (g a)
    -- Pointfree definition: fmap = (.)

也就是说,(->)仿函数相当于一个只能'opened'的容器,通过获取一些a类型的值和'opening'容器用它。任何 fmap 只是在我们 'open' 容器之后更改值。即:组合函数。

这有点像 Maybe 仿函数,因为我可以将函数应用于该值(如果它存在),但是对于 (->) 仿函数,我在知道它是什么之前就这样做了是。

但是请记住,所有的 monad 都是仿函数,因为我们可以这样定义 fmap

fmap f m = m >>= (\a -> return (f a))

因此,如果您了解在 Monad 实例中的作用,那么应该清楚它在 Functor 实例中的作用。