[英]confused about function as instance of Functor in haskell
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)
但是当( - >)用作Functor时(在Control.Monad.Instances中)
import Control.Monad.Instances
(fmap show Just) 1
result is : "Just 1"
也就是说,Just首先应用,然后显示应用。 在另一个例子中,结果是相同的:
fmap (*3) (+100) 1
result is 303
为什么不* 3先,然后+100?
(->) r
(即函数)的fmap
实例实际上只是组合。 从源本身 :
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
的值(通过r -> a
函数),以便a -> b
函数可以将其转换为类型b
的值(结果)。
Functor中的fmap类型是:
fmap :: Functor f => (a -> b) -> fa -> fb
看起来,首先将函数(a - > b)应用到fa的参数以创建类型b的结果,然后对其应用f,结果为fb
这是fmap
的类型,但是你对这种类型的解释是错误的。
您似乎假设fa
有一个参数,并且该参数的类型为a
。
考虑xs :: [a]
:
xs = []
。 xs = [x1]
。 xs = [x1, x2]
。 类型 fa
是具有单个类型参数a
的仿函数f
。 但是fa
类型的值不一定采用F x
的形式,正如您从上面的第一和第三种情况中可以看到的那样。
现在考虑fmap f xs
:
fmap f xs = []
。 fmap f xs = [f x1]
。 fmap f xs = [f x1, f x2]
。 我们根本不一定申请f
(第一种情况)! 或者我们可以多次应用它(第三种情况)。
我们所做的是用类型b
的东西替换类型a
东西。 但是我们保留了较大的结构 - 没有添加新元素,没有删除元素,它们的顺序保持不变。
现在让我们考虑一下仿函数(c ->)
。 (请记住,仿函数只接受一个类型参数,因此(->)
的输入是固定的。)
c -> a
是否包含a
? 它可能根本不包含任何a
s,但是当我们给它一个c
时,它可以用某种方式用空气来魔术。 但是fmap
的结果是类型c -> b
:当我们看到c
时,我们只需要提供一个b
。
所以我们可以说fmap fx = \\y -> f (xy)
。
在这种情况下,我们按需应用f
- 每次返回我们返回的函数时, f
也会被应用。
需要定义它以使类型工作。 正如您所指出的, fmap
的类型是:
fmap :: Functor f => (a -> b) -> f a -> f b
让我们考虑仿函数f
为((->) c)
( 注意:我们实际上想把它写成(c ->)
,即来自c
函数,但是Haskell不允许我们这样做。)
那么fa
实际上是((->) ca)
,相当于(c -> a)
,同样对于fb
,所以我们有:
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 = (.)
fmap
为(->)
被定义像fmap = (.)
因此, (fmap fg) x
是(fmap fg) x
(f . g) x
是f (gx)
。 在你的情况下(*3) ((+100) 1)
,等于3 * (100 + 1)
,结果为303
。
为了形成函数类型,( - >)需要2种参数,即单输入参数类型和返回类型。
Functor只能接受1个类型参数,因此您必须确定输入参数类型(因为它是从左到右的第一个),这使得函数的返回类型成为Functor的类型参数。
所以对于函数(Functor)a-> b,你需要给fmap一个类型为b-> xxx的函数ff而不是a-> xxx才能工作,这意味着函数ff只能在a-> b之后应用适用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.