如何解释 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
在这一点上,我很困惑。我已经提供了从 String
和 Int
转换为 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
当然,这个例子有点太简单了,没有用,但你也可以实现一些重要的例子。
†注意f
和g
实际上不是同一个函子 .我们倾向于称它们为“the function functor”,但实际上对于 (->)
构造函数的每个部分应用你都会得到一个不同的 functor。这意味着,即使有一个 Monad (a->)
实例,您也无法以任何方式统一这两层。
我正在尝试理解一些代码,但我自己却纠结得相当厉害。请帮助我理解我的逻辑,或者缺乏逻辑......
开始:
*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
在这一点上,我很困惑。我已经提供了从 String
和 Int
转换为 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
当然,这个例子有点太简单了,没有用,但你也可以实现一些重要的例子。
†注意f
和g
实际上不是同一个函子 .我们倾向于称它们为“the function functor”,但实际上对于 (->)
构造函数的每个部分应用你都会得到一个不同的 functor。这意味着,即使有一个 Monad (a->)
实例,您也无法以任何方式统一这两层。