2016-07-13 7 views
3

私は以前この質問をした:Combine a PartialFunction with a regular function匿名部分写像構文

、その後実現し、私は実際にそれを右に尋ねていないこと。 別の試みがここにあります。私はこれを行う場合は

val foo = PartialFunction[Int, String] { case 1 => "foo" } 
val bar = foo orElse { case x => x.toString } 

をそれがコンパイルされません:error: missing parameter type for expanded function The argument types of an anonymous function must be fully known. (SLS 8.5) Expected type was: PartialFunction[?,?]

しかし、これは正常に動作します:

val x: Seq[String] = List(1,2,3).collect { case x => x.toString } 

質問は差がある何ですか?引き数のタイプは、両方のケースで同じです:PartialFunction[Int, String]。渡された値は文字通り同一です。なぜ1つのケースが動作するのですが、もう1つは動作しませんか?

+1

'orElse'は' [A1 <: A, B1 >:B]期待しながらcollect'が ''部分写像[A、B]期待コンパイラは最初に推測することができつつ、部分写像[A1、B1]を 'あなたは、何とか2番目の助けを必要とします。 –

+0

ありがとう、@PeterNeyens、それは私のために説明します。あなたが約25ポイントの担当者を気にしていると答えて投稿してください。 bump :) – Dima

答えて

0

barの型を指定する必要があります。これは、コンパイラがその型を推測できないためです。これは、コンパイル:List(1,2,3).collect{case x => x.toString}の場合、コンパイラは

val foo = PartialFunction[Int, String] { case 1 => "foo" } 
val bar : (Int => String) = foo orElse { case x => x.toString } 
+0

この場合、呼び出される '' orElse'''メソッドは、PartialFunctionではなくFunctionにあります。これは、コンパイラがちょうど仮定することを望まない、これに関する別のあいまいさを示しています。私はOPが最後に機能を望んでいるかどうかはわかりません。 –

+0

@ScottShippあなたは本当ですか? 'Function'の' orElse'はどこですか?そしてそれは何をするのですか? – Dima

+0

@henrik、私はそれがそれを推論することができないことを認識します。問題はそれを推論することができず、なぜそれが他の場合に推論できるのかということでした。 – Dima

0

Listが入力された方法のオフに基づいて、部分関数の入力タイプを推測することができます。

final override def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[List[A], B, That]) 

型パラメーターに基づいて、コンパイラーは、型指定された部分関数を渡すことを推論できます。そのため、List(1,2,3).collect{case x:String => x.toString}はコンパイルされず、List(1,2,3).collect{case x:Int => x.toString; case x: String => x.toString}もありません。

Listは共変であるため、コンパイラは部分関数{case x => x.toString}Intの部分関数であると推測できます。コンパイラがIntまたはサブクラスIntのいずれかで操作していると推測するため、List(1,2,3).collect{case x => x.length}はコンパイルされません。

{case x => x.toString}は構文上の砂糖です。私たちは以下のような何かを行う場合は、あなたの例では、期待される

val f = new PartialFunction[Int, String](){ 
    override def isDefinedAt(x: Int): Boolean = true 
    override def apply(v1: Int): String = v1.toString 
} 

val foo = PartialFunction[Int, String] { case 1 => "foo" } 

val bar = foo orElse f //This compiles fine. 

List(1,2,3).collect{f} // This works as well. 

として働くので、私の観点からの唯一の論理的な答えは{case x => x.toString}ためPartialFunctionインスタンスを生成することができる糖衣構文は、コンパイル時に十分な情報を持っていないということですあなたのorElseケースにPartialFunction[Int, String]として適切に入力できるようになります。

+0

あなたは 'applyOrElse'を実装していないので、これは完璧な解決策ではありません。 'applyOrElse'はパフォーマンスを改善します。 –

0

ライブラリExtractor.scalaを使用できます。

import com.thoughtworks.Extractor._ 

// Define a PartialFunction 
val pf: PartialFunction[Int, String] = { 
    case 1 => "matched by PartialFunction" 
} 

// Define an optional function 
val f: Int => Option[String] = { i => 
    if (i == 2) { 
    Some("matched by optional function") 
    } else { 
    None 
    } 
} 

// Convert an optional function to a PartialFunction 
val pf2: PartialFunction[Int, String] = f.unlift 

util.Random.nextInt(4) match { 
    case pf.extract(m) => // Convert a PartialFunction to a pattern 
    println(m) 
    case f.extract(m) => // Convert an optional function to a pattern 
    println(m) 
    case pf2.extract(m) => // Convert a PartialFunction to a pattern 
    throw new AssertionError("This case should never occur because it has the same condition as `f.extract`.") 
    case _ => 
    println("Not matched") 
} 
関連する問題