如何解决fmap (+3) (*3) 不应该等价于 \x -> ((x+3)*3) 吗?
在Learn you a Haskell中,给出了
fmap (+3) (*3)
相当于
\x -> ((x*3)+3))
但是,我不明白为什么。不应该是\x -> ((x+3)*3)
吗?
我不知道 fmap
函子的 (*3)
的实现,但我的直觉告诉我,由于函子 (*3)
等价于 \x -> x * 3
,所以映射 {将首先应用 {1}},然后应用 (+3)
,但反过来也是如此。我在这里错过了什么?
解决方法
我的直觉告诉我,由于函子 (*3) 等价于 \x -> x * 3
函数组成一个函子实例
instance Functor ((->) r) where ...
那些是从 r
映射的函数。
给定一个函数 g :: r -> a
,您可以借助 h :: r -> b
通过 f :: a -> b
形成一个新函数 h = fmap f g
。现在应该清楚 f :: a -> b
不能先应用,而必须第二应用。也就是说 h' = (g :: r -> a) . (f :: a -> b)
没有任何意义,但 h = (f :: a -> b) . (g :: r -> a)
有。
fmap
必须遵守两条法律:
fmap id == id
fmap (f . g) == fmap f . fmap g
您提议的定义 fmap' f g == g . f
满足第一定律但违反第二定律:
fmap' id f == f . id == f == id f -- OK
fmap' (f . g) h == h . (f . g)
== (h . f) . g
== (fmap' f h) . g
== fmap' g (fmap' f h)
== (fmap' g . fmap' f) h -- violation,since (.) is not commutative
正确的定义,fmap f g = f . h
,同时满足:
fmap id f == id . f == f == id f
fmap (f . g) h == (f . g) . h
== f . (g . h)
== fmap f (g . h)
== fmap f (fmap g h)
== (fmap f . fmap g) h
,
一个“函子”,在 Haskell 中,是一个高阶类型,F
,——“高阶”的意思,它接受另一个类型变量,a
(表示 any 输入任何内容),-- 这样我们就可以
F a fa
(a -> b) ab
-----------------
F b fmap ab fa
被称为“flip fmap
”(flip
只是意味着参数的顺序颠倒了,flip fmap fa ab == fmap ab fa
)。它也必须遵循一些“常识”法则。
对于F ~ Maybe
,比如说,这意味着
flip fmap :: Maybe a ->
(a -> b) ->
Maybe b
对于F ~ []
,
flip fmap :: [] a ->
(a -> b) ->
[] b
通常写成 [a] -> (a -> b) -> [b]
。
在我们这里的例子中,F a ~ r -> a
,或更正式地说,F a ~ ((->) r) a
,意思是 F ~ ((->) r)
,
flip fmap :: ((->) r) a ->
(a -> b) ->
((->) r) b
通常写成 (r -> a) -> (a -> b) -> (r -> b)
,
r -> a
a -> b
-------------
r -> b
与 (r -> a) -> (a -> b) -> r -> b
相同,因为对于类型,箭头在右侧关联,对应于应用程序在左侧关联的事实:f a b c
实际上是 ((f a) b) c
和>
f a b c = d -- f a b c
f a b = \c -> d -- (f a b) c
f a = \b c -> d -- ((f a) b) c
f = \a b c -> d -- (((f) a) b) c
都是写下同一个定义的不同方式,写下同一个函数调用的不同方式。
这意味着我们需要实现
fmap :: (a -> b) -> (r -> a) -> (r -> b)
fmap ab ra r = b
where
b =
那么定义是什么?由我们来解码去哪里?好吧,我们必须生成一个 b
类型的值。我们唯一可以为我们做的就是ab :: a -> b
。
没有它我们能生成一个 b
吗?出乎意料?除了出错之外,不,我们不能——我们对 b
类型一无所知。它可以是任何东西。所以我们只剩下
b = ab a
a =
现在我们必须在某处获得一个 a
,以将其用作 ab
的参数。幸运的是,ra
可以给我们:
a = ra r
和r
,我们已经得到了!所以类型确实为我们编写了这个实现:
fmap :: (a -> b) -> (r -> a) -> (r -> b)
fmap ab ra r = b
where
b = ab a
a = ra r
或者,简化和重命名,我们得到
fmap f g r = f ( g r)
= (f . g) r
根据函数组合的定义,.
,as
(.) :: (a -> b) -> (r -> a) -> (r -> b)
(f . g) r = f (g r)
这是一个有效的语法定义,否则写成
(.) :: (a -> b) -> (r -> a) -> (r -> b)
(.) f g r = f (g r)
或
(.) :: (a -> b) -> (r -> a) -> (r -> b)
(.) f g = \ r -> f (g r)
或
(.) :: (a -> b) -> (r -> a) -> (r -> b)
(.) = \f g r -> f (g r)
所有这些都是等价的。及其类型图
a -> b
r -> a
--------------
r -> b
就直觉而言,F A
类型的函子类型值松散地是一个 F
类型的“东西”,它可以以某种方式产生一个 {{1} } - 输入一些东西,在某种 A
类型的意义上。
函子 laws 意味着 F
以某种纯粹的“结构性”、机械方式这样做,而不考虑它实际产生的 F
值是什么。换句话说,A
值不会影响它们的生成方式,只有 A
类型本身决定了这一点。
例如,F
可以 Maybe Int
产生 Maybe
。或者 Int
可以产生多个 [Int]
。 Int
也可以产生一个 (*3)
,如果我们为它提供一个 Int
参数。
那么这个 Int
是什么?它有什么作用?它转化将要产生的价值。每个函子类型都必须定义它的 fmap
,这就是使它成为一个函子类型的原因,它定义了
fmap
等等。那么,使用函数 instance Functor Maybe where
fmap ab (Just a) = (Just (ab a))
,产生由其类型承诺的 r -> a
类型值,在应用于参数后,我们通过将转换函数应用于它来转换该值:
a
这只是函数组合本身的定义,重命名了参数。
这就是为什么,在这种情况下,
fmap transf mult3 arg = tansf (mult3 arg)
我们 fmap (+3) (*3) r = (+3) ((*3) r)
= (+3) (r*3)
= (r*3) + 3
将(+3)
产生的值转换为(*3)
意义上的应用到一些用户提供的参数,((->) r)
。因此,必须首先应用 r
,以获取(产生)该值。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。