[英]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.