2

Scala をよりよく学習するために、いくつかの基本的なプログラミング演習を行っていますが、コードが型チェックを行わない理由を突き止めようとしています。

こだわりポイントはpossibilities機能です。数値のリストを指定して、数値と数学演算子のすべての可能な配置を含むストリームを返す関数が必要です。

Stream[Object]関数の戻り値の型を型チェックを読み取るように変更すると、問題なく方程式のストリームのように見える結果が返されるため、私は混乱しています。ただし、以下に含まれるバージョンは、戻り値の型が に設定されている型チェックを行いませんpossibilitesStream[Equation]

補足として、カードに opsMix を追加するとOperations が正しい順序にならないことは理解していますが、最初に問題のこの部分を解決したいと思います。その部分を達成するためにflatMapor zipAllwithを使用すると思います。flatten

また、これは宿題ではありません。

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 に答える