25

Functor 中 fmap 的类型是:

fmap :: Functor f => (a -> b) -> f a -> f b

看起来,首先将函数(a -> b)应用于fa的参数以创建b类型的结果,然后将f应用于它,结果为fb

使用Maybe a例如:

 fmap show (Just 1)
 result is : Just "1"

和说的一样:

Just (show 1)

但当(->)用作函子时(在Control.Monad.Instances

import Control.Monad.Instances
(fmap show Just) 1
result is : "Just 1"

Just先应用,再show应用。在另一个例子中,结果是一样的:

 fmap (*3) (+100) 1
 result is 303

那为什么不*3+100呢?

4

5 回答 5

34

(即函数)的fmap实例(->) r实际上只是组合。从源本身

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

因此,在您的示例中,我们可以替换fmap(.),并进行一些转换

fmap (*3) (+100) 1 => 
(.) (*3) (+100) 1  =>
(*3) . (+100) $ 1  => -- put (.) infix
(*3) (1 + 100)     => -- apply (+100)
(1 + 100) * 3         -- apply (*3)

也就是说,fmapfor 函数从右到左组合它们(与 完全一样(.),这是明智的,因为它是(.))。

换一种方式来看(用于(双重)确认!),我们可以使用类型签名:

-- general fmap
fmap :: Functor f => (a -> b) -> f a -> f b

-- specialised to the function functor (I've removed the last pair of brackets)
fmap :: (a -> b) -> (r -> a) -> r -> b 

所以首先r需要将类型的值(第三个参数)转换为类型的值a(通过r -> a函数),以便a -> b函数可以将其转换为类型的值b(结果)。

于 2012-04-24T08:36:05.927 回答
26

Functor 中 fmap 的类型是:

fmap :: Functor f => (a -> b) -> f a -> f b

看起来,首先将函数(a -> b)应用于fa的参数以创建b类型的结果,然后将f应用于它,结果为fb

那是 的类型fmap,但是您对该类型含义的解释是错误的。

您似乎假设f a有一个参数,并且该参数具有 type a

考虑xs :: [a]

  • 也许xs = []
  • 也许xs = [x1]
  • 也许xs = [x1, x2]
  • ...

类型 是具有单个类型参数f a的函子。但是type 的不一定采用 形式,正如您从上面的第一种和第三种情况中看到的那样。faf aF x

现在考虑fmap f xs

  • 也许fmap f xs = []
  • 也许fmap f xs = [f x1]
  • 也许fmap f xs = [f x1, f x2]
  • ...

我们不一定适用f(第一种情况)!或者我们可能会多次应用它(第三种情况)。

我们所做的就是用类型的东西替换类型a的东西b。但是我们保留了更大的结构——没有添加新元素,没有删除元素,它们的顺序保持不变。


现在让我们考虑函子(c ->)。(记住,仿函数只接受一个类型参数,所以输入(->)是固定的。)

ac -> a甚至包含一个a? 它可能根本不包含任何as,但是当我们给它一个 s 时,它可以以某种方式凭空变魔术c。但是fmaphas type的结果:当我们看到 a 时,c -> b我们只需要提供a 。bc

所以我们可以说fmap f x = \y -> f (x y)

在这种情况下,我们是f按需应用 --- 每次我们返回的函数被应用f时,也会被应用。

于 2012-04-24T08:50:49.083 回答
20

需要以这种方式定义以使类型起作用。正如您所指出的,类型fmap是:

fmap :: Functor f => (a -> b) -> f a -> f b

让我们考虑函子f((->) c)

注意:我们实际上想把它写成(c ->),即来自 的函数c,但是 Haskell 不允许我们这样做。)

那么f a实际上是((->) c a),它等价于(c -> a),同样对于f b,所以我们有:

fmap :: (a -> b) -> (c -> a) -> (c -> b)

即我们需要采取两个功能:

  • f :: a -> b
  • g :: c -> a

并构造一个新函数

  • h :: c -> b

但是只有一种方法可以做到这一点:你必须先申请g获得类型的东西a,然后申请f获得类型的东西b,这意味着你必须定义

instance Functor ((->) c) where
    fmap f g = \x -> f (g x)

或者,更简洁地说,

instance Functor ((->) c) where
    fmap = (.)
于 2012-04-24T08:41:44.213 回答
6

fmapfor(->)定义为fmap = (.). 所以,(fmap f g) x(f . g) xf (g x)。在您的情况下(*3) ((+100) 1),这等于3 * (100 + 1)结果303

于 2012-04-24T08:34:34.220 回答
1

为了形成一个函数类型,你需要 2 种参数用于 (->),即单输入参数类型和返回类型。

Functor 只能接受 1 个类型参数,因此您必须确定输入参数类型(因为它是从左到右的第一个),这使得函数的返回类型成为 Functor 的类型参数。

所以对于函数(Functor)a->b,你需要给fmap一个b->xxx类型的函数ff而不是a->xxx才能工作,这意味着函数ff只能在a->b之后应用是应用。

于 2018-01-06T09:07:38.583 回答