本文介绍了在Scala中输入类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我遇到了一些问题,试图将一个小的,可扩展的表达式语言从Haskell转换成Scala 。编写可与新数据变体和操作一起扩展的数据类型的基本问题通常称为表达式问题。 我在Haskell中的原始解决方案使用带约束的类型和实例声明。我的表达式的基础定义如下: module Expr where class Expr e其中 eval :: e - >整数 数据点亮=点亮整数实例显示其中 eval(Lit l)= l data加上ab =(Expr a,Expr b)=>加上b 实例(Expr a,Expr b)=> Expr(Plus ab)其中 eval(Plus xy)=(eval x)+(eval y) 然后,我有一个数据扩展添加乘法: module ExprWithMul其中 import Expr data Mul ab =(Expr a,Expr b)=> Mul a b instance(Expr a,Expr b)=> Expr(Mul ab)其中 eval(Mul xy)=(eval x)*(eval y) $ b $ module FormatExpr where import Expr class(Expr t)=> FormatExpr t其中 format :: t - >字符串 实例FormatExpr Lit其中格式(Lit l)= show l 实例(FormatExpr a,FormatExpr b)=> FormatExpr(Plus ab)其中格式(Plus xy)=(++(format x)+++++(format y)++) 最后,在第四个模块中,可以组合两个独立的扩展: import FormatExpr import ExprWithMul 实例(FormatExpr a,FormatExpr b)=> FormatExpr(Mul ab)其中格式(Mul xy)=(++(format x)++*++(format y)++) 抽象类Expr [A] {//这对应于一个类型类 def eval(e:A):Int; case class Lit(v:Int)隐式对象ExprLit extends Expr [Lit] { def eval(e:Lit)= x.v; case class Plus [A,B](e1:A,e2:B)(隐式c1:Expr [A],c2:Expr [B]) 这里我坚持实现Plus的隐式对象。我如何声明带有类型参数和约束的隐式对象? 我知道在Scala中有表达式问题还有其他解决方案,但我对此版本感兴趣特别是。 谢谢大家阅读我有点冗长的问题。 解决方案 第一次尝试(有缺陷): case class Plus [A,B](e1:A,e2:B)(隐式c1:Expr [A],c2:Expr [B]){隐式对象ExprPlus扩展Expr [Plus [A,B]] { def eval(p:Plus [A,B]) = c1.eval(p.e1)+ c2.eval(p.e2)} } 编辑1: 以上功能不够强大(不能添加两个 Plus 表达式),隐式见证不需要在 Plus case类中定义......试试这个: case class Plus [A,B](e1:A,e2:B)(隐式val c1:Expr [A],c2:Expr [B])含义它确定ExprPlus [A,B](隐含的c1:Expr [A],c2:Expr [B])= 新的Expr [Plus [A,B]] { def eval(p:Plus [A,B])= c1.eval(p.e1)+ c2.eval(p.e2)} 编辑2: 以下是一个稍微更习惯的版本: case class Plus [A:Expr,B:Expr](e1:A,e2:B)隐式def ExprPlus [A:Expr,B:Expr] = new Expr [Plus [A,B]] { def eval(p:Plus [A,B])=隐含[Expr [A]]。eval(p.e1)+ 隐含[Expr [B ]]。eval(p.e2)} Having a background in Haskell I am currently trying to get familiar with Scala.I encountered some problems trying to translate a small, extensible expression language from Haskell into Scala. The underlying issue of writing a data type that is extensible with both new data-variants and operations is commonly known as the expression problem.My original solution in Haskell uses type classes and instance declarations with constraints. The base of my expression is defined as follows:module Expr whereclass Expr e where eval :: e -> Integerdata Lit = Lit Integerinstance Expr Lit where eval (Lit l) = ldata Plus a b = (Expr a, Expr b) => Plus a binstance (Expr a, Expr b) => Expr (Plus a b) where eval (Plus x y) = (eval x) + (eval y)Then, I have one data-extension that adds multiplication:module ExprWithMul whereimport Exprdata Mul a b = (Expr a, Expr b) => Mul a binstance (Expr a, Expr b) => Expr (Mul a b) where eval (Mul x y) = (eval x) * (eval y)Let's take a pretty-printer as an operational extension:module FormatExpr whereimport Exprclass (Expr t) => FormatExpr t where format :: t -> Stringinstance FormatExpr Lit where format (Lit l) = show linstance (FormatExpr a, FormatExpr b) => FormatExpr (Plus a b) where format (Plus x y) = "(" ++ (format x) ++ "+" ++ (format y) ++ ")"And, finally, in the fourth module the two independent extensions can be combined:module FormatExprWithMult whereimport FormatExprimport ExprWithMulinstance (FormatExpr a, FormatExpr b) => FormatExpr (Mul a b) where format (Mul x y) = "(" ++ (format x) ++ "*" ++ (format y) ++ ")"Now for my problem: Usually type classes from haskell are translated to the concept-pattern with implicits in Scala. This is how far I got: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])Here I am stuck with implementing the implicit object for Plus. How do I declare an implicit object with type parameters and constraints?I know that there are other solution for the expression problem in Scala, I am however interested in this version in particular.Thank you all for reading my somewhat lengthy question. 解决方案 First attempt (flawed):case class Plus[A,B] (e1: A, e2: B) (implicit c1: Expr[A], c2: Expr[B]) { implicit object ExprPlus extends Expr[Plus[A, B]] { def eval(p:Plus[A, B]) = c1.eval(p.e1) + c2.eval(p.e2) }}Edit 1:The above isn't sufficiently powerful (you can't add two Plus expressions), and the implicit witness need not be defined inside of the Plus case class... try this instead:case class Plus[A,B] (e1: A, e2: B) (implicit val c1: Expr[A], c2: Expr[B])implicit def ExprPlus[A, B](implicit c1: Expr[A], c2: Expr[B]) = new Expr[Plus[A, B]] { def eval(p:Plus[A, B]) = c1.eval(p.e1) + c2.eval(p.e2) }Edit 2:Here's a (perhaps) slightly more idiomatic version:case class Plus[A: Expr, B: Expr] (e1: A, e2: B)implicit def ExprPlus[A: Expr, B: Expr] = new Expr[Plus[A, B]] { def eval(p:Plus[A, B]) = implicitly[Expr[A]].eval(p.e1) + implicitly[Expr[B]].eval(p.e2)} 这篇关于在Scala中输入类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
10-23 09:59