我有一个函数seperateFuncs
,以便
seperateFuncs :: [a -> b] -> (a -> [b])
seperateFuncs xs = \x -> map ($ x) xs
我想知道反过来是否存在,即是否存在功能
joinFuncs :: (a -> [b]) -> [a -> b]
我认为不是(主要是因为列表不是固定长度),但也许我会被证明是错误的。
那么问题是有一些数据类型f
,它有一个函数::(a - > f b) - > f(a - > b)?
答案 0 :(得分:7)
您可以非常干净地将seperateFuncs
概括为Applicative
(或Monad
):
seperateFuncs :: (Applicative f) => f (a -> b) -> (a -> f b)
seperateFuncs f x = f <*> pure x
以无点样式编写,你有seperateFuncs = ((. pure) . (<*>))
,所以你基本上想要unap . (. extract)
,如果你用有点的风格写下它,给出以下定义:
joinFuncs :: (Unapplicative f) => (a -> f b) -> f (a -> b)
joinFuncs f = unap f (\ g -> f (extract g))
我将Unapplictaive
定义为:
class Functor f => Unapplicactive f where
extract :: f a -> a
unap :: (f a -> f b) -> f (a -> b)
要获取definitions given by leftaroundabout,您可以提供以下实例:
instance Unapplicative [] where
extract = head
unap f = [\a -> f [a] !! i | i <- [0..]]
instance Unapplicative ((->) c) where
extract f = f undefined
unap f = \x y -> f (const y) x
我认为很难为任何与f :: (f a -> f b) -> f (a -> b)
不同的f
提供“有用”功能(->)
。
答案 1 :(得分:4)
首先,你可以蛮力强迫自己这个功能:
joinFuncs f = [\x -> f x !! i | i<-[0..]]
但这显然很麻烦 - 结果列表总是无限的,但仅i
评估x
元素,length(f x) > i
只会成功。
为
提供“真正的”解决方案那么问题是某些数据类型
f
有一个函数:: (a -> f b) -> f (a -> b)
?
考虑(->)c
。这样,您的签名就会显示(a -> (c->b)) -> (c->(a->b))
或等效(a -> c -> b) -> c -> a -> b
,结果只是flip
。
当然,这是一个微不足道的问题,因为seperateFuncs
具有相同的此类签名...
答案 2 :(得分:3)
“是否有一些数据类型f具有函数::(a - &gt; f b) - &gt; f(a - &gt; b)?”
事实上,在Traversable类型类中有一个更通用的版本,该类处理可交换的仿函数:
class (Functor t, Foldable t) => Traversable t where
...
sequenceA :: Applicative f => t (f b) -> f (t b)
这与你的功能有什么关系?从您的类型开始,只需一种类型替换,我们就会恢复sequenceA
:
(a -> f b) -> f (a -> b)
==&gt; let t = (->) a
t (f b) -> f (t b)
但是,此类型具有t
必须是Traversable的约束 - 并且(->) a
没有可遍历的实例,这意味着此操作通常无法执行功能。虽然请注意“其他方向” - f (a -> b) -> (a -> f b)
适用于所有函数和所有Applicative f
。
答案 3 :(得分:3)
我最近不得不考虑一些与你的问题非常相似的问题。这是我发现的概括。
首先,做到这一点很简单(在Tinctorius指出):
f2m :: Functor f => f (a -> b) -> a -> f b
f2m f a = fmap ($a) f
但一般来说不可能这样做:
m2a :: Monad m => (a -> m b) -> m (a -> b)
在#haskell irc频道中有人向我解释的一种深刻理解这一点的方法是,如果存在m2a
函数,Applicative
和{{之间就没有区别1}}。为什么?好吧,我没有100%遵循它,但它是这样的:Monad
是一个参数的常见类型的monadic动作,而Monad m => a -> m b
也是非常常见的类型,不知道正确的名称,我会称之为“适用的应用程序”。 Applicative f => f (a -> b)
可以执行Monad
无法做到的事情与Applicative
不存在的事实相关联。
现在,适用于您的问题:
m2a
我怀疑同样的“Monad / = Applicative”论点(再次,让我强调,我不完全理解)应该在这里适用。我们知道joinFuncs :: (a -> [b]) -> [a -> b]
实例可以执行Monad []
实例无法执行的操作。如果您可以使用指定的类型编写Applicative []
,那么与joinFuncs
参数相比,[a -> b]
结果在某种意义上必须“丢失信息”,否则a -> [b]
是与Applicative []
相同。 (并且通过“丢失”信息,我的意思是任何具有Monad []
类型的函数都不能具有逆,因此可以保证消除某些函数对joinFuncs
之间的区别。那是f, g :: a -> [b]
。)
我确实发现我需要类似于joinFuncs = undefined
的功能所以我发现的特殊情况是可以这样做:
m2a
请注意,除了我们列举import Data.Map (Map)
import qualified Data.Map as Map
-- | Enumerate a monadic action within the domain enumerated by the
-- argument list.
boundedM2a :: Monad m => (a -> m b) -> [a] -> m [(a,b)]
boundedM2a f = mapM f'
where f' a = do b <- f a
return (a, b)
-- | The variant that makes a 'Map' is rather useful.
boundedM2a' :: (Monad m, Ord a) => (a -> m b) -> [a] -> m (Map a b)
boundedM2a' f = liftM Map.fromList . boundedM2a f
的要求之外,一个有趣的观察是,要做到这一点,我们必须在某种意义上“实现”结果;将它从函数/动作转换为某种列表,地图或表格。
答案 4 :(得分:0)
“我是否可以使用具有类型签名joinFuncs :: (a -> [b]) -> [a -> b]
的函数,但还没有说明您希望该函数满足哪些法律。这个问题不完整。如果没有法律,则可以通过定义joinFuncs _ = []
(始终返回一个空列表)。这个琐碎的函数可以满足所需的类型签名,但很可能是无用的。
要求joinFuncs
有用的一种方法是强加非简并性法律separateFuncs . joinFuncs == id
。然后人们可以证明不可能为这种类型签名实现joinFuncs
。
这种类型签名的一个更一般的情况是(a -> f b) -> f (a -> b)
,其中f
是一个函子。我称这类函子为“刚性”。有关更多详细信息,请参见问题Is this property of a functor stronger than a monad?。
所有刚性函子R
满足以下性质:类型R ()
仅具有一个不同的值,即,它等效于()
。这使我们可以立即看到List
函子不是严格的,因为List ()
不等于()
。
刚性函子最简单的简单例子是type R a = (a -> p) -> a
,其中p
是固定类型。以此方式定义的函子R
实际上是一个刚性单子。