【问题标题】:Free implementation in scalaz在 scalaz 中免费实现
【发布时间】:2016-06-10 07:27:46
【问题描述】:

Haskell 中的免费实现是:

data Free f a =
Pure a
| Free (f (Free f a))

然而,Scalaz 中的实现是:

sealed abstract class Free[S[_], A]

private case class Return[S[_], A](a: A) extends Free[S, A]
private case class Suspend[S[_], A](a: S[A]) extends Free[S, A]
private case class Gosub[S[_], B, C](a: Free[S, C], f: C => Free[S, B]) extends Free[S, B]

为什么scalaz的实现不像Haskell,比如:

sealed trait Free[F[_],A]
case class Return[F[_],A](a: A) extends Free[F,A]
case class GoSub[F[_],A](s: F[Free[F,A]]) extends Free[F,A]

这两个实现是同构的吗?

【问题讨论】:

  • 在给定 F[A] 使用第二个 Scala 实现的情况下,您将如何创建 Free[F, A]
  • @PeterNeyens 当FFunctor 时很有可能。这种表示的问题在于它会导致堆栈安全问题。
  • @TomasMikula。好的,我看到GoSub[F, A](F.map(fa)(Return[F, A](_))),谢谢!

标签: scala scalaz free-monad


【解决方案1】:

将 Haskell 代码翻译成 Scala 是

sealed abstract class Free[S[_], A]

case class Return[S[_], A](a: A) extends Free[S, A]
case class Suspend[S[_], A](a: S[Free[S, A]]) extends Free[S, A]

由于惰性求值,Haskell 实现不需要Gosub 案例。这种表示也可以在 Scala 中工作,但由于(严格评估和)缺乏尾调用消除,它会导致堆栈溢出问题。为了使其堆栈安全,我们将flatMap 懒惰地表示为Gosub(我认为FlatMap 会更好):

case class Gosub[S[_], B, C](a: Free[S, C], f: C => Free[S, B]) extends Free[S, B]

作为奖励,Gosub 的引入允许我们将Suspend 简化为

case class Suspend[S[_], A](a: S[A]) extends Free[S, A]

因为我们不再需要通过映射S[_] 的内容来执行flatMaps——我们将flatMaps 明确表示为Gosubs。

因此,这种结果表示,与 Haskell 表示不同,它允许我们用 Free 做任何事情,而不需要 Functor[S]。因此,当我们的S 不是Functor 时,我们甚至不需要使用“Coyoneda 技巧”。

【讨论】:

    猜你喜欢
    • 2011-01-08
    • 2013-01-16
    • 2010-12-20
    • 1970-01-01
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-15
    相关资源
    最近更新 更多