2016-07-13 4 views
3
частично определённая функция

Я задал этот вопрос раньше: Combine a PartialFunction with a regular functionAnonymous синтаксис

, а потом понял, что я на самом деле не спросил его правильно. Итак, вот еще одна попытка.

Если я это сделать:

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

'collect' ожидает' [A частично определённой функции, B] 'а' orElse' ожидает '[A1 <: A, B1 >: B] частично определённая функция [A1, B1] ', так что в то время как компилятор может вывести первый, вам как-то нужно помогать со вторым. –

+0

Спасибо, @PeterNeyens, что объясняет это для меня. Опубликуйте его как ответ, вы заботитесь о 25 пунктах. bump :) – Dima

ответ

0

Необходимо указать тип для bar, потому что компилятор не может его вывести. Это составляет:

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

В этом случае метод '' orElse'', который вызывается, находится в функции, а не в PartialFunction. Это иллюстрирует еще одну двусмысленность вокруг этого, что вы не хотите, чтобы компилятор просто предположил. Я не уверен, что OP хочет функцию в конце. –

+0

@ScottShipp вы уверены? где 'orElse' в' Function'? И что он делает? – Dima

+0

@henrik, я понимаю, что он неспособен сделать это. Вопрос заключался в том, почему он не может это сделать и почему он может сделать это в другом случае. – Dima

0

В случае List(1,2,3).collect{case x => x.toString} компилятор может определить тип ввода частичной функции на основе от того, как 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. Вы заметите, что List(1,2,3).collect{case x => x.length} не компилируется, потому что компилятор выдает, что вы работаете либо с Int, либо с подклассом Int.

Также имейте в виду, что {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. 

Таким образом, единственный логический ответ с моей точки зрения является то, что синтаксический сахар, который способен генерировать PartialFunction экземпляр для {case x => x.toString} не имеет достаточно информации по компиляции чтобы иметь возможность адекватно ввести его как PartialFunction[Int, String] в вашем orElse корпусе.

+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") 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^