【问题标题】:Turning A => M[B] into M[A => B]将 A => M[B] 变成 M[A => B]
【发布时间】:2015-01-31 18:53:53
【问题描述】:

对于一个单子M,是否可以将A => M[B] 变成M[A => B]

我尝试过遵循这些类型无济于事,这让我认为这是不可能的,但我想我还是会问。此外,在 Hoogle 中搜索 a -> m b -> m (a -> b) 并没有返回任何内容,所以我运气不佳。

【问题讨论】:

  • (旁注:你真的想要来自 Hoogle 的 Monad m => (a -> m b) -> m (a ->b)。注意额外的括号,表示一个参数而不是“两个”。当然,正如 chi 所证明的那样,这种类型并没有超越使用底部,所以你仍然不会得到任何结果。)

标签: scala haskell types monads scalaz


【解决方案1】:

实践中

不,不能这样做,至少不能以有意义的方式。

考虑一下这个 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

上面要提前做好所有的IO,才知道n,然后返回一个纯函数。这不能等同于上面的代码。

为了强调这一点,请考虑下面这段无意义的代码:

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 =&gt; (a -&gt; m b) -&gt; m (a -&gt; b)。 将 m 专门用于延续单子 ((_ -&gt; r) -&gt; 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

根据 Curry-Howard 同构,以下是直觉重言式

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

但这是皮尔斯定律,在直觉逻辑中无法证明。矛盾。

【讨论】:

  • @user5402 transform是OP要求的理论函数
  • @user5402 上面其实说明transform无法实现。
  • @user5402 它可以存在于某些特定的monad(例如Reader),但不能存在于所有的monad(例如IO)。
  • @chi:你能推荐一本可以让人们了解更多关于库里-霍华德、皮尔斯定律等的书吗? Simon Thompson 的“类型理论与函数式编程”是否仍然适用(1991 年)?
  • @Zeta 那本书很好,在我看来。我不知道涵盖一般和更高级材料的书籍。我自己也想看一个。在 Coq 的书籍或 HoTT 书籍中可以找到一些普遍的事实,尽管这些的目的更精确。我还建议学习削减消除和连续演算——否则我将无法证明皮尔士定律在 IPC 中是不可证明的。
【解决方案2】:

其他回复很好地说明了通常不可能为任何 monad m 实现从 a -&gt; m bm (a -&gt; b) 的函数。但是,有一些特定的 monad 很可能实现此功能。一个例子是 reader 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

【讨论】:

    【解决方案3】:

    没有。

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

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

    你用什么代替???Some? Some 然后呢?还是None

    【讨论】:

    • 虽然答案是正确的,但要小心“缺乏想象力的证明”。
    【解决方案4】:

    只是为了完成@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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-23
      • 1970-01-01
      • 2012-04-07
      • 2021-10-15
      • 2018-01-12
      • 1970-01-01
      • 2015-12-19
      • 1970-01-01
      相关资源
      最近更新 更多