web-dev-qa-db-ja.com

無名関数の引数の型は完全にわかっている必要があります。 (SLS 8.5)

関数リテラルがあります

_{case QualifiedType(preds, ty) =>
               t.ty = ty ;
               Some((emptyEqualityConstraintSet,preds)) }
_

エラーメッセージが表示されます

_missing parameter type for expanded function The argument types of an anonymous function
must be fully known. (SLS 8.5) Expected type was:
? => Option[(Typer.this.EqualityConstraintSet, Typer.this.TypeRelationSet)]
_

SLS 8.5 を調べましたが、説明が見つかりませんでした。

自分で機能を拡張すると

_{(qt : QualifiedType) =>
  qt match {case QualifiedType(preds, ty) =>
               t.ty = ty ;
               Some((emptyEqualityConstraintSet,preds)) }}
_

エラーはなくなります。

(a)なぜこれがエラーなのですか?

(b)修正するにはどうすればよいですか?

パターンと=>の間に_: QualifiedType_を追加するという明らかな修正を試みましたが、これは構文エラーです。


気づいたことの1つは、コンテキストによって違いが生じることです。 _QualifiedType => B_を期待して宣言された関数の引数として関数リテラルを使用しても、エラーは発生しません。しかし、_A => B_が必要な関数の引数として使用すると、エラーが発生します。ここで起こっていることは、パターンがQualifiedTypeのスーパータイプであるオブジェクトにおそらく適用される可能性があるので、コンパイラが関数が適用されないという保証なしに明白なタイプを割り当てることを望んでいないことですQualifiedTypeではないもの。本当に私が望んでいるのは、{QualifiedType( preds, ty) => ...}を記述して、Haskellの\QualifiedType(preds,ty) -> ...と同じ意味を持たせることです。

33

これが SLS quote です。

このような式の予想されるタイプは、部分的に定義する必要があります。どちらかである必要がありますscala.Functionk[S1, . . . , Sk, R]一部のk> 0の場合、またはscala.PartialFunction[S1, R]、ここで引数のタイプS1 、. 。 。 、Skは完全に決定される必要がありますが、結果のタイプRは不定になる可能性があります。

そうでなければ、あなたはあなたの質問に答えました。

7
som-snytt

{ case X(x) => ... }は部分関数ですが、Xのスーパータイプであることを除いて、コンパイラーは入力タイプが何であるかをまだ認識していません。匿名関数を作成している場合、型はコンテキストからわかるため、通常これは問題になりません。しかし、ここにタイプを提供する方法があります:

case class Foo(x: Int)

// via annotation
val f: Foo => Int = { case Foo(x) => x }

// use pattern matching
val f = (_: Foo) match { case Foo(x) => x }

// or more normally, write as a method
def f(a: Foo) = a match { case Foo(x) => x }
def f(a: Foo) = a.x

おそらくお気づきのように、ここで関数リテラル/パターンマッチングを使用しても、まったく無意味です。あなたの場合は通常の方法が必要なようです:

def whatever(qt: QualifiedType) = {
  t.ty = qt.ty
  Some((emptyEqualityConstraintSet, qt.preds)) 
}

ただし、変更可能な状態を削除するにはリファクタリングする必要があります。

これが、関数リテラルを使用したかったため、型を2回繰り返す必要がなかった理由です。すべてのオプションマッチングコードを除外するために、独自の制御構造を構築しようとしていました。オーバーヘッドが多すぎる場合、制御構造は役に立ちません。これが私がやりたかったことです

//This is the control construct definition
def switch[A,B]( x : Option[A], noneFun : =>B, someFun : A=>B) = x match {
    case None => noneFun 
    case Some(y) => someFun(y) }

//And this is an example of using it.
def foobar( qt : Option[QualifiedType]  ) = 
    switch( qt, {reportError("SNAFU");None},
            {case QualifiedType(preds, ty) =>
               Some((emptyEqualityConstraintSet,preds)) } ) 

スイッチ制御コンストラクトは正常にコンパイルされますが、SLSがAがある場所には「明確な型」が必要であるとSLSが言っているため、使用法によりエラーが発生しました。これは、この種の関数リテラル( "case"を含む種類)は、引数が正当なものである可能性がある部分的な関数を対象としているためです。私は関数リテラルをintで論じることができましたが、それは型エラーではなく、すべてのパターンが失敗するという問題にすぎません。したがって、コンパイラは、「拡張関数リテラル」のパラメータにどのタイプを意図するかを知るために「トップダウン」情報を必要とします。

{(x : X) => x match {case Some(QualifiedType(preds, ty)) =>
               Some((emptyEqualityConstraintSet,preds)) } }

コンパイラがスイッチのタイプを使用して、部分的な関数を意図していないことを確認できず、AをQualifiedTypeと統合できないのはなぜでしょうか。しかし、そうではありません。

とにかくそれはコンパイルされません。ただし、AをAnyに置き換えると、エラーがなくなります。次のコードは実際にコンパイルされます。私が失うのは、いくつかの型チェックです。

//This is the control construct definition
def switch[A,B]( x : Option[A], noneFun : =>B, someFun : A=>B) = x match {
    case None => noneFun 
    case Some(y) => someFun(y) }

//And this is an example of using it.
def foobar( qt : Option[QualifiedType]  ) = 
    switch( qt, {reportError("SNAFU");None},
            {case QualifiedType(preds, ty) =>
               Some((emptyEqualityConstraintSet,preds)) } ) 

(a)上記のスイッチの定義を改善できるかどうか、および(b)必要なことを実行するライブラリー関数がすでにあるかどうかを知りたいです。


Luigiのコメントの後に追加

これが最終的なコードです。はい、私はそれがフォールド(カタモフィズム)だと思います。

def switch[A,B]( x : Option[A])(noneFun : =>B, someFun : A=>B) = x match {
    case None => noneFun 
    case Some(y) => someFun(y) }

def foobar( qt : Option[QualifiedType]  ) : Option[(EqualityConstraintSet, TypeRelationSet)] =
    switch( qt )({reportError("SNAFU");None},
            {case QualifiedType(preds, ty) =>
               Some((emptyEqualityConstraintSet,preds)) } ) 

ルイージに感謝します。

4