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

诺 铁*_*诺 铁 23 haskell functor

Functor中的fmap类型是:

fmap :: Functor f => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

看起来,首先将函数(a - > b)应用于fa的参数以创建类型b的结果,然后对其应用f,结果为fb

使用Maybe a例如:

 fmap show (Just 1)
 result is : Just "1"
Run Code Online (Sandbox Code Playgroud)

同说:

Just (show 1)
Run Code Online (Sandbox Code Playgroud)

但是当( - >)用作Functor时(在Control.Monad.Instances中)

import Control.Monad.Instances
(fmap show Just) 1
result is : "Just 1"
Run Code Online (Sandbox Code Playgroud)

也就是说,Just首先应用,然后显示应用.在另一个例子中,结果是相同的:

 fmap (*3) (+100) 1
 result is 303
Run Code Online (Sandbox Code Playgroud)

为什么不*3先,然后+100?

huo*_*uon 33

(即函数)的fmap实例(->) r实际上只是组合.从源本身:

instance Functor ((->) r) where
    fmap = (.)
Run Code Online (Sandbox Code Playgroud)

所以,在你的榜样,我们就可以代替fmap(.),并做一些转换

fmap (*3) (+100) 1 => 
(.) (*3) (+100) 1  =>
(*3) . (+100) $ 1  => -- put (.) infix
(*3) (1 + 100)     => -- apply (+100)
(1 + 100) * 3         -- apply (*3)
Run Code Online (Sandbox Code Playgroud)

也就是说,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 
Run Code Online (Sandbox Code Playgroud)

所以首先r需要将type (第三个参数)的值转换为类型的值a(通过r -> a函数),以便a -> b函数可以将其转换为类型的值b(结果).


dav*_*420 26

Functor中的fmap类型是:

fmap :: Functor f => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

看起来,首先将函数(a - > b)应用于fa的参数以创建类型b的结果,然后对其应用f,结果为fb

这是类型fmap,但你对这种类型的解释是错误的.

您似乎假设f a有一个参数,并且该参数具有类型a.

考虑xs :: [a]:

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

类型 f af具有单个类型参数的仿函数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?它可能根本不包含任何as,但是当我们给它一个时,它可以以某种方式用空气来魔术c.但是从结果fmap具有类型c -> b:我们只需要提供b出的,当我们提出了一个c.

所以我们可以说fmap f x = \y -> f (x y).

在这种情况下,我们f按需应用---每当我们返回的函数被应用时,f也会应用.

  • 是的,您的答案很棒!我犯了个大错误。非常感谢你。 (2认同)

Chr*_*lor 17

需要被定义的方式,使各类工作了.正如您所指出的那样,类型fmap是:

fmap :: Functor f => (a -> b) -> f a -> f b
Run Code Online (Sandbox Code Playgroud)

让我们考虑仿函数的f情况((->) c)

(注意:我们实际上喜欢将其写为(c ->),即函数c,但Haskell不允许我们这样做.)

那么f a实际上((->) c a),这相当于(c -> a),同样f b如此,所以我们有:

fmap :: (a -> b) -> (c -> a) -> (c -> b)
Run Code Online (Sandbox Code Playgroud)

即我们需要采取两个功能:

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

并构建一个新的功能

  • h :: c -> b

但是只有一种方法可以做到这一点:你必须首先申请g获得类型的东西a,然后申请f获得类型的东西b,这意味着你必须定义

instance Functor ((->) c) where
    fmap f g = \x -> f (g x)
Run Code Online (Sandbox Code Playgroud)

或者,更简洁,

instance Functor ((->) c) where
    fmap = (.)
Run Code Online (Sandbox Code Playgroud)


phi*_*ler 6

fmapfor (->)定义为fmap = (.).所以,(fmap f g) x(f . g) xf (g x).在你的情况下(*3) ((+100) 1),等于3 * (100 + 1)导致的结果303.