簡體   English   中英

相當於Haskell模式匹配的Scala構造函數

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

為什么OpHelloWorld源自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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM