繁体   English   中英

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

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

我正在阅读“Haskell 编程”一书(第二版),偶然发现了练习 2,第 12 章,第 2 部分:

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

答案是:

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

这让我挠了好一阵子。 我想这在直观层面上对我来说确实有意义(部分应用的函数类型a ->是一个函子,当组合是它的fmap ),但我认为一些很好的例子会巩固我对这个练习的理解。

我想出了这两个:

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

我的例子是否正确地说明了练习?

fmap给出了两个参数:

  • 部分应用函数(函数)
  • 另一个部分应用的函数(函子)

更新

fmap给出了两个参数:

  • 功能(功能)
  • 另一个函数(函子)

对我来说只是看起来很奇怪,我不确定我的概念是否正确。

我在 SO 上看到了一些类似的问题(例如this one ),其中这个问题几乎是我正在寻找的,但并不完全(我只是在寻找函子的例子,没有别的 - 没有应用程序和单子)。

没有什么比这更重要的了,对于函子ffmap的实现(已知对于任何可能的f最多只有一个实现)必须具有类型(a -> b) -> fa -> fb ,并满足两个函子定律:

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

f是类型构造函数(->) r - 即当fa表示r -> a - 那么所需的类型签名是:

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

(最后一对括号是不必要的,但我把它们留在了,因为它使“模式”更容易看到),很容易看到,这正是(.)运算符的签名。

至于这两条定律,很明显,当你写下它们所说的话时,它们必须成立。 我将通过详细地写出所有内容来证明它们:

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

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

所以那些也是一样的。

(不要太担心最后的推导——通常这样的事情似乎很难遵循如何从一行到下一行的逻辑,即使在这里它们基本上都使用组合的定义。这真的只是表达了显而易见的众所周知的事实,即函数组合是结合的。无论如何,这是一个普遍的结果,除了我相信对于某些病理类型,如果满足第一个函子定律,那么第二个将始终自动满足。 )

重要的是:当f被定义为fa = r -> a ,则该组合物操作者具有相同的类型fmap ,并同时满足算符法律-因此组合物是的法律定义(和只有这样的定义) fmap到为f创建一个Functor实例。 没有什么比这更重要的了,至少在形式上是这样。

暂无
暂无

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

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