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

时间:2012-04-24 08:24:07

标签: haskell functor

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?

5 个答案:

答案 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之后应用。