繁体   English   中英

如何从Scala的Haskell表达这种存在类型?

[英]How to express this existential type from Haskell in Scala?

我试图将基于Haskell的基于类型类的表达式问题解决方案改编为Scala。 我当前的代码如下。 我在Scala中表达存在类型Exp遇到问题。

我怎样才能达成同一目标?

object ExpressionProblem {

  // class Eval a where
  //   eval :: a -> Int
  trait Eval[A] {
    def eval(expr: A): Int
  }

  // data Exp = forall t. Eval t => Expr t
  sealed abstract class Exp
  case class Expr[T](val e: T)(implicit ev: Eval[T]) extends Exp

  // instance Eval Exp where
  //   eval (Expr e) = eval e
  implicit val exprInstance = new Eval[Exp] {
    def eval(expr: Exp) = expr match { case Expr(e, ev) => ev.eval(e) }
  }
  //                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  //                                       here is the problem

  // data BaseExp = Const Int | Add Exp Exp | Mul Exp Exp
  sealed abstract class BaseExpr
  case class Const(c: Int) extends BaseExpr
  case class Add(lhs: Exp, rhs: Exp) extends BaseExpr
  case class Mul(lhs: Exp, rhs: Exp) extends BaseExpr

  // instance Eval BaseExp where
  //   eval (Const n) = n
  //   eval (Add a b) = eval a + eval b
  //   eval (Mul a b) = eval a * eval b
  implicit val baseExprInstance = new Eval[BaseExpr] {
    def eval(baseExpr: BaseExpr)(implicit e: Eval[Exp]): Int =
      baseExpr match {
        case Const(c)      => c
        case Add(lhs, rhs) => e.eval(lhs) + e.eval(rhs)
        case Mul(lhs, rhs) => e.eval(lhs) + e.eval(rhs)
      }
  }

  // TODO: Is there an easier way to make all of them implicitly convertible?
  //
  // The following doesn't seem to work:
  //
  //    implicit def baseExprToExp[T <: BaseExpr](t: T): Exp = Expr[BaseExpr](t)
  //
  implicit def constToExp(c: Const): Exp = Expr[BaseExpr](c)
  implicit def addToExp(a: Add): Exp = Expr[BaseExpr](a)
  implicit def mulToExp(m: Mul): Exp = Expr[BaseExpr](m)

  ///////////////////////////////////////////////
  // Possibly in another module/lib.
  ///////////////////////////////////////////////

  // data SubExp = Sub Exp Exp
  case class SubExpr(val lhs: Exp, val rhs: Exp)

  // instance Eval SubExp where
  //   eval (Sub a b) = eval a - eval b
  implicit val subExprInstance = new Eval[SubExpr] {
    def eval(subExpr: SubExpr)(implicit e: Eval[Exp]): Int =
      e.eval(subExpr.lhs) - e.eval(subExpr.rhs)
  }

  // Make it implicitly convertible to Exp.
  implicit def subExprToExp(s: SubExpr): Exp = Expr(s)

  object Test {
    val exprs: List[Exp] = List(
      SubExpr(Const(10), Const(3)),
      Add(Const(1), Const(1))
    )
  }

} // ExpressionProblem

编辑 :同时,我找到了这个相关的StackOverflow答案,并对其进行了修改。

import scala.language.implicitConversions

object ExpressionProblem {

  // class Eval a where
  //   eval :: a -> Int
  trait Eval[A] {
    def eval(expr: A): Int
  }

  //////////////////////////////////////////
  // HERE'S THE MAGIC
  //
  // data Expr = forall t. Eval t => Expr t
  trait Expr {
    type T
    val t: T
    val evalInst: Eval[T]
  }

  object Expr {
    def apply[T0 : Eval](t0: T0) = new Expr {
      type T = T0
      val t = t0
      val evalInst = implicitly[Eval[T]]
    }
  }

