Functor中的fmap类型是:
fmap :: Functor f => (a -> b) -> f a -> f b
看起来,首先将函数(a - > b)应用于f a的参数以创建类型b的结果,然后对其应用f,结果为f b
使用Maybe a例如:
fmap show (Just 1)
result is : Just "1"
同如:
Just (show 1)
但是当( - >)用作Functor时(在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?
答案 0 :(得分:32)
fmap
的{{1}}实例(即函数)实际上只是组合。来自the source itself:
(->) 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)
从右到左组成(与fmap
完全相同,这是明智的,因为它是(.)
)。
以另一种方式查看(对于(双重)确认!),我们可以使用类型签名:
(.)
首先,类型-- 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
函数),以便{{1函数可以将其转换为类型r -> a
的值(结果)。
答案 1 :(得分:26)
Functor中的fmap类型是:
fmap :: Functor f => (a -> b) -> f a -> f b
看起来,首先将函数(a - > b)应用于f a的参数 要创建类型b的结果,然后对其应用f,结果为f b
这是fmap
的类型,但您对该类型的解释是错误的。
您似乎认为f a
有一个参数,并且该参数的类型为a
。
考虑xs :: [a]
:
xs = []
。xs = [x1]
。xs = [x1, x2]
。 类型 f a
是一个带有单个参数f
的仿函数a
。但是f a
类型的值不一定采用F x
形式,正如您从上面的第一个和第三个案例中可以看到的那样。
现在考虑fmap f xs
:
fmap f xs = []
。fmap f xs = [f x1]
。fmap f xs = [f x1, f x2]
。我们根本不一定适用f
(第一种情况)!或者我们可以多次应用它(第三种情况)。
我们所做的是将a
类型的内容替换为b
类型的内容。但是我们保留了较大的结构 - 没有添加新元素,没有删除元素,它们的顺序保持不变。
现在让我们考虑一下仿函数(c ->)
。 (请记住,仿函数只接受一个类型参数,因此(->)
的输入是固定的。)
c -> a
是否包含a
?它可能根本不包含任何a
,但是当我们给它c
时它可以用某种方式用神奇的方法来制造它。但fmap
的结果类型为c -> b
:当我们看到b
时,我们只需要提供c
。
所以我们可以说fmap f x = \y -> f (x y)
。
在这种情况下,我们按需应用f
- 每次我们返回的函数都被应用时,f
也会被应用。
答案 2 :(得分:17)
需要以这种方式定义以使类型成功。正如您所指出的,fmap
的类型是:
fmap :: Functor f => (a -> b) -> f a -> f b
让我们考虑仿函数f
为((->) c)
(注意:我们实际上想把它写成(c ->)
,即来自c
的函数,但Haskell不允许我们这样做。)< / p>
然后f a
实际上是((->) c a)
,相当于(c -> a)
,同样适用于f b
,所以我们有:{/ p>
fmap :: (a -> b) -> (c -> a) -> (c -> b)
即。我们需要承担两个功能:
f :: a -> b
g :: c -> a
并构建一个新函数
h :: c -> b
但是只有一种方法可以做到这一点:您必须首先应用g
来获取a
类型的内容,然后应用f
来获取{{1}类型的内容},这意味着你有来定义
b
或者,更简洁,
instance Functor ((->) c) where
fmap f g = \x -> f (g x)
答案 3 :(得分:5)
fmap
的{{1}}定义为(->)
。
因此,fmap = (.)
(fmap f g) x
是(f . g) x
。在您的情况f (g x)
中,等于(*3) ((+100) 1)
,结果为3 * (100 + 1)
。
答案 4 :(得分:1)
为了形成函数类型,( - &gt;)需要2种参数,即单输入参数类型和返回类型。
一个Functor只能接受一个类型参数,所以你必须确定输入参数类型(因为它是从左到右的第一个),这使得函数的返回类型成为类型Functor的参数。
因此对于函数(Functor)a-> b,你需要给fmap一个类型为b-&gt; xxx的函数ff而不是a-&gt; xxx才能工作,这意味着函数ff只能是在应用a-&gt; b之后应用。