gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-02 15:56:59 25 4
gpt4 key购买 nike

我正在阅读“Programming in 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 ),其中 this one几乎就是我正在寻找的,但不完全是(我只是在寻找仿函数的示例,没有其他任何东西 - 没有应用程序,也没有单子(monad))。

最佳答案

对于仿函数f来说,实际上没有什么比这更重要的了,即fmap的实现(已知对于任何可能的最多有一个实现>f) 必须具有类型 (a -> b) -> f a -> f b,并满足两个仿函数定律:

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

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

(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定义为f a = r -> a时,复合运算符与fmap具有相同的类型>,并且满足两个仿函数定律 - 因此组合是 fmap 的合法定义(并且唯一这样的定义),用于为以下对象创建一个 Functor 实例f。确实没有什么比这更重要的了,至少在形式上是这样。

关于haskell - Haskell 中部分应用函数类型 (a ->) 作为 Functor 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60329563/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com