Scala相当于Haskell模式在构造函数上匹配

时间:2018-01-23 18:42:39

标签: scala haskell

在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))

3 个答案:

答案 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 classes 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

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)
  }
}

答案 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)