如何解释 fmap where f a = c -> d -> e

How to interpret fmap where f a = c -> d -> e

我正在尝试理解一些代码,但我自己却纠结得相当厉害。请帮助我理解我的逻辑,或者缺乏逻辑......

开始:

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

如果我只是想让f a成为一个接受一个参数的函数,那没关系,也很有意义:

*Main> :t \f -> fmap f (undefined :: String -> Int)
\f -> fmap f (undefined :: String -> Int) :: (Int -> b) -> String -> b

我可以在第二个参数中传入一个String,生成一个Int,然后使用第一个参数中的函数生成b

现在,我希望 f a 成为一个带有两个参数的函数,所以我将其替换为:

*Main> :t \f -> fmap f (undefined :: String -> Int -> Bool)
\f -> fmap f (undefined :: String -> Int -> Bool) 
    :: ((Int -> Bool) -> b) -> String -> b

在这一点上,我很困惑。我已经提供了从 StringInt 转换为 Bool 的函数。我现在如何提供 a Int -> Bool 转换为 b 的另一个函数?这是荒谬的还是我没有正确阅读?

或者这可能是一个函子中的一个函子的情况,需要做更多的工作才能使它有意义?在这种情况下,什么?

在Haskell中其实没有两个参数的函数。每个函数只有一个参数。

特别地,String -> Int -> Bool 是一个接受一个 String 参数的函数。 (当然,知道结果又是一个函数,你可以使用它 就好像它是 一个有两个参数的函数一样。)所以如果你想将它与 f a, 你需要

f ~ (String->)
a ~ Int->Bool

确实Int->Bool本身可以解释为函子应用

f ~ (String->)
g ~ (Int->)
b ~ Bool

所以String->Int->Bool ~ f (g b);因此

\f -> fmap (fmap f) (undefined :: String -> Int -> Bool)
       :: (Bool -> b) -> String -> Int -> b

我不认为函子的函数族真的是掌握 functors/applicatives/monads 属性的好例子。 List 和 maybes 通常不会那么混乱;当您需要该功能(双关语不是故意的)时,首选等效的 Reader 而不是普通函数仿函数。

你原来的表达,其实也不是没有意义。如果我们把它翻译成一个 tamer 函子,我们可以写成

> fmap () [(>1), (>2), (>3)]
            [True, False, False]

很多相同的事情可以用函数函子完成:

> fmap () (<) 1
True
> fmap () (<) 2
False
> fmap () (<) 3
False

当然,这个例子有点太简单了,没有用,但你也可以实现一些重要的例子。


注意fg实际上不是同一个函子 .我们倾向于称它们为“the function functor”,但实际上对于 (->) 构造函数的每个部分应用你都会得到一个不同的 functor。这意味着,即使有一个 Monad (a->) 实例,您也无法以任何方式统一这两层。