在我看来{ case ... => ... },部分函数的语法至少需要一个case:
scala> val pf: PartialFunction[String, String] = { case "a" => "b" }
pf: PartialFunction[String,String] = <function1>
scala> val pf: PartialFunction[String, String] = { }
<console>:5: error: type mismatch;
found : Unit
required: PartialFunction[String,String]
val pf: PartialFunction[String, String] = { }
^
Run Code Online (Sandbox Code Playgroud)
那么,定义"空"部分函数的最佳方法是什么?难道还有比"手动"覆盖更好的办法isDefinedAt和apply?
只要我们有一个PartialFunction[X,R]很容易将它转换为返回的函数Option[R],例如
def pfToOptf[X, R](f: PartialFunction[X,R])(x: X) =
if (f.isDefinedAt(x)) Some(f(x))
else None
Run Code Online (Sandbox Code Playgroud)
但是,如果任务相反,那该怎么办:假设我有一个函数作为参数f获取X并返回Option[R]结果.我想做出一个PartialFunction[X,R].什么是最好的方法?
我想出来的东西看起来很丑陋我的口味:
def optfToPf[X,R](f: X => Option[R]) : PartialFunction[X,R] = {
object extractor {
def unapply(x: X): Option[R] = f(x)
}
{ case extractor(r) => r }
}
Run Code Online (Sandbox Code Playgroud)
我错过了一些更好的方法吗?
我有两个PartialFunctions f和g.它们没有副作用,可以快速执行.将它们组成另一个部分函数的最佳方法是什么h,
h.isDefinedAt(x)iff f.isDefinedAt(x) && g.isDefinedAt(f(x))?
如果h函数返回Option而不是部分函数,也可以.
我很失望,f andThen g没有做我想做的事:
scala> val f = Map("a"->1, "b"->2)
f: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)
scala> val g = Map(1->'c', 3->'d')
g: scala.collection.immutable.Map[Int,Char] = Map(1 -> c, 3 -> d)
scala> (f andThen g).isDefinedAt("b")
res3: Boolean = true
scala> (f andThen g).lift("b")
java.util.NoSuchElementException: key not found: 2
at scala.collection.MapLike$class.default(MapLike.scala:228)
Run Code Online (Sandbox Code Playgroud) PartialFunction简而言之,在Scala中,a 是另外定义isDefinedAt方法的函数.
使用一系列case语句很容易定义部分函数.一个简单的例子是,例如:
scala> val pf: PartialFunction[Int, Unit] = {
| case 42 => ()
| }
pf: PartialFunction[Int,Unit] = <function1>
scala> pf.isDefinedAt(42)
res0: Boolean = true
scala> pf.isDefinedAt(0)
res1: Boolean = false
Run Code Online (Sandbox Code Playgroud)
isDefinedAt从case定义部分函数的s 列表中自动生成.
Lift框架在许多地方使用部分功能,例如定义一个请求是应该由Lift的引擎处理还是直接从磁盘上的文件提供服务.有时候,我发现自己想要编写一个case匹配所有输入参数的语句,然后才决定是否要返回一个值.这意味着cases 的初始序列不再足以确定我的函数是否定义在给定值
例如,在Lift中,我想添加一个规则,直接提供所有html和htm文件,并且应该处理带有"lift"扩展名的文件.做这样的事情会很容易:
LiftRules.liftRequest.prepend {
case Req(path, extension, tpe) => extension match {
case "html" | "htm" => false
case "lift" => true
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,在这种情况下,编译器认为我的部分函数是在任何地方定义的,因为第一个case总是匹配.嵌套match可能与所有传入请求不匹配.而且,请求是不匹配的,MatchError …
我认为PartialFunction可以是Monoid.我的思维过程是否正确?例如,
import scalaz._
import scala.{PartialFunction => -->}
implicit def partialFunctionSemigroup[A,B]:Semigroup[A-->B] = new Semigroup[A-->B]{
def append(s1: A-->B, s2: => A-->B): A-->B = s1.orElse(s2)
}
implicit def partialFunctionZero[A,B]:Zero[A-->B] = new Zero[A-->B]{
val zero = new (A-->B){
def isDefinedAt(a:A) = false
def apply(a:A) = sys.error("error")
}
}
Run Code Online (Sandbox Code Playgroud)
但目前的版本Scalaz(6.0.4)不包括在内.没有包含某些东西的原因是什么?
为了实现互操作性,我需要从Java代码传递Scala PartialFunction.对于Function(Function1等),我可以使用匿名类型对AbstractFunction进行子类化,但对PartialFunction执行相同操作的最简单方法是什么?
在这种情况下,我很乐意将它作为Java中的"完整"函数,出现为所有值定义,但键入为PartialFunction.
让我们重用Daily scala中的示例:
type PF = PartialFunction[Int,Int]
val pf1 : PF = {case 1 => 2}
val pf2 : PF = {case 2 => 3}
Run Code Online (Sandbox Code Playgroud)
让我们补充一下:
val pf3 : PF = {case 3 => 4}
Run Code Online (Sandbox Code Playgroud)
然后按预期工作:
pf1 andThen pf2 isDefinedAt(x)
Run Code Online (Sandbox Code Playgroud)
返回trueiff x == 1(实际上,pf2根本不需要是PartialFunction)
但是,我预计:
pf1 andThen pf3 isDefinedAt(x)
Run Code Online (Sandbox Code Playgroud)
将返回false所有x(即,iff pf1已定义,检查pf3),但它不会,只验证pf1.
最后,pf1 andThen pf3 lift(x)总是会导致MatchError.我宁愿得到None ......我可以通过解除每个函数来获得这种行为,pf1.lift(x).flatMap(pf3.lift)但是有没有更简单的方法使用纯PartialFunction API?(并且不单独提升每个部分功能?)
鉴于:
def save(f: => Any)(run:Boolean) { if (run) { println("running f"); f } else println("not running f") }
Run Code Online (Sandbox Code Playgroud)
我可以用它来调用它:
save("test")(true) -> running f
save("test")(false) -> not running f
save(throw new RuntimeException("boom!"))(false) -> not running f
save(throw new RuntimeException("boom!"))(true) -> running f and then exception thrown
Run Code Online (Sandbox Code Playgroud)
这是部分应用的奇怪行为:
save(throw new RuntimeException("boom!"))(_) -> (Boolean) => Unit = <function1> //as expected
save(throw new RuntimeException("boom!")) _ -> exception thrown
Run Code Online (Sandbox Code Playgroud)
立即评估代码块而不作为函数传递.上述两个陈述有什么区别?
我使用orElse定义的方法得到了非常奇怪的行为(至少在我看来)PartialFunction
在我看来:
val a = PartialFunction[String, Unit] {
case "hello" => println("Bye")
}
val b: PartialFunction[Any, Unit] = a.orElse(PartialFunction.empty[Any, Unit])
a("hello") // "Bye"
a("bogus") // MatchError
b("bogus") // Nothing
b(true) // Nothing
Run Code Online (Sandbox Code Playgroud)
有道理,但这不是它的表现方式,我很难理解为什么类型签名似乎表明我在上面暴露了什么.
以下是我使用Scala 2.11.2观察的内容的记录:
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val a = PartialFunction[String, Unit] {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1> …Run Code Online (Sandbox Code Playgroud) functional-programming scala partialfunction read-eval-print-loop
有没有办法PartialFunction通过case声明创建一个除外?
我很好奇,因为我想表达以下内容(scala pseudo ahead!)...
val bi = BigInt(_)
if (bi.isValidInt) bi.intValue
Run Code Online (Sandbox Code Playgroud)
......作为一个部分功能,并做
val toInt : PartialFunction[String, Int] = {
case s if BigInt(s).isValidInt => BigInt(s).intValue
}
Run Code Online (Sandbox Code Playgroud)
因为我创造了BigInt两次似乎是多余的.