Proposal: create an Extractor for PartialFunction

163 views
Skip to first unread message

杨博

unread,
Jul 9, 2015, 12:56:11 AM7/9/15
to scala-l...@googlegroups.com

Sometimes, when I create a method, I need an extractor parameter for pattern matching, while there is not a generic extractor trait in the Scala Standard Library. So we have to use a PartialFunction as the parameter instead.


When I use the PartialFunction, I had to create pattern matching expression like this.


input match {

  case x if partialFunction.isDefined(x) =>

    val data = partialFunction.apply(x)

    doSomethingWith(data)

}


This approach is not perfect because:

  1. partialFunction.isDefined and partialFunction.apply checked x twice, which is slow if isDefined has complex logical, checking whether a file exists for example.
  2. The if condition around temporary variable x is too trivial.

I think the better approach is converting the PartialFunction to an extractor and matching with that extractor


implicit final class PartialFunctionAsExtractor[A, B](pf: PartialFunction[A, B]) {

  object Extractor {

    def unapply(a: A) = PartialFunction.condOpt(a)(pf)

  }

}


input match {

  case partialFunction.Extractor(data) =>
    doSomethingWith(data)
}

Since this is a common approach, I hope adding the PartialFunctionAsExtractor to scala.Predef .

I would like to create a pull request if people like this idea.

Alec Zorab

unread,
Jul 9, 2015, 4:12:41 AM7/9/15
to scala-l...@googlegroups.com
Don't either PartialFunction.lift or PartialFunction.applyOrElse do pretty much exactly what you want?

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

杨博

unread,
Jul 9, 2015, 7:11:13 AM7/9/15
to scala-l...@googlegroups.com
No, neither lift nor applyOrElse is an extractor.

In fact, the extractor I proposed calls condOpt, which calls applyOrElse internally.

Alec Zorab <alec...@gmail.com>于2015年7月9日周四 下午4:12写道:
You received this message because you are subscribed to a topic in the Google Groups "scala-language" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/scala-language/g0-hbN5qerQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to scala-languag...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
--
杨博 (Yang Bo)

Vlad Patryshev

unread,
Jul 9, 2015, 10:43:15 AM7/9/15
to scala-l...@googlegroups.com

Instead of going back into the world of booleans and conditions, I'd suggest to think about why there's no such thing already available. Maybe this is the right direction. applyOrElse is total; if it does not work for you, lift should. It is pretty scientific, and gets you to a Kleisli category. All these ifs and match/cases are a little bit like crutches.

Thanks,
-Vlad

--

杨博

unread,
Jul 9, 2015, 10:57:40 AM7/9/15
to scala-l...@googlegroups.com
lift and applyOrElse are hard to work with other cases in a match expression, especially when dealing with Exceptions. For example: https://github.com/Atry/memcontinuationed/blob/master/src/main/scala/com/dongxiguo/memcontinuationed/Memcontinuationed.scala#L599

在 2015年7月9日星期四 UTC+8下午10:43:15,Vlad Patryshev写道:

杨博

unread,
Jul 9, 2015, 11:06:22 AM7/9/15
to scala-l...@googlegroups.com
https://github.com/search?q=if+catcher.isDefinedAt&ref=reposearch&type=Code&utf8=%E2%9C%93

There are too many people who have to use case e if catcher.isDefinedAt(e) =>

Does that matter?

在 2015年7月9日星期四 UTC+8下午10:57:40,杨博写道:

杨博

unread,
Jul 9, 2015, 11:26:52 AM7/9/15
to scala-l...@googlegroups.com
BTW: At the moment, all the other answers on the discussion except mine are wrong because they did not implement getOrElse.

在 2015年7月9日星期四 UTC+8下午10:43:15,Vlad Patryshev写道:

Rex Kerr

unread,
Jul 10, 2015, 2:55:44 PM7/10/15
to scala-l...@googlegroups.com
I think it's a good idea.  I'd make it more general, actually: call it `Computes`, and make a (lower priority) version on Function1 also.

You often want to do things like

foo match {
  case bar.Computes(x) if baz(x) => x
  case _ => quux
}

where the only difference with the PartialFunction is that you don't always need the if clause since it's embedded.

It wouldn't be fast for primitives, for instance, since you always have the overhead of at least a virtual Some wrapper (and maybe a real one, depending on the JVM).  But it'd sure be handy.

  --Rex



杨博

unread,
Jul 10, 2015, 3:45:04 PM7/10/15
to scala-l...@googlegroups.com
Thank you. But I think Computes for Function1 is not that useful unless we allow eta-conversion as a pattern. e.g.

case foo.someMethod.Computes(x) =>



Rex Kerr <ich...@gmail.com>于2015年7月11日周六 上午3:32写道:
You received this message because you are subscribed to a topic in the Google Groups "scala-language" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/scala-language/g0-hbN5qerQ/unsubscribe.
To unsubscribe from this group and all its topics, send an email to scala-languag...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
--
杨博 (Yang Bo)

Rex Kerr

unread,
Jul 10, 2015, 4:30:44 PM7/10/15
to scala-l...@googlegroups.com
It would be more useful with eta-conversion, I agree.

  --Rex

Reply all
Reply to author
Forward
0 new messages