繁体   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