函数组合运算符(。)和fmap(< $>)之间的差异 [英] Difference between function composition operator (.) and fmap (<$>)

查看:108
本文介绍了函数组合运算符(。)和fmap(< $>)之间的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前阅读这篇文章(这是漂亮的btw),并有一个非常简单的问题:

如果我将(+ 3)(+ 2)< $> ,它似乎给了我一个新的函数,传递给它。如果我对函数组合操作符做同样的操作,即(+ 3)。 (+2),它不会做同样的事情吗?如果那是真的,这两个操作员之间是否存在关系,这样他们在这个简单情况下做同样的事情?



这是一个聪明的问题吗?

解决方案

函数 fmap < $> ; 都具有相同的类型:

 > :t fmap 
fmap :: Functor f => (a - > b) - > f a - > f b
> :t(< $>)
(< $>):: Functor f => (a - > b) - > f a - > fb

虽然函数 p>

 > :t(。)
(。)::(b - > c) - > (a - > b) - > a - > c

那么我们怎么可能使用 fmap 放在一个函数上,最后加上?我假设你明白Functor是什么,所以现在你必须明白功能是Functor。怎么样?

 > ( - >)
数据( - >)ab - 在'GHC.Prim'中定义
实例Monad(( - >)r) - 定义于`GHC.Base'
实例Functor(( - >)r) - 在`GHC.Base'中定义
实例应用(( - >)a) - 在Control.Applicative中定义

不像只是, [] Left ,函数没有可以使用的构造函数。 Functor实例应用于语法本身。我们可以从ghci的info中看到,语法箭头 - > 实际上有一个functor的实例



当我们查看+3类型时会发生什么?

 > :t(+3)
(+3):: Num a => a - >一个

所以函数(+3)是一个Functor,它接受一个a并返回一个a。当我们在Functor上使用 fmap 时,我们得到了一个Functor,我们得到了嵌套的Functors:

 > :t fmap Just(Just 3)
fmap Just(Just 3):: Num a =>也许(也许是)
> :t fmap(replicate 5)[1,2,3]
fmap(replicate 5)[1,2,3] :: Num a =>同样,当我们应用 fmap

$ c>给两个函数,我们在函数中获得一个函数。唯一的区别是它们融合在一起:

 > :t(fmap(+3)(+2))
(fmap(+3)(+2)):: Num a => a - > a

为什么这不会导致( - >) ( - >)aa ?我们必须记住, fmap 的第一个参数是一个函数(a - > b)不一定是一个Functor。所以当我们做 fmap g(Just 5)时,我们可以进行任何转换。但是每当我们在一个函数上执行 fmap 时,我们知道它总是总是结果带有一个函数内部的函数。



因此 fmap(+3)(+2)的计算结果如下: \x - > (\ x' - > x'+ 3)(x + 2)。这是写作(+ 3)的非常迂回的方式。 (+2)

 > :t(fmap(+3)(+2))
(fmap(+3)(+2)):: Num a => a - > a
> :((。)(+3)(+2))
((。)(+3)(+2)):: Num a => a - > a

通常解决concat问题(Maybe(Maybe a)) [[a]] 我们实际上需要依靠它作为 Monad a ,以便我们可以使用绑定>> = 。但函数( - >)是一个特例,因为我们知道每次我们在函数上使用 fmap ,它总会给我们一个函数的功能。对于除 - > 之外的其他任何Functor都不能这么说。因此,我们可以确保总是在函数上连接 fmap

因此,任何 f < $> g == f。 g



编辑:快速提示,如果您这样做 fmap(+)(+0) code>你最终得到一个函数内的函数。在这种情况下,实际需要一元绑定(>> = )来连接函数:

 > :t fmap(+)(+0)
fmap(+)(+0):: Num a => a - > a - > a
> :t(+0)> =(+)
(+0)> =(+):: Num b => b - > b
>让bindfunc =(+0)>> =(+)
> bindfunc 5
10

这与我们在执行<$时得到的行为并不完全不同c $ c> [1,2]>> =复制5

 > [1,2]>> =复制品5 
[1,1,1,1,1,2,2,2,2,2]


Currently reading through this article (which is pretty brilliant btw) and have a pretty simple question:

If I combine two functions like (+3) and (+2) with <$>, it seems to give me a new function that adds 5 to whatever is passed to it. If I do the same with the function composition operator, i.e. (+3) . (+2), would it not do the same thing? If that is true, is there a relationship here between these two operators such that they do the same thing in this simple case?

Is this even an intelligent question?

解决方案

The functions fmap and <$> both have the same type:

> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
> :t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b

While the function . is

> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

So how is it possible that we can use fmap on a function and end up with .? I'm assuming you understand what a Functor is, so now you have to understand that "functions" are Functors. How so?

> :i (->)
data (->) a b   -- Defined in `GHC.Prim'
instance Monad ((->) r) -- Defined in `GHC.Base'
instance Functor ((->) r) -- Defined in `GHC.Base'
instance Applicative ((->) a) -- Defined in `Control.Applicative'

Unlike Just, [] and Left, functions do not have a constructor that can be used. The Functor instance is applied to the syntax itself. We can see from :info in ghci that the syntactic arrow -> actually has an instance for functor.

What happens when we look at the type of +3?

> :t (+3)
(+3) :: Num a => a -> a

So the function (+3) is a Functor that accepts an a and returns an a. When we use fmap on a Functor and that also gives us back a Functor, we get nested Functors:

> :t fmap Just (Just 3)
fmap Just (Just 3) :: Num a => Maybe (Maybe a)
> :t fmap (replicate 5) [1,2,3]
fmap (replicate 5) [1,2,3] :: Num a => [[a]]

Likewise, when we apply fmap to two functions we get a function inside a function. The only difference is that they are fused together:

> :t (fmap (+3) (+2))
(fmap (+3) (+2)) :: Num a => a -> a

Why doesn't this result in the type (->) (->) a a? We have to remember that the first argument of fmap is a function (a -> b) and not necessarily a Functor. So when we do fmap g (Just 5) we can have any transformation. But whenever we perform fmap on a function we know that it will always result with a function inside of a function.

Thus fmap (+3) (+2) evaluates to something like this: \x -> (\x' -> x' + 3) (x + 2). That is a really roundabout way of writing (+3) . (+2).

> :t (fmap (+3) (+2))
(fmap (+3) (+2)) :: Num a => a -> a
> :t ((.) (+3) (+2))
((.) (+3) (+2)) :: Num a => a -> a

Normally to get around the concat problem (Maybe (Maybe a)) or [[a]] we actually need to rely on it being a Monad a, so that we can use a bind >>=. But functions (->) are a special case because we know that every single time we use fmap on a function, it will always give us a function in side of a function. This cannot be said for any other Functor except ->. As such we can be sure to always concatenate fmap on functions.

Therefore any f <$> g == f . g

Edit: A quick side note, if you do this fmap (+) (+0) you end up with a function inside a function. In this case the monadic bind (>>=) is actually needed to concatenate the functions:

> :t fmap (+) (+0)
fmap (+) (+0) :: Num a => a -> a -> a
> :t (+0) >>= (+)
(+0) >>= (+) :: Num b => b -> b
> let bindfunc = (+0) >>= (+)
> bindfunc 5
10

Which is not entirely unlike the behaviour we get when we do [1,2] >>= replicate 5:

> [1,2] >>= replicate 5
[1,1,1,1,1,2,2,2,2,2]

这篇关于函数组合运算符(。)和fmap(&lt; $&gt;)之间的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