简体   繁体   English

部分应用的函数类型 (a ->) 作为 Haskell 中的 Functor 实例

[英]Partially applied function type (a ->) as Functor instance in Haskell

I'm going through the "Programming in Haskell" book (second edition) and just stumbled across exercise 2, chapter 12, part 2:我正在阅读“Haskell 编程”一书(第二版),偶然发现了练习 2,第 12 章,第 2 部分:

instance Functor ((->) a) where
  fmap = TODO

where the answer is:答案是:

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

It got me scratching my head for a good while.这让我挠了好一阵子。 I guess it does make sense to me on an intuitive level (partially applied function type a -> is a functor when composition is its fmap ), but I think some good examples would solidify my understanding of the exercise.我想这在直观层面上对我来说确实有意义(部分应用的函数类型a ->是一个函子,当组合是它的fmap ),但我认为一些很好的例子会巩固我对这个练习的理解。

I came up with these two:我想出了这两个:

main = do
    putStrLn . show $ (fmap (+1) (*2)) (5 :: Int)
    putStrLn . show $ (fmap (show) (+1)) 3

Do my examples correctly illustrate the exercise?我的例子是否正确地说明了练习?

fmap given two arguments: fmap给出了两个参数:

  • partially applied function (the function)部分应用函数(函数)
  • another partially applied function (the functor)另一个部分应用的函数(函子)

UPDATE更新

fmap given two arguments: fmap给出了两个参数:

  • function (the function)功能(功能)
  • another function (the functor)另一个函数(函子)

just looks strange to me and I'm not sure I got the concept right.对我来说只是看起来很奇怪,我不确定我的概念是否正确。

I see some similar questions on SO (like eg this one ) where this one is almost what I'm looking for, but not quite (I'm just looking for examples of functors and nothing else - no applicatives and no monads).我在 SO 上看到了一些类似的问题(例如this one ),其中这个问题几乎是我正在寻找的,但并不完全(我只是在寻找函子的例子,没有别的 - 没有应用程序和单子)。

There's really nothing more to it than that, for a functor f , the implementation of fmap (there is known to be at most one implementation for any possible f ) has to have type (a -> b) -> fa -> fb , and satisfy the two functor laws:没有什么比这更重要的了,对于函子ffmap的实现(已知对于任何可能的f最多只有一个实现)必须具有类型(a -> b) -> fa -> fb ,并满足两个函子定律:

fmap id = id
fmap (g . h) = fmap g . fmap h

When f is the type constructor (->) r - that is when fa means r -> a - then the needed type signature is:f是类型构造函数(->) r - 即当fa表示r -> a - 那么所需的类型签名是:

(a -> b) -> (r -> a) -> (r -> b)

(the last pair of parentheses there is unnecessary, but I've left them in because it makes the "pattern" easier to see), which it is easy to see is exactly the signature of the (.) operator. (最后一对括号是不必要的,但我把它们留在了,因为它使“模式”更容易看到),很容易看到,这正是(.)运算符的签名。

As for the two laws, it's pretty obvious that they must hold when you write down what they're saying.至于这两条定律,很明显,当你写下它们所说的话时,它们必须成立。 I'll prove them by writing everything out in painstaking detail:我将通过详细地写出所有内容来证明它们:

fmap id = (.) id
        = \g -> id . g
        = \g -> (\a -> id (g a))
        = \g -> (\a -> g a)
        = \g -> g
        = id

and

fmap (g . h) = (.) (g . h)
             = \g1 -> (g . h) . g1
             = \g1 -> \a -> ((g . h) . g1) a
             = \g1 -> \a -> g (h (g1 a))

(fmap g) . (fmap h) = ((.) g) . ((.) h)
                    = \g1 -> ((.) g) (h . g1)
                    = \g1 -> g . h . g1
                    = \g1 -> \a -> g (h (g1 a))

so those are also the same.所以那些也是一样的。

(Don't worry too much about that last derivation - often such things might seem hard to follow the logic of how to get from one line to the next, even though here they're all basically using the definition of composition. It's really just expression the obvious and well-known fact that function composition is associative. And in any case, it's a general result that, except I believe for certain pathological types, if the first functor law is satisfied then the second one will always be automatically satisfied.) (不要太担心最后的推导——通常这样的事情似乎很难遵循如何从一行到下一行的逻辑,即使在这里它们基本上都使用组合的定义。这真的只是表达了显而易见的众所周知的事实,即函数组合是结合的。无论如何,这是一个普遍的结果,除了我相信对于某些病理类型,如果满足第一个函子定律,那么第二个将始终自动满足。 )

The important thing is: when f is defined as fa = r -> a , then the composition operator has the same type as fmap , and satisfies both functor laws - therefore composition is a legal definition (and the only such definition) of fmap to make a Functor instance for f .重要的是:当f被定义为fa = r -> a ,则该组合物操作者具有相同的类型fmap ,并同时满足算符法律-因此组合物是的法律定义(和只有这样的定义) fmap到为f创建一个Functor实例。 There's really nothing more to in than that, at least formally.没有什么比这更重要的了,至少在形式上是这样。

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

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