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
fofa=(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
fofa=(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
。你当然可以这样做