在 Scala 中编写自由 monad

Composing Free monads in Scala

我想我理解 Free monad 是什么。我希望我也明白函子 compose 但 monads do not,即如果 M1M2 是 monads 那么 M1[M2]不是 必须是 monad。

我的问题是:

希望我能回答你的问题:

自由 monad 可以组合吗?

。出于与 "normal" 相同的原因,monad 不会。要编写 monadic bind,我们需要了解一些关于底层 monad 的知识,或者了解自由 monad 情况下的底层仿函数。

希望 Haskell 语法不会吓到你:

type X f g a = Free f (Free g a)

bind :: X f g a -> (a -> X f g b) -> X f g b
bind (Pure (Pure x)) k = k x
bind (Pure (Free f)) k = error "not implemented"
bind _ = error "we don't even consider other cases"

在第二种情况下,我们有 f :: g (Free g a)k :: a -> Free f (Free g b)。我们可以 fmap,因为这是我们唯一能做的事情:

bind (Pure (Free f)) k = let kf = fmap (fmap k) f -- fmapping inside g ∘ Free g
                         in = error "not implement"

当我们需要 Free f (Free g b) 时,kf 的类型将是:g (Free g (Free f (Free g b)))。您将遇到与为任何 Compose m1 m2 编写 monad 实例时相同的问题,我们需要将 "bind layers" 从 g-g-f-g 重新排序为 f-g-g-g,然后执行此操作我们需要更多地了解 fg.

如果你想看上面的Scala版本,请评论。不过它会更加晦涩:(

我们可以为 F1[F2] 定义一个只有 Free1 和 Free2 的 Free monad吗

换句话说:

type Free1[A] = Free[F1, A]
type Free2[A] = Free[F2, B]

type FreeDist[A] = Free1[Free2[A]] = Free[F1, Free[F2, A]]
type FreeComp[A] = Free[F1[F2[_]], A]

我们可以写一个从 FreeDist[A]FreeComp[A] 的 monad 同态(good 映射)吗?我们不能,原因与前一部分相同。


Scala 版本

Scalaz 有 Free 子类的私有定义,所以我必须自己实现 Free 才能有一个 "runnable" 示例。从 http://eed3si9n.com/learning-scalaz/Free+Monad.html

中删除的一些代码

Scala 中 Free 的第一个最简单的定义:

import scala.language.higherKinds

trait Functor[F[_]] {
  def map[A, B](x: F[A])(f: A => B): F[B]
}

sealed trait Free[F[_], A] {
  def map[B](f: A => B)(implicit functor: Functor[F]): Free[F, B]
  def flatMap[B](f: A => Free[F, B])(implicit functor: Functor[F]): Free[F, B]
}
case class Pure[F[_], A](x: A) extends Free[F, A] {
  def map[B](f: A => B)(implicit functor: Functor[F]): Free[F, B] = Pure[F, B](f(x))
  def flatMap[B](f: A => Free[F, B])(implicit functor: Functor[F]): Free[F, B] = f(x)
}
case class Bind[F[_], A](x: F[Free[F, A]]) extends Free[F, A]  {
  def map[B](f: A => B)(implicit functor: Functor[F]): Free[F, B] = Bind {
    functor.map[Free[F,A], Free[F,B]](x) { y => y.map(f) }
  }
  // omitted 
  def flatMap[B](f: A => Free[F, B])(implicit functor: Functor[F]): Free[F, B] = ???
}

使用它我们可以将 Haskell 示例翻译成 Scala:

type X[F[_], G[_], A] = Free[F, Free[G, A]]

// bind :: X f g a -> (a -> X f g b) -> X f g b
def xFlatMap[F[_], G[_], A, B](x: X[F, G, A], k: A => X[F, G, B])(implicit functorG: Functor[G]): X[F, G, B] =
  x match {
    case Pure(Pure(y)) => k(y)
    case Pure(Bind(f)) => {
      // kf :: g (Free g (Free f (Free g b)))
      val kf: G[Free[G, Free[F, Free[G, B]]]] = functorG.map(f) { y => y.map(k) }
      // But we need Free[F, Free[G, B]]
      ???
    }
    // we don't consider other cases
    case _ => ???
  }

结果是一样的,我们不能使类型匹配,我们需要将Free[G, Free[F, A]]转换成Free[F, Free[G, A]]