在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))
答案 0 :(得分:3)
Although @nicodp code is technically correct (but IMHO not quite), it provides no explanation. The reason why your code doesn't work as expect is because you define your cases inside trait Function
. The thing is that in the Java world inner classes can be static and non-static and Scala copies this part of the behavior. And classes defined inside a trait
are non-static. Particularly it means that an instance of HelloWorld.Const(42)
is not equal to an instance of Op.Const(42)
because they capture different "outer" values of different types (the Op
object and the HelloWorld
object). And this is also why your pattern matching doesn't work as you might expect. If you make you write your pattern matching as:
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)
}
}
it will work but this is probably not what you want. The way to work this around is to define your case class
es in a static context. You may do it in just top level as in @nicodp suggested. Another choice is to put them into a Function
a companion object like this:
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)
}
}
Note that you replace extends Function
with import Function._
Also note that it is suggested to use sealed
on such traits so you (compiler) know your pattern-matching is exhaustive.
答案 1 :(得分:2)
您创建的类型为path dependent。将类型声明更改为:
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._
根据您的原始定义,需要在相同的Const
对象内创建Function
才能匹配。您在Op
内部匹配,但您匹配的Const
是在HelloWorld
内创建的,因此您HelloWorld.Const
再次匹配Op.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)
}
}
答案 2 :(得分:1)
在Haskell
中定义Scala
这段内容:
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)