2

为了更好地学习 Scala,我正在玩一些基本的编程练习,但我一直在试图弄清楚为什么我的代码不会进行类型检查。

症结在于possibilities功能。我想要一个函数,它返回一个流,其中包含给定数字列表的所有可能的数字排列和数学运算符。

我很困惑,因为将函数的返回类型更改为Stream[Object]可以很好地读取类型检查并返回似乎是方程流的结果。但是,下面包含的版本没有类型检查,返回类型possibilites设置为Stream[Equation]

附带说明一下,我知道在 opsMix 中附加卡片不会将Operations 置于正确的顺序,但我想先解决这部分问题。我想我会使用flatMapor zipAllwithflatten来完成那部分。

另外 -这不是家庭作业!

abstract class Operation
case class Add() extends Operation
case class Subtract() extends Operation
case class Multiply() extends Operation
case class Divide() extends Operation
case class Num(val valu: Float) extends Operation

type Equation = List[Operation]

def calc(equa: Equation): Float =
  equa match {
    case Num(x) :: List() => x
    case Num(x) :: y :: Num(z) :: xs => y match {
      case Add() => calc( Num(x + z)::xs )
      case Subtract() => calc( Num(x - z)::xs )
      case Multiply() => calc( Num(x * z)::xs )
      case Divide() => calc( Num(x / z)::xs )
    }
    case _ => 0
  }

// from http://stackoverflow.com/questions/1070859/listing-combinations-with-repetitions-in-scala
def mycomb[T](n: Int, l: List[T]): List[List[T]] =
  n match {
    case 0 => List(List())
    case _ => for(el <- l;
              sl <- mycomb(n-1, l dropWhile { _ != el } ))
              yield el :: sl
}
def comb[T](n: Int, l: List[T]): List[List[T]] = mycomb(n, l.removeDuplicates)

val ops = List(Add, Subtract, Multiply, Divide)
def possibilities(cards: List[Num]) : Stream[Equation] =
  { for {
      hand <- cards.permutations
      opMix <- comb(cards.length-1, ops)
    } yield hand ++ opMix
  }.toStream

// test value:
val ppp = possibilities(List(Num(20), Num(3), Num(7), Num(100)))
4

1 回答 1

4

问题是您将操作案例类声明为Add()etc.,但在val ops您使用List(Add, ...). 如果您尝试ops使用正确的类型声明:

val ops: List[Operation] = List(Add, Subtract, Multiply, Divide)

你会看到错误。(这就是为什么自己添加类型而不是依赖类型检查器通常很有帮助 - 它有助于发现错误。)

我建议您更新您的类层次结构以case object用于单例操作:

  abstract class Operation
  case object Add extends Operation
  case object Subtract extends Operation
  case object Multiply extends Operation
  case object Divide extends Operation
  case class Num(val valu: Float) extends Operation

当然,您还需要更新您的模式:

  def calc(equa: Equation): Float =
    equa match {
      case Num(x) :: List() => x
      case Num(x) :: y :: Num(z) :: xs => y match {
        case Add => calc( Num(x + z)::xs )
        case Subtract => calc( Num(x - z)::xs )
        case Multiply => calc( Num(x * z)::xs )
        case Divide => calc( Num(x / z)::xs )
      }
      case _ => 0
    }

然后possibilities按预期工作,无需任何更改。

或者,您可以保留课程的方式,只需更改ops

val ops: List[Operation] =
    List(Add(), Subtract(), Multiply(), Divide())

更新: 关于交错,您可以执行以下操作:

def interleave[T](xs: List[T], ys: List[T], padX: T, padY: T): List[T] =
  xs.zipAll(ys, padX, padY).flatMap(pair => List(pair._1, pair._2))

但请注意,结果将始终包含偶数个元素。也许更好的解决方案是实现interleave自己,例如:

def interleave[T](xs: List[T], ys: List[T]): List[T] = {
  import collection.mutable._;
  @annotation.tailrec
  def f(xs: List[T], ys: List[T], r: Buffer[T]): Buffer[T] =
    xs match {
      // By swapping the arguments, we get interelaving:
      case x :: xrest   => f(ys, xrest, r += x);
      case Nil          => r ++= ys;
    }
  return f(xs, ys, new ArrayBuffer[T]).toList;
}

但是,我想说更好的解决方案是不要混合操作和数字。相反,您可以为由符号形成的格式良好的表达式声明一个特殊类,例如(未经测试):

sealed abstract class Symbol
sealed abstract class Operation extends Symbol
case object Add Operation
case object Subtract extends Operation
case object Multiply extends Operation
case object Divide extends Operation
case class Num(val valu: Float) extends Symbol

sealed abstract class Expression;
case class App(val op: Operation, val arg1: Expression, val arg2: Expression)
  extends Expression;
case class Const(val n: Num)
  extends Expression;

而不是创建交错列表,而是创建Expression.

于 2013-02-17T20:50:42.197 回答