简体   繁体   English

混淆功能作为haskell中Functor的实例

[英]confused about function as instance of Functor in haskell

the type of fmap in Functor is: Functor中的fmap类型是:

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

it looks like ,first apply function (a -> b) to the parameter of fa to create a result of type b, then apply f to it, and result is fb 看起来,首先将函数(a - > b)应用到fa的参数以创建类型b的结果,然后对其应用f,结果为fb

using Maybe a for example : 使用Maybe a例如:

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

same as saying: 同说:

Just (show 1)

but when (->) is used as a Functor (in Control.Monad.Instances) 但是当( - >)用作Functor时(在Control.Monad.Instances中)

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

that is, Just is apply first, then show is applied. 也就是说,Just首先应用,然后显示应用。 in another example ,result is same: 在另一个例子中,结果是相同的:

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

why not *3 first, then +100? 为什么不* 3先,然后+100?

The fmap instance for (->) r (ie functions) is literally just composition. (->) r (即函数)的fmap实例实际上只是组合。 From the source itself : 源本身

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

So, in your example, we can just replace fmap with (.) , and do some transformations 因此,在您的示例中,我们可以用(.)替换fmap ,并进行一些转换

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

That is, fmap for functions composes them right to left (exactly the same as (.) , which is sensible because it is (.) ). 也就是说,函数的fmap从右到左组成(与(.)完全相同,这是明智的,因为它是(.) )。

To look at it another way (for (double) confirmation!), we can use the type signature: 另一种方式(对于(双重)确认!),我们可以使用类型签名:

-- 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 

So first the value of type r (the third argument) needs to be transformed into a value of type a (by the r -> a function), so that the a -> b function can transform it into a value of type b (the result). 所以首先需要将类型r (第三个参数)的值转换为类型a的值(通过r -> a函数),以便a -> b函数可以将其转换为类型b的值(结果)。

the type of fmap in Functor is: Functor中的fmap类型是:

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

it looks like ,first apply function (a -> b) to the parameter of fa to create a result of type b, then apply f to it, and result is fb 看起来,首先将函数(a - > b)应用到fa的参数以创建类型b的结果,然后对其应用f,结果为fb

That is the type of fmap , but your interpretation of what that type means is wrong. 这是fmap的类型,但是你对这种类型的解释是错误的。

You seem to assume that fa has one parameter, and that that parameter has type a . 您似乎假设fa有一个参数,并且该参数的类型为a

Consider xs :: [a] : 考虑xs :: [a]

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

The type fa is a functor f with a single type parameter a . 类型 fa是具有单个类型参数a的仿函数f But values of type fa do not necessarily take the form F x , as you can see from the first and third cases above. 但是fa类型的不一定采用F x的形式,正如您从上面的第一和第三种情况中可以看到的那样。

Now consider fmap f xs : 现在考虑fmap f xs

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

We don't necessarily apply f at all (first case)! 我们根本不一定申请f (第一种情况)! Or we might apply it more than once (third case). 或者我们可以多次应用它(第三种情况)。

What we do is replace the things of type a , with things of type b . 我们所做的是用类型b的东西替换类型a东西。 But we leave the larger structure intact --- no new elements added, no elements removed, their order is left unchanged. 但是我们保留了较大的结构 - 没有添加新元素,没有删除元素,它们的顺序保持不变。


Now let's think about the functor (c ->) . 现在让我们考虑一下仿函数(c ->) (Remember, a functor takes one type parameter only, so the input to (->) is fixed.) (请记住,仿函数只接受一个类型参数,因此(->)的输入是固定的。)

Does a c -> a even contain an a ? c -> a是否包含a It might not contain any a s at all, but it can somehow magic one out of thin air when we give it a c . 它可能根本不包含任何a s,但是当我们给它一个c时,它可以用某种方式用空气来魔术。 But the result from fmap has type c -> b : we only have to provide a b out of that when we're presented with a c . 但是fmap的结果是类型c -> b :当我们看到c时,我们只需要提供一个b

So we can say fmap fx = \\y -> f (xy) . 所以我们可以说fmap fx = \\y -> f (xy)

In this case, we're applying f on demand --- every time the function we return gets applied, f gets applied as well. 在这种情况下,我们按需应用f - 每次返回我们返回的函数时, f也会被应用。

It needs to be defined that way to make the types work out. 需要定义它以使类型工作。 As you pointed out, the type of fmap is: 正如您所指出的, fmap的类型是:

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

Let's consider the case when the functor f is ((->) c) 让我们考虑仿函数f((->) c)

( Note: we'd actually like to write this as (c ->) , ie functions from c , but Haskell doesn't allow us to do this.) 注意:我们实际上想把它写成(c ->) ,即来自c函数,但是Haskell不允许我们这样做。)

Then fa is actually ((->) ca) , which is equivalent to (c -> a) , and similarly for fb , so we have: 那么fa实际上是((->) ca) ,相当于(c -> a) ,同样对于fb ,所以我们有:

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

ie we need to take two functions: 即我们需要采取两个功能:

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

and construct a new function 并构建一个新的功能

  • h :: c -> b

But there's only one way to do that: you have to apply g first to get something of type a , and then apply f to get something of type b , which means that you have to define 但是只有一种方法可以做到这一点:你必须首先应用g来获得类型为a东西,然后应用f来获得类型为b东西,这意味着你必须定义

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

or, more succinctly, 或者,更简洁,

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

fmap for (->) is defined like fmap = (.) . fmap(->)被定义像fmap = (.) So, (fmap fg) x is (f . g) x is f (gx) . 因此, (fmap fg) x(fmap fg) x (f . g) xf (gx) In your case (*3) ((+100) 1) , which equals 3 * (100 + 1) which results in 303 . 在你的情况下(*3) ((+100) 1) ,等于3 * (100 + 1) ,结果为303

In order to form a function type, you need 2 kind parameters for (->), that is the single input argument type and the return type. 为了形成函数类型,( - >)需要2种参数,即单输入参数类型和返回类型。

A Functor can only take 1 type parameter, so you have to nail down the input argument type(since it's the first one from left to right), which makes the return type of the function to be the type parameter of the Functor. Functor只能接受1个类型参数,因此您必须确定输入参数类型(因为它是从左到右的第一个),这使得函数的返回类型成为Functor的类型参数。

So for function (the Functor) a->b, you need to give fmap a function ff of type b->xxx other than a->xxx to work, and that means the function ff can only be applied after a->b is apply. 所以对于函数(Functor)a-> b,你需要给fmap一个类型为b-> xxx的函数ff而不是a-> xxx才能工作,这意味着函数ff只能在a-> b之后应用适用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM