Haskell 如何解释fmap,其中f a=c->;d->;E

Haskell 如何解释fmap,其中f a=c->;d->;E,haskell,functor,Haskell,Functor,我试图理解一些代码,我把自己弄得相当混乱。请帮助我理解我的逻辑,或者不理解 开始: *Main> :t fmap fmap :: Functor f => (a -> b) -> f a -> f b 如果我只想将fa作为一个只接受一个参数的函数,那么这是可以理解的: *Main> :t \f -> fmap f (undefined :: String -> Int) \f -> fmap f (undefined :: String -

我试图理解一些代码,我把自己弄得相当混乱。请帮助我理解我的逻辑,或者不理解

开始:

*Main> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
如果我只想将fa作为一个只接受一个参数的函数,那么这是可以理解的:

*Main> :t \f -> fmap f (undefined :: String -> Int)
\f -> fmap f (undefined :: String -> Int) :: (Int -> b) -> String -> b
我可以在第二个参数中传入一个
字符串
,它生成一个
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
在这一点上,我感到困惑。我已经提供了将
字符串和
Int
转换为
Bool
的函数。我现在如何提供另一个函数,将
Int->Bool
转换为
b
?这是非感官的还是我没有读对


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

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

特别是,
String->Int->Bool
是一个接受一个
String
参数的函数。(当然,知道结果也是一个函数,你就可以像使用两个参数的函数一样使用它。)因此,如果你想用
fa
来统一它,你需要

f ~ (String->)
a ~ Int->Bool
实际上,
Int->Bool
本身可以解释为函子应用程序†

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

\f -> fmap (fmap f) (undefined :: String -> Int -> Bool)
       :: (Bool -> b) -> String -> Int -> b
我认为函子函数族并不是掌握函子/应用程序/单子属性的好例子。列表和可能会比较容易混淆;当您需要普通函数functor时,最好使用等效函数functor(并非有意使用双关语)

对于你最初的表达,那其实并不是毫无意义的。如果我们把它翻译成一个tamer函子,我们可以写

> fmap ($2) [(>1), (>2), (>3)]
            [True, False, False]
使用函数函子也可以做同样的事情:

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

>fmap($2)(fmap($2)(fmap($2))
构造函数。这意味着,即使有一个
Monad(a->)
实例,也无法以任何方式统一这两个层。

Haskell中实际上没有两个参数的函数。每个函数只有一个参数

特别是,
String->Int->Bool
是一个接受一个
String
参数的函数。(当然,知道结果也是一个函数,你可以像使用两个参数的函数一样使用它。)因此,如果你想用
fa
统一这个函数,你需要

f ~ (String->)
a ~ Int->Bool
实际上,
Int->Bool
本身可以解释为函子应用程序†

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

\f -> fmap (fmap f) (undefined :: String -> Int -> Bool)
       :: (Bool -> b) -> String -> Int -> b
我不认为函子函数族是掌握函子/应用程序/单子属性的一个好例子。列表和maybes通常不那么容易混淆;当您需要该功能时,最好使用等效函数函子,而不是普通函数函子(不是双关语)

关于你的原始表达式,这其实不是毫无意义的。如果我们把它翻译成一个驯服函子,我们可以写

> fmap ($2) [(>1), (>2), (>3)]
            [True, False, False]
使用函数函子也可以做同样的事情:

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

>fmap($2)(fmap($2)(fmap($2))
构造函数。这意味着,即使有一个
Monad(a->)
实例,您也无法以任何方式统一这两个层。

如果您将其重新表述为
fmap f(undefined::String->(Int->Bool))
,这就是您要说的(基本上
String
保持
String
,但您可以将
Int
替换为
Int->Bool
,以匹配所需的模式)@卡斯滕:我理解分组,但它对我没有帮助,因为我仍然保留着相同的类型签名。如果我的类型
String->Int->Bool
函数对我来说是不透明的,那么我就没有办法实现这个
fmap
。没有办法实现
fmap
fo
fa=(String->Int)->Bool->a
-至少不能直接-您可以将其包装成类似
newtype MyMap a=String->Int->Bool->a
的内容,并将
MyMap
作为
Functor
的实例-但是,您必须包装/取消包装构造函数或可能的副本,如果您将其重新表述为
fmap f,这对您有帮助吗(未定义::String->(Int->Bool))
?因为这就是您所说的(基本上
String
保留
String
,但您将
Int
替换为
Int->Bool
,以匹配所需的模式)@卡斯滕:我理解分组,但它对我没有帮助,因为我仍然保留着相同的类型签名。如果我的类型
String->Int->Bool
函数对我来说是不透明的,那么我就没有办法实现这个
fmap
。没有办法实现
fmap
fo
fa=(String->Int)->Bool->a
-至少不能直接-您可以将其包装成类似
newtype MyMap a=String->Int->Bool->a
的东西,并将
MyMap
作为
Functor
的实例-但是,您必须包装/取消包装构造函数,或者可以将层统一起来;使用标准
Monad
。一般来说,您当然可以执行类似于
uncurry
的操作。我还猜想,如果参数类型之间有适当的关系,您可能可以使用索引Monad进行操作。我认为
\f->fmap(fmap f)(未定义的::String->Int->Bool):(Bool->b)->String->Int->b
是我想要的。谢谢!你可以统一层;你只是不能用标准的
Monad
。你当然可以这样做