My instinct says that the following code could be made shorter, but I 开发者_StackOverflow社区cannot figure how. Can you help me?
def asGraphingFunction[A : Numeric, B : Numeric](f: PartialFunction[A, B]): Double => Double = {
val (numericA, numericB) = (implicitly[Numeric[A]], implicitly[Numeric[B]])
(x: Double) => {
val xa: A = numericA.fromInt(x.toInt)
if(f.isDefinedAt(xa))
numericB.toDouble(f(xa))
else
0.0
}
}
Two tips here:
As you need the
Numeric
instances named, it's easier to just de-sugar the context bounds into implicit argumentsUse
PartialFunction#lift
to convert thePartialFunction[A,B]
into anA => Option[B]
Then remove the boilerplate and... voila!
def asGraphingFunction[A, B](f: PartialFunction[A, B])
(implicit numA: Numeric[A], numB: Numeric[B]) =
(x: Double) => f.lift(numA fromInt x.toInt) map (numB.toDouble) getOrElse 0.0
If you use a forward pipe operator (either from scalaz, or as defined here), then it can be made even more legible:
def asGraphingFunction[A, B](f: PartialFunction[A, B])
(implicit numA: Numeric[A], numB: Numeric[B]) =
(x: Double) => (numA fromInt x.toInt) |> f.lift map (numB.toDouble) getOrElse 0.0
Update
As you're only converting ints/doubles, you don't actually need Numeric
at all, you can do everything via java.util.Number
, dropping the type params in the process:
def asGraphingFunction(f: PartialFunction[Number, _ <: Number]) =
(x: Number) => f.lift(x.intValue) map (_.doubleValue) getOrElse 0.0
What about this?:
import scala.{ PartialFunction => PF }
def asGraphingFunction[A : Numeric, B : Numeric](f: PF[A, B]): Double => Double = {
val pf1: PF[Double,A ] = { case d => numericA.fromInt(d.toInt) }
val pf2: PF[B ,Double] = { case b => numericB.toDouble(b) }
val pf3: PF[Double,Double] = { case _ => 0 }
pf1 andThen f andThen pf2 orElse pf3
}
Not shorter but perhaps clearer?! Any comments?
精彩评论