2013-02-17 41 views
2

我正在玩一些基本的编程练习,以更好地学习Scala,但我坚持试图找出为什么我的代码不会输入check。我想我的函数返回一个流[T],但我不知道如何使它类型检查

该问题的关键是possibilities函数。我想要一个函数返回一个包含数字和数学运算符的所有可能排列的数据流。

我很困惑,因为改变函数的返回类型来读取Stream[Object]类型检查就好了,并返回看起来是等式流的结果。但是,包含在以下的版本不会类型检查,返回类型possibilites设置为Stream[Equation]

作为一个方面说明,我知道用卡添加opsMix并不会将Operation按正确顺序排列,但我想先解决这部分问题。我想我会用flatMapzipAllflatten来完成那部分。

另外 - 这不是一项家庭作业!

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

的问题是,你宣布你的操作案例类作为Add()等,但在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一个实例。

+0

谢谢,很好的答案。你的建议是完全正确的。现在,当按照我的计划尝试使用zipAll和flatten时,我遇到了另一个类型相关的错误......将“card”和“opMix”项以交错顺序排列的第一个想法是什么? – 2013-02-17 21:37:21

+0

@DustMason我给答案增加了一些想法。 – 2013-02-17 22:57:44

+0

非常有帮助,谢谢!您的最终建议对我来说更像是“scala方式”,因为它可以通过定义明确的类型类来解决问题。 – 2013-02-18 01:00:38

相关问题