将参数映射到函数 - fmap($ 3)(4+)

时间:2018-04-04 11:51:11

标签: haskell

在Learn You Haskell书中阅读Function application with $我找到了将$应用于函数列表的示例。

map ($ 3) [(4+), (10*), (^2), sqrt]

我想尝试类似的事情并减少应用于一个功能的例子

fmap ($ 3) (4+) 

但我收到的错误是我不明白的

• Non type-variable argument in the constraint: Num (a -> b)
  (Use FlexibleContexts to permit this)
• When checking the inferred type
    it :: forall a b. (Num (a -> b), Num a) => (a -> b) -> b

你能帮助我理解为什么它在第一种情况下起作用但它不在第二种情况下吗?我怎样才能达到预期的效果?

谢谢

3 个答案:

答案 0 :(得分:6)

在第一个示例中,您需要map,因为您有一个完整的容器,并且每个要应用于该数字。在该示例中,您确实可以将map替换为fmapPrelude> fmap ($ 3) [(4+), (10*), (^2), sqrt] -- list functor [7.0,30.0,9.0,1.7320508075688772] Prelude> fmap ($ 3) (Just (4+)) -- `Maybe` functor Just 7 Prelude> fmap ($ 3) (do y<-readLn; return (y+)) -- `IO` functor > 100 103 适用于任何容器(在任何仿函数上)。

(4+)

但是,fmap本身并不是包含在任何仿函数中的函数,它本身只是一个函数。所以,你真的不需要任何Prelude> ($ 3) (4+) 7

4+3

当然,您可以进一步简化fmap ...

如果出于某种原因,您确实需要使用Prelude> :m +Data.Functor.Identity Prelude Data.Functor.Identity> fmap ($ 3) (Identity (4+)) Identity 7 ,无论,您需要它在身份仿函数中运行:

Identity

身份仿函数是一个非常无聊的容器,总是只包含一个元素

这不是不切实际的BTW:在Haskell中,我们希望尽可能保持代码的通用性。你可能有一个能够处理任意仿函数的函数(更常见的是,任意的 monads ,它们是特殊的仿函数)但是可能想要在的简单上下文中使用它只包含一个元素。或者,您可能希望将不同的monad功能堆叠为 monad transformers ;那么你通常会以<button class="btn btn-standard" name="refresh" (click)="simpleForm.reset()">Refresh</button> <button class="btn btn-standard" name="submit" [disabled]="!simpleForm.form.valid" (click)="doAction()">Submit</button> 作为“香草单子”开始。

答案 1 :(得分:2)

我想说的主要问题是你的(4 +)没有在仿函数中正确包装。如果您检查了fmap的类型:

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

在第一个示例中,所有函数都包含在列表中。如果您将(4 +)更改为[ (4 +) ],则会有效。

关于仿函数的解释,您可能会在线找到更多文档(或在评论部分:D感谢您的反馈)

答案 2 :(得分:2)

fmap将函数应用于某些函数值中的值。在fmap ($ 3) [(4+), (10*), (^2), sqrt]中,列表是functorial值,函数($ 3)应用于其元素。至于fmap ($ 3) (4+)leftaroundabout correctly points out

  

但是,(4+)本身并不是包含在任何仿函数中的函数,它本身只是一个函数。

在这种情况下,有一种互补的方式来看待它。 (4+)是一个函数值;然而,算子并不是你需要的那个。函数是仿函数,并且出于fmap的目的,它们中的值&#34;和#34;是函数的结果:

GHCi> :set -XTypeApplications
GHCi> :t fmap @((->) _)
fmap @((->) _) :: (a -> b) -> (w -> a) -> w -> b
函数的

fmap将函数应用于另一个函数的结果,这相当于函数组合。所以这......

GHCi> fmap (4*) (2+) 1
12

...与:

相同
GHCi> ((4*) . (2+)) 1
12

在您的情况下,我们有:

GHCi> :t (4+)
(4+) :: Num a => a -> a

因此fmap f (4+)会将f应用于Num a => a的{​​{1}}结果。但(4+)的类型是:

($ 3)

所以GHCi> :t ($ 3) ($ 3) :: Num a => (a -> b) -> b 会期望在其中找到函数的函数值:

fmap ($ 3)

总而言之,我们得到:

GHCi> :t fmap ($ 3)
fmap ($ 3) :: (Num a, Functor f) => f (a -> b) -> f b

这将导致类型错误与GHCi> :t fmap ($ 3) (4+) fmap ($ 3) (4+) :: (Num (a -> b), Num a) => (a -> b) -> b 约束有关。如果在Num (a -> b)中找到了函数,则(4+)本身必须是函数。由于4是数字文字,因此其类型也必须是4的实例。但是,函数没有Num个实例。尝试Num会导致错误提及fmap ($ 3) (4+)。这应该表明有些事情已经结束:

Num (a -> b)

&#34;非类型变量参数&#34;然而,投诉是一种分散注意力,由数字文字引起的多态性。我们可以通过启用GHCi> fmap ($ 3) (4+) <interactive>:33:1: error: * Non type-variable argument in the constraint: Num (a -> b) (Use FlexibleContexts to permit this) * When checking the inferred type it :: forall a b. (Num (a -> b), Num a) => (a -> b) -> b 然后尝试使用FlexibleContexts(由于默认规则导致fmap ($ 3) (4+)专门用于Num a => a)来获得更直接的错误。 ..

Integer

...或通过类型注释专门化数字类型:

GHCi> :set -XFlexibleContexts
GHCi> fmap ($ 3) (4+) (2*)

<interactive>:39:1: error:
    * No instance for (Num (Integer -> Integer))
        arising from a use of `it'
        (maybe you haven't applied a function to enough arguments?)
    * In the first argument of `print', namely `it'
      In a stmt of an interactive GHCi command: print it