  // Default boxing is needed
  implicit def box[T : Eval](t: T) = Expr(t)

  // instance Eval Expr where
  //   eval (Expr e) = eval e
  implicit object exprInstance extends Eval[Expr] {
    def eval(expr: Expr) = expr.evalInst.eval(expr.t)
  }

  // data BaseExpr = Const Int | Add Expr Expr | Mul Expr Exp
  sealed abstract class BaseExpr
  case class Const(c: Int) extends BaseExpr
  case class Add(lhs: Expr, rhs: Expr) extends BaseExpr
  case class Mul(lhs: Expr, rhs: Expr) extends BaseExpr

  // instance Eval BaseExpr where
  //   eval (Const n) = n
  //   eval (Add a b) = eval a + eval b
  //   eval (Mul a b) = eval a * eval b
  implicit object baseExprInstance extends Eval[BaseExpr] {
    def eval(baseExpr: BaseExpr): Int =
      baseExpr match {
        case Const(c)      => c
        case Add(lhs, rhs) => exprInstance.eval(lhs) + exprInstance.eval(rhs)
        case Mul(lhs, rhs) => exprInstance.eval(lhs) + exprInstance.eval(rhs)
      }
  }

  // Implicit conversions for all base expressions
  implicit def baseExprToExpr[T <: BaseExpr](t: T): Expr = Expr[BaseExpr](t)

  ///////////////////////////////////////////////
  // Possibly somewhere else (in the future).
  ///////////////////////////////////////////////

  // data SubExpr = Sub Expr Exp
  case class SubExpr(val lhs: Expr, val rhs: Expr)

  // instance Eval SubExpr where
  //   eval (Sub a b) = eval a - eval b
  implicit object subExprInstance extends Eval[SubExpr] {
    def eval(subExpr: SubExpr): Int =
      exprInstance.eval(subExpr.lhs) - exprInstance.eval(subExpr.rhs)
  }

  // NOTE: We don't have to provide an implicit conversion to Expr as the
  // default `box` one suffices.

  object Test {
    val exprs: List[Expr] = List(
      SubExpr(Const(10), Const(3)),
      Add(Const(1), Const(1))
    )
  }

} // ExpressionProblem

你的问题是,你正在使用提取器( unapply ),但忽略一个事实,即implicits是默认情况下不暴露的部分unapply

所以这行:

def eval(expr: Exp) = expr match { case Expr(e, ev) => ev.eval(e) }

没有case Expr(e, ev) ,只有case Expr(e) ,因为只有e是公开的。 编写自定义提取器或找到其他方法。

Scala确实提供了以下形式的存在类型:

Expr[T] forSome { type T})

具有可用的简写类型表示法: Expr[_]

您的代码还有更多问题:

如果您在eval上定义了implicit ,则所有实现者都必须使用该特定签名来实现eval函数,您不能像在eval中那样使用不包含签名中的隐式的实现来覆盖eval

 implicit val baseExprInstance = new Eval[BaseExpr] {
    def eval(baseExpr: BaseExpr)(implicit e: Eval[Exp]): Int =
      baseExpr match {
        case Const(c)      => c
        case Add(lhs, rhs) => e.eval(lhs) + e.eval(rhs)
        case Mul(lhs, rhs) => e.eval(lhs) + e.eval(rhs)
      }
  }

接下来,您将需要使Expr T成为SubExpr ,或者使SubExpr也扩展Exp ,这里有一个问题:

  // instance Eval SubExp where
  //   eval (Sub a b) = eval a - eval b
  implicit val subExprInstance = new Eval[SubExpr] {
    def eval(subExpr: SubExpr)(implicit e: Eval[SubExpr]): Int =
      e.eval(subExpr.lhs) - e.eval(subExpr.rhs)
  }

如果尝试匹配类型签名,则implicit e: Eval[SubExpr]可以评估T >: SubExpr类型,但是您需要的是Eval的较低Exp隐式。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM