Скала, частичные функции - PullRequest
8 голосов
/ 14 апреля 2011

Есть ли способ создать PartialFunction, кроме как с помощью оператора case?

Мне любопытно, потому что я хотел бы выразить следующее (псевдо вперед!) ...

val bi = BigInt(_)
if (bi.isValidInt) bi.intValue

... как частичная функция и выполняет

val toInt : PartialFunction[String, Int] = {
    case s if BigInt(s).isValidInt => BigInt(s).intValue
}

кажется избыточным, так как я создаю BigInt дважды.

Ответы [ 5 ]

5 голосов
/ 14 апреля 2011

Не уверен, что понимаю вопрос. Но вот моя попытка: почему бы не создать экстрактор?

object ValidBigInt {
  def unapply(s: String): Option[Int] = {
    val bi = BigInt(s)
    if (bi.isValidInt) Some(bi.intValue) else None
  }
}

val toInt: PartialFunction[String, Int] = {
  case ValidBigInt(i) => i
}

Другой вариант (и это может ответить на вопрос о том, можно ли создать PartialFunction, кроме литерала case):

val toInt = new PartialFunction[String, Int] {
  def isDefinedAt(s: String) = BigInt(s).isValidInt
  def apply(s: String) = BigInt(s).intValue
}

Однако, поскольку идея частичной функции заключается в том, что она определена только частично, в конце концов вы все равно будете делать лишние вещи - вам нужно создать большое целое число, чтобы проверить, является ли оно допустимым, а затем в приложении-функции, которое вы создаете опять большой int ...

Я видел проект на Github , который пытался обойти это, несколько кешируя результаты isDefinedAt. Если вы перейдете к тестам, вы увидите, что он оказался медленнее, чем стандартная реализация Scala:)

Так что, если вы хотите обойти двойную природу isDefinedAt против apply, вы должны просто перейти к (полной) функции, которая обеспечивает Option[Int] в качестве результата.

4 голосов
/ 15 ноября 2011

Я думаю, вы ищете лифт / лифт. Лифт принимает частичную функцию и превращает ее в функцию, которая возвращает Option. Unlift принимает функцию с одним аргументом, которая возвращает опцию, и возвращает частичную функцию.

import scala.util.control.Exception._

scala> def fn(s: String) = catching(classOf[NumberFormatException]) opt {BigInt(s)}
fn: (s: String)Option[scala.math.BigInt]

scala> val fnPf = Function.unlift(fn)
fnPf: PartialFunction[String,scala.math.BigInt] = <function1>

scala> val fn = fnPf.lift
fn: String => Option[scala.math.BigInt] = <function1>

Тесно связанный, вы также хотите посмотреть на этот ответ для получения информации о cond и condOpt:

scala> import PartialFunction._
import PartialFunction._

scala> cond("abc") { case "def" => true }
res0: Boolean = false

scala> condOpt("abc") { case x if x.length == 3 => x + x }
res1: Option[java.lang.String] = Some(abcabc)
3 голосов
/ 15 апреля 2011

Вы можете написать PartialFunction "длинную руку", если хотите:

object pf extends PartialFunction[Int,String] {
  def isDefinedAt(in: Int) = in % 2 == 0

  def apply(in: Int) = {
    if (in % 2 == 0) 
      "even" 
    else 
      throw new MatchError(in + " is odd")
}
1 голос
/ 06 марта 2012

Хорошо, я получил это

import java.lang.NumberFormatException
import scala.util.control.Exception._

val toInt: PartialFunction[String, Int] = {
  catching(classOf[NumberFormatException]) opt BigInt(_) match {
    case Some(bi) if bi.isValidInt => bi.intValue
  }
}
0 голосов
/ 15 сентября 2011

Как насчет этого?

val toInt: PartialFunction[String, Int] = (s: String) => BigInt(s) match {
  case bi if bi.isValidInt => bi.intValue
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...