[英]Scala equivalent to Haskell pattern Matching on constructors
在Haskell中,我定义了如下构造函数:
data Fonction =
Const Float
| Param String
| Var String
| Add Fonction Fonction
infix 3 @+
(@+) :: Fonction -> Fonction -> Fonction
(@+) (Const k) (Const k') = Const (k + k')
在Scala中,对我来说很新,我尝试过:
trait Function {
case class Const(value: Double) extends Function
case class Param(value: String) extends Function
case class Var(value: String) extends Function
case class Add(f1: Function, f2: Function) extends Function
}
object Op extends Function {
def som(f1:Function, f2: Function): Function =
(f1, f2) match {
case (Const(a),Const(b)) => Const(a + b)
case _ => Add(f1,f2)
}
}
object HelloWorld extends Function {
def main(args: Array[String]): Unit = {
val s = Op.som(Const(3),Const(5))
println(s)
}
}
但是模式(Const(3),Const(5))不匹配,因为我得到了Add(Const(3.0),Const(5.0))
尽管@nicodp代码在技术上是正确的(但恕我直言不太正确),但没有提供任何解释。 您的代码无法按预期工作的原因是因为您在trait Function
定义了案例。 事实是,在Java世界中, 内部类可以是静态的,也可以是非静态的,并且Scala复制了行为的这一部分。 trait
中定义的类是非静态的。 特别是,这意味着HelloWorld.Const(42)
的实例不等于Op.Const(42)
的实例,因为它们捕获不同类型( Op
对象和HelloWorld
对象)的不同“外部”值。 这也是为什么模式匹配无法按预期工作的原因。 如果您将模式匹配写为:
object Op extends Function {
def som(f1: Function, f2: Function): Function =
(f1, f2) match {
// this doesn't work
//case (Const(a), Const(b)) => Const(a + b)
// this works
case (HelloWorld.Const(a), HelloWorld.Const(b)) => Const(a + b)
case _ => Add(f1, f2)
}
}
它会起作用,但这可能不是您想要的。 解决此问题的方法是在静态上下文中定义case class
。 您可以按照建议的@nicodp在顶级级别上进行操作。 另一个选择是将它们放置在Function
作为一个伴随对象,如下所示:
sealed trait Function
object Function {
case class Const(value: Double) extends Function
case class Param(value: String) extends Function
case class Var(value: String) extends Function
case class Add(f1: Function, f2: Function) extends Function
}
object Op {
import Function._
def som(f1: Function, f2: Function): Function =
(f1, f2) match {
// case (HelloWorld.Const(a), HelloWorld.Const(b)) => Const(a + b)
case (Const(a), Const(b)) => Const(a + b)
case _ => Add(f1, f2)
}
}
object HelloWorld {
import Function._
def main(args: Array[String]): Unit = {
val s = Op.som(Const(3), Const(5))
println(s)
}
}
请注意,您更换extends Function
与import Function._
另请注意,建议对此类特征使用sealed
,以便您(编译器)知道您的模式匹配是详尽的。
您创建的类型取决于路径 。 将类型声明更改为此:
trait Function
object Function {
case class Const(value: Double) extends Function
case class Param(value: String) extends Function
case class Var(value: String) extends Function
case class Add(f1: Function, f2: Function) extends Function
}
import Function._
使用原始定义,需要在相同的Function
对象内部创建Const
以进行匹配。 您在Op
内进行匹配,但是要在HelloWorld
内创建要匹配的Const
,因此,您Op.Const
内匹配HelloWorld.Const
。
为什么Op
和HelloWorld
源自Function
特性有什么原因吗? (您在示例中没有使用它,但是也许您出于某些原因)。 对我而言,以下内容看起来更自然:
object HelloWorld {
def som(f1:Function, f2: Function): Function = {
(f1, f2) match {
case (Const(a), Const(b)) => Const(a + b)
case _ => Add(f1, f2)
}
}
def main(args: Array[String]): Unit = {
val s = som(Const(3),Const(5))
println(s)
}
}
在Scala
定义Haskell
这一部分:
data Fonction =
Const Float
| Param String
| Var String
| Add Fonction Fonction
我将进行如下操作:
trait Function
case class Const(v: Float) extends Function
case class Param(v: String) extends Function
case class Var(v: String) extends Function
case class Add(f1: Function, f2: Function) extends Function
现在您的代码将按预期工作:
scala> HelloWorld.main(Array())
Const(8.0)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.