Haskell:f a的实际含义是什么?

时间:2016-10-27 17:52:16

标签: haskell functor

我偶然发现了这段代码fold ((,) <$> sum <*> product)的代码:: (Foldable t, Num a) => t a -> (a, a),我完全迷失了。

我知道它的作用,但我不知道怎么做。所以我试着把它分成几小块ghci:

λ: :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
λ: :t (,)
(,) :: a -> b -> (a, b)
λ: :t sum
sum :: (Foldable t, Num a) => t a -> a

一切都很好,只是基本的东西。

λ: :t (,) <$> sum
(,) <$> sum :: (Foldable t, Num a) => t a -> b -> (a, b)

我又迷失了......

我发现将t a -> a转变为f a会发生一些神奇的事情,但如何做到这一点对我来说是个谜。 (sum甚至不是Functor的实例!)

我一直认为f a是包含f的某种方框a,但看起来意义更深。

2 个答案:

答案 0 :(得分:5)

您示例中的仿函数f是所谓的“阅读器仿函数”,其定义如下:

newtype Reader r = Reader (r -> a)

当然,在Haskell中,这是为函数本地实现的,因此在运行时没有包装或解包。

相应的FunctorApplicative实例如下所示:

instance Functor f where
  fmap :: (a -> b) -> (r -> a)_-> (r -> b)
  fmap f g = \x -> f (g x) -- or: fmap = (.)

instance Applicative f where
  pure :: a -> (r -> a) -- or: a -> r -> a
  pure x = \y -> x -- or: pure = const
  (<*>) :: (r -> a -> b) -> (r -> a) -> (r -> b)
  frab <*> fra = \r -> frab r (fra r)   

在某种程度上,读者仿函数也是一个“盒子”,就像所有其他仿函数一样,具有产生类型r的上下文a

让我们看一下(,) <$> sum

:t (,) :: a -> b -> (a, b)
:t fmap :: (d -> e) -> (c -> d) -> (c -> e)
:t sum :: Foldable t, Num f => t f -> f

我们现在可以将d类型专用于a ~ feb -> (a, b)ct f。现在我们得到:

:t (<$>) -- spcialized for your case
:: Foldable t, Num f => (a -> (b -> (a, b))) -> (t f -> f) -> (t f -> (b -> (a, b)))
:: Foldable t, Num f => (f -> b -> (f, b)) -> (t f -> f) -> (t f -> b -> (f, b))

应用功能:

:t (,) <$> sum
:: Foldable t, Num f => (t f -> b -> (f, b))

这正是ghc所说的。

答案 1 :(得分:2)

简短的回答是f ~ (->) (t a)。要查看原因,只需稍微重新排列sum的类型签名,使用->作为前缀运算符而不是中缀运算符。

sum :: (Foldable t, Num a) => (->) (t a) a
                              ~~~~~~~~~~
                                  f

通常,(->) r是任何参数类型r的仿函数。

instance Functor ((->) r) where
    fmap = (.)

通过将(.)插入fmap的{​​{1}}类型,可以很容易地证明((->) r)fmap唯一可能的实现:

f

这是合成的类型签名,合成是具有此类型签名的唯一函数。

由于fmap :: (a -> b) -> f a -> f b :: (a -> b) -> ((->) r) a -> ((->) r) b :: (a -> b) -> (r -> a) -> (r -> b) Data.Functor定义为<$>的中缀版本,我们有

fmap

从这里开始,确认结果类型确实是(,) <$> sum == fmap (,) sum == (.) (,) sum 是一项相对简单但又繁琐的工作。我们有

(Foldable t, Num a) => t a -> b -> (a, b)