转动A => M [B]为M [A => B]

时间:2014-12-03 09:24:04

标签: scala haskell scalaz

对于monad M,是否可以将A => M[B]变为M[A => B]

我试过跟踪这些类型无济于事,这让我觉得它不可能,但我想我还是要问。此外,搜索Hoogle a -> m b -> m (a -> b)并没有返回任何内容,因此我没有太多运气。

4 个答案:

答案 0 :(得分:55)

在实践中

不,这是不可能的,至少不是以有意义的方式。

考虑这个Haskell代码

action :: Int -> IO String
action n = print n >> getLine

首先取n,打印它(此处执行IO),然后从用户读取一行。

假设我们有一个假设的transform :: (a -> IO b) -> IO (a -> b)。然后作为心理实验,考虑:

action' :: IO (Int -> String)
action' = transform action

在知道n之前,上面必须事先做所有IO,然后返回一个纯函数。这不能等同于上面的代码。

要强调这一点,请考虑以下无意义的代码:

test :: IO ()
test = do f <- action'
          putStr "enter n"
          n <- readLn
          putStrLn (f n)

奇怪的是,action'应事先知道用户下一步要输入的内容!会话看起来像

42     (printed by action')
hello  (typed by the user when getLine runs)
enter n
42     (typed by the user when readLn runs)
hello  (printed by test)

这需要一台时间机器,因此无法完成。

理论上

不,它无法完成。该论点类似于the one I gave to a similar question

假设存在矛盾transform :: forall m a b. Monad m => (a -> m b) -> m (a -> b)。 将m专门化为continuation monad ((_ -> r) -> r)(我省略了newtype包装器)。

transform :: forall a b r. (a -> (b -> r) -> r) -> ((a -> b) -> r) -> r

专业化r=a

transform :: forall a b. (a -> (b -> a) -> a) -> ((a -> b) -> a) -> a

应用:

transform const :: forall a b. ((a -> b) -> a) -> a

通过库里 - 霍华德的同构,以下是直觉主义的同义反复

((A -> B) -> A) -> A

但这是Peirce定律,这在直觉主义逻辑中是不可证明的。矛盾。

答案 1 :(得分:4)

其他回复很好地说明了对于任何monad a -> m b,通常无法从m (a -> b)m实现函数。但是,有一些特定的monad很可能实现这个功能。一个例子是读者monad:

data Reader r a = R { unR :: r -> a }

commute :: (a -> Reader r b) -> Reader r (a -> b)
commute f = R $ \r a -> unR (f a) r

答案 2 :(得分:3)

没有

例如,Option是一个monad,但函数(A => Option[B]) => Option[A => B]没有有意义的实现:

def transform[A, B](a: A => Option[B]): Option[A => B] = ???

你放什么代替???Some?那么Some呢?或None

答案 3 :(得分:0)

只需完成@svenningsson的答案即可。 其中一个特别有用的示例是在QuickCheck中生成随机函数。 此处的生成器定义为:

newtype Gen a = MkGen {
  unGen :: QCGen -> Int -> a
}

它有一个Monad实例,该实例在某种意义上是Reader,但其中bind总是为所有子计算分配随机生成器。

这意味着我们可以定义一个作用在生成器上的函数,作为函数的生成器!

promote :: (a -> Gen b) -> Gen (a -> b)
promote f = MkGen $ \gen n -> \a -> let MkGen h = f a in h gen n

它在library中更为普遍。

现在的问题是如何获得一个首先作用于生成器的函数,但这是另一个很好的解释here的问题。