[英]Haskell: What does type f a actually mean?
I have stumbled on this piece of code fold ((,) <$> sum <*> product)
with type signature :: (Foldable t, Num a) => ta -> (a, a)
and I got completely lost. 我偶然发现这段代码fold ((,) <$> sum <*> product)
类型签名:: (Foldable t, Num a) => ta -> (a, a)
我完全迷失了。
I know what it does, but I don't know how. 我知道它的作用,但我不知道怎么做。 So I tried to break it into little pieces in 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
Everything is okay, just basic stuff. 一切都很好,只是基本的东西。
λ: :t (,) <$> sum
(,) <$> sum :: (Foldable t, Num a) => t a -> b -> (a, b)
And I am lost again... 而我又迷失了......
I see that there is some magic happening that turns ta -> a
into fa
but how it is done is mystery to me. 我看到有一些神奇的事情会变成ta -> a
into fa
但它是如何完成的对我来说是个谜。 ( sum
is not even instance of Functor
!) ( sum
甚至不是Functor
实例!)
I have always thought that fa
is some kind of box f
that contains a
but it looks like the meaning is much deeper. 我一直认为fa
是某种箱f
包含a
,但它看起来像含义深刻得多。
The functor f
in your example is the so-called "reader functor", which is defined like this: 您的示例中的仿函数f
是所谓的“reader functor”,其定义如下:
newtype Reader r = Reader (r -> a)
Of course, in Haskell, this is implemented natively for functions, so there is no wrapping or unwrapping at runtime. 当然,在Haskell中,这是为函数本地实现的,因此在运行时没有包装或解包。
The corresponding Functor
and Applicative
instances look like this: 相应的Functor
和Applicative
实例如下所示:
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)
In a way, the reader functor is a "box" too, like all the other functors, having a context r
which produces a type a
. 在某种程度上,读者仿函数也是一个“盒子”,就像所有其他仿函数一样,具有产生类型a
的上下文r
。
So let's look at (,) <$> sum
: 那么让我们看看(,) <$> sum
:
:t (,) :: a -> b -> (a, b)
:t fmap :: (d -> e) -> (c -> d) -> (c -> e)
:t sum :: Foldable t, Num f => t f -> f
We can now specialize the d
type to a ~ f
, e
to b -> (a, b)
and c
to tf
. 我们现在可以将d
类型专门化为a ~ f
, e
到b -> (a, b)
和c
到tf
。 Now we get: 现在我们得到:
: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))
Applying the functions: 应用功能:
:t (,) <$> sum
:: Foldable t, Num f => (t f -> b -> (f, b))
Which is exactly what ghc says. 这正是ghc所说的。
The short answer is that f ~ (->) (ta)
. 简短的回答是f ~ (->) (ta)
。 To see why, just rearrange the type signature for sum
slightly, using ->
as a prefix operator instead of an infix operator. 要了解原因,只需稍微重新排列sum
的类型签名,使用->
作为前缀运算符而不是中缀运算符。
sum :: (Foldable t, Num a) => (->) (t a) a
~~~~~~~~~~
f
In general, (->) r
is a functor for any argument type r
. 通常, (->) r
是任何参数类型r
的仿函数。
instance Functor ((->) r) where
fmap = (.)
It's easy to show that (.)
is the only possible implementation for fmap
here by plugging ((->) r)
into the type of fmap
for f
: 通过将((->) r)
插入到f
的fmap
类型中,很容易证明(.)
是fmap
唯一可能的实现:
fmap :: (a -> b) -> f a -> f b
:: (a -> b) -> ((->) r) a -> ((->) r) b
:: (a -> b) -> (r -> a) -> (r -> b)
This is the type signature for composition, and composition is the unique function that has this type signature. 这是合成的类型签名,合成是具有此类型签名的唯一函数。
Since Data.Functor
defines <$>
as an infix version of fmap
, we have 由于Data.Functor
将<$>
定义为fmap
的中缀版本,我们有
(,) <$> sum == fmap (,) sum
== (.) (,) sum
From here, it is a relatively simple, though tedious, job of confirming that the resulting type is, indeed, (Foldable t, Num a) => ta -> b -> (a, b)
. 从这里开始,确认结果类型确实是(Foldable t, Num a) => ta -> b -> (a, b)
,这是一个相对简单但又繁琐的工作。 We have 我们有
(b' -> c') -> (a' -> b') -> (a' -> c') -- composition
b' -> c' ~ a -> b -> (a,b) -- first argument (,)
a' -> b' ~ t n -> n -- second argument sum
----------------------------------------------------------------
a' ~ t n
b' ~ a ~ n
c' ~ a -> b -> (a,b)
----------------------------------------------------------------
a' -> c' ~ t a -> b -> (a,b)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.