拥有 Haskell 的背景,我目前正在尝试熟悉 Scala。
我在尝试将一种小型的、可扩展的表达式语言从 Haskell 翻译成 Scala 时遇到了一些问题。编写可使用新数据变体和操作扩展的数据类型的基本问题通常称为表达式问题。
我在 Haskell 中的原始解决方案使用类型类和带有约束的实例声明。我的表达式的基础定义如下:
module Expr where
class Expr e where
eval :: e -> Integer
data Lit = Lit Integer
instance Expr Lit where
eval (Lit l) = l
data Plus a b = (Expr a, Expr b) => Plus a b
instance (Expr a, Expr b) => Expr (Plus a b) where
eval (Plus x y) = (eval x) + (eval y)
然后,我有一个添加乘法的数据扩展:
module ExprWithMul where
import Expr
data Mul a b = (Expr a, Expr b) => Mul a b
instance (Expr a, Expr b) => Expr (Mul a b) where
eval (Mul x y) = (eval x) * (eval y)
让我们以漂亮的打印机作为操作扩展:
module FormatExpr where
import Expr
class (Expr t) => FormatExpr t where
format :: t -> String
instance FormatExpr Lit where
format (Lit l) = show l
instance (FormatExpr a, FormatExpr b) => FormatExpr (Plus a b) where
format (Plus x y) = "(" ++ (format x) ++ "+" ++ (format y) ++ ")"
最后,在第四个模块中,可以组合两个独立的扩展:
module FormatExprWithMult where
import FormatExpr
import ExprWithMul
instance (FormatExpr a, FormatExpr b) => FormatExpr (Mul a b) where
format (Mul x y) = "(" ++ (format x) ++ "*" ++ (format y) ++ ")"
现在我的问题是:通常来自 haskell 的类型类被转换为 Scala 中隐含的概念模式。这是我走了多远:
abstract class Expr[A] { // this corresponds to a type class
def eval(e:A): Int;
}
case class Lit(v: Int)
implicit object ExprLit extends Expr[Lit] {
def eval(e: Lit) = x.v;
}
case class Plus[A,B] (e1: A, e2: B) (implicit c1: Expr[A], c2: Expr[B])
在这里,我坚持为 Plus 实现隐式对象。如何声明具有类型参数和约束的隐式对象?
我知道 Scala 中的表达式问题还有其他解决方案,但是我对这个版本特别感兴趣。
感谢大家阅读我有点冗长的问题。