2011-12-18 16 views
5
def foo(num:Int, str:String):Int = 1 

val bar = foo(3, _) // compiler complains "missing parameter type for expanded function ((x$1) => test(3, x$1))" 

val baz = foo(3, _:String) // compiles fine 

なぜコンテキストから推測できないのかを明示的に指定する必要がありますか?部分的に適用される関数定義の冗長パラメータ型情報

EDIT:David Soergelの提案に基づいて名前が衝突しないように名前が変更されました。すべての

答えて

3

まず、「DEFテスト」および「valのテスト」との混同を避けるために、のは、書いてみましょう:文脈からinferrable何

def foo(num:Int, str:String):Int = 1 

val bar = foo(3, _) // compiler complains "missing parameter type for expanded function ((x$1) => foo(3, x$1))" 

val baz = foo(3, _:String) // compiles fine 

は、引数が何らかの形で文字列に変換可能でなければならないバーするだけということです。これは継承(Stringの代わりにいくつかの非最終型を使用している場合)または暗黙的な変換によるものである可能性があります。

潜在的に暗黙の可能性は、barの引数がまったくどの型にもなりうることを意味します。したがって、記述されたコードは実際にはあまり指定されていません。コンパイラが「欠落している型」のエラーを発行する前にスコープ内に適切な暗黙の変換があるかどうかを実際にチェックするかどうかはわかりませんが、私は推測しません。 (ストリングの場合は、とにかく束が存在する可能性が高い)。文字列を生成する新しい暗黙的な関数をインポートした結果、bazのシグネチャが変更された場合、脆く混乱します。私はデビッドSoergelの説明は、本質的に正しいと思い

+1

ありがとうございます。しかし、 'def foo(num:Int)= 1; val bar = foo(_) 'がうまくコンパイルされます。だから私は相続または暗黙の変換がエラーを引き起こすとは思わない。 – xiefei

+0

ああ、申し訳ありませんが、私の議論についてのさらなる議論は、とにかく意味がありません。コンパイラは実際にはbar引数の型をStringに推論してから、いつものようにbarを呼び出すときにimplicitsを許可することができます。 –

3

:タイプTは、[文字列への暗黙の型変換val bar = foo(3, _:T)を持っている場合は、String => Intに無関係である、タイプT => Intの機能を与え、有効です。

コンパイラが(明示的な型定義がないと)型が実際には(あなたの質問の本質である)同じであるという合理的な仮定をしないのはなぜですか?私はそれが言語仕様を複雑にするためだと推測することができます。

タイプが指定されていない場合、つまりval bar = foo(_, _)の場合、コンパイラはそれをval bar = foo _と同じ単純なη変換と解釈して、String => Intとなります。簡単barの種類を見ることが

私の好適なイディオムはあなたを可能にする利点を持っている左側の機能の種類を与えるために次のようになります。

val bar: String => Int = foo(3, _) 

あなたは再にアレルギーならStringという単語を入力すると、

val bar = (foo _).curried(3) 
+0

"無名関数のプレースホルダ構文"スカラ仕様(2.8)の一部には、 "_"の型がどのように推論されるかについての情報はありません。 specの不足は、このコンパイラの不一致の原因になる可能性があります。 – xiefei

関連する問題