如何解释fmap,其中f a = c - > d - > Ë

时间:2016-02-14 21:25:08

标签: haskell functor

我试图了解一些代码,并且让自己纠结得很好。请帮助我理解我的逻辑或缺乏逻辑......

开始:

*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的功能。我现在如何提供另一个 Int -> Bool转换为b的功能?这是非感性的还是我没有读到这个权利?

或许这可能是仿函数中的仿函数,需要做更多才能使其有意义?在哪种情况下,是什么?

1 个答案:

答案 0 :(得分:3)

在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

我认为函子函数族不是一个很好的例子来掌握函子/应用程序/ monad的属性。列表和maybes通常不那么容易混淆;而不是普通的函数仿函数,当你需要这个功能时,首选等价的Reader(双关语不是)。

关于你的原始表达,这实际上并非毫无意义。如果我们将它翻译成驯兽师,我们可以写一下

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

使用函数函数可以完成同样的事情:

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

当然,这个例子有点太简单了,但你也可以实现非常有用的。

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