3

次のコードスニペットについて考えてみます。これは、元の問題の縮小版です。

case class RandomVariable[A](values: List[A])
case class Assignment[A](variable: RandomVariable[A], value: A)

def enumerateAll(vars: List[RandomVariable[_]], evidence: List[Assignment[_]]): Double = 
  vars match {
    case variable :: tail =>
      val enumerated = for {value <- variable.values
        extendedEvidence = evidence :+ Assignment(variable, value)
      } yield enumerateAll(tail, extendedEvidence)
      enumerated.sum
    case Nil => 1.0
  }

これは、必要なタイプのときにvariableタイプがあると推測されたコンパイル時エラーで失敗します。なぜ型も推測されないのですか?を使用してコンパイラーにヒントを与えるために実存型に名前を付けてみましたが、それもコンパイルされませんでした(T型が見つからなかったため、説明にも興味があります)。RandomVariable[_0]AssignmentAny value _0case (variable: RandomVariable[T forSome {type T}]) :: tail =>

さらなる動機付けのために、次のようにタイプパラメータをキャプチャするときを検討してください。

case variable :: tail =>
  def sum[A](variable: RandomVariable[A]): Double = {
    val enumerated = for {value <- variable.values
      extendedEvidence = evidence :+ Assignment(variable, value)
      } yield enumerateAll(tail, extendedEvidence)
    enumerated.sum
  }
  sum(variable)

これは警告/エラーなしでコンパイルされます。この余分な機能を必要としないように最初の例で変更できるものはありますか?

編集:より明確にするために、型であり、すべての値がinから来ているのに、なぜvalue型であると推論されないのか知りたいです。また、コンパイラにこの事実を伝えるための追加の方法があるかどうかを知りたいです(上記のように関数で型をキャプチャする以外に)。_0variable_0List[_0]variable

4

3 に答える 3

1

別のコンパイルソリューション、つまり、関数を使用して型をキャプチャするよりもクリーン(?)です。ただし、元のケースで型推論が失敗する理由については、さらに不可解になります。

def enumerateAll(vars: List[RandomVariable[_]], evidence: List[SingleAssignment[_]]): Double = vars match {
  case (variable@RandomVariable(values)) :: tail =>
    val enumeration = for {value <- values
      assignment = SingleAssignment(variable, value)
      extendedEvidence = evidence :+ assignment
    } yield enumerateAll(tail, extendedEvidence)
    enumeration.sum
  case Nil => 1.0
}

また、次の警告が返されます。

scala: match may not be exhaustive.
It would fail on the following input: List((x: questions.RandomVariable[?] forSome x not in questions.RandomVariable[?]))
  def enumerateAll(vars: List[RandomVariable[_]], evidence: List[SingleAssignment[_]]): Double = vars match {

この投稿の時点では解読できません。RandomVariableまた、いくつかのテストケースで実行すると、パラメーターリストでint、double、およびstringのsを 使用して、一致エラーなしで目的の結果が生成されます。

于 2013-01-10T06:03:40.850 に答える
0

RandomVariableとAssignmentのタイプを一緒にバインドするべきではありませんか?

 def [A] enumerateAll(vars: List[RandomVariable[A]], evidence: List[Assignment[A]]): Double = 

実際、あなたはもっと寛容になり、ただ言うことができます

 def [A] enumerateAll(vars: List[RandomVariable[A]], evidence: List[Assignment[_ <: A]]): Double = 
于 2013-01-10T04:21:52.647 に答える
0

エラーコードは、解決策を示しています。

<console>:15: error: type mismatch;
 found   : RandomVariable[_0] where type _0
 required: RandomVariable[Any]
Note: _0 <: Any, but class RandomVariable is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
           extendedEvidence = evidence :+ Assignment(variable, value)

これは、推測よりも具体的な型が見られ、RandomVariableで共変Aを許可するように提案されていることを示しています。これにより、必要に応じて型を下方に変更できます。

case class RandomVariable[+A](values: List[A])

または、両方のパラメーターのenumerateAllでジェネリック型を明示的に設定することもできます。このようにして、Anyを推測するのではなく、適切なタイプを推測できます。両方のパラメーターが同じタイプであるため、この定義ではRandomVariable共変量の変更は必要ありません。

def enumerateAll[A](vars: List[RandomVariable[A]], evidence: List[Assignment[A]]): Double = 

この質問は説明に役立つかもしれません。なぜ例がコンパイルされないのですか、別名(co-、contra-、およびin-)分散はどのように機能しますか?

于 2013-01-10T05:40:36.240 に答える