Haskell函数来自(a - > [b]) - > [a - > b]

时间:2012-12-07 14:44:33

标签: list function haskell

我有一个函数seperateFuncs,以便

seperateFuncs :: [a -> b] -> (a -> [b])
seperateFuncs xs = \x -> map ($ x) xs

我想知道反过来是否存在,即是否存在功能

joinFuncs :: (a -> [b]) -> [a -> b]

我认为不是(主要是因为列表不是固定长度),但也许我会被证明是错误的。 那么问题是有一些数据类型f,它有一个函数::(a - > f b) - > f(a - > b)?

5 个答案:

答案 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

  1. (a -> f b) -> f (a -> b) ==&gt; let t = (->) a
  2. t (f b) -> f (t b)
  3. 但是,此类型具有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实际上是一个刚性单子。