Generic unapply methods

725 views
Skip to first unread message

Jon Pretty

unread,
Oct 7, 2012, 2:29:10 PM10/7/12
to scala-i...@googlegroups.com
Hello again.

I found myself wanting to write something like this today:

   val As[Int](foo) = "42"

which I would have loved to implement with the following:

   trait Extractor[T] { def extract(s: String): Option[T] }
   implicit val intExtractor = new Extractor[Int] { def extract(s: String) = ... }
   object As { def unapply[T](s: String)(implicit e: Extractor[T]): Option[T] = e.extract(s) }

However, the parameter T doesn't seem to get passed to the unapply method when it's expanded, and the compiler gives the slightly misleading error message "not found: type As".

Defining lots of extractors called "AsInt", "AsDouble", "AsFoo" doesn't appeal to me nearly as much as defining just one called "As". How hard would it be to support this?

Cheers,
Jon


Paul Phillips

unread,
Oct 7, 2012, 2:52:06 PM10/7/12
to scala-i...@googlegroups.com


On Sun, Oct 7, 2012 at 11:29 AM, Jon Pretty <googl...@accounts.propensive.com> wrote:
Defining lots of extractors called "AsInt", "AsDouble", "AsFoo" doesn't appeal to me nearly as much as defining just one called "As". How hard would it be to support this?

It is long desired; all the way to 884.


It may not be enormously difficult now that we have virtpatmat.  I fixed the parser at some point so that at least the syntax is possible (it used to freak out when encountering the square brackets) but it still doesn't deal with the type parameter.

Jon Pretty

unread,
Oct 7, 2012, 5:30:03 PM10/7/12
to scala-i...@googlegroups.com
Le dimanche 7 octobre 2012 19:52:08 UTC+1, Paul Phillips a écrit :
It may not be enormously difficult now that we have virtpatmat.  I fixed the parser at some point so that at least the syntax is possible (it used to freak out when encountering the square brackets) but it still doesn't deal with the type parameter.

Ah - I was a little surprised the type parameter got past the parser. But good to hear it's not been forgotten. I've upvoted issue SI-884 just in case that makes a difference.

Cheers,
Jon

Paolo G. Giarrusso

unread,
Oct 10, 2012, 9:56:56 PM10/10/12
to scala-i...@googlegroups.com
Il giorno domenica 7 ottobre 2012 20:52:08 UTC+2, Paul Phillips ha scritto:


On Sun, Oct 7, 2012 at 11:29 AM, Jon Pretty <googl...@accounts.propensive.com> wrote:
Defining lots of extractors called "AsInt", "AsDouble", "AsFoo" doesn't appeal to me nearly as much as defining just one called "As". How hard would it be to support this?

It is long desired; all the way to 884.

Upvoted as well. 

It may not be enormously difficult now that we have virtpatmat.
Do you mean "we can use virtualization" or just "the code is well-written, so I can change it without hell breaking loose"?
While at it or independently, would it be possible to support this code better?

case class Eq[T](a: T, b: T)
//... foo match {
case x: Eq[u] =>
  x match {
    case Eq(a, b) => ...
  }
Possible syntaxes:
case Eq[u](a, b) => //hopefully allowed by fixing SI-884?

But more in general, it'd be nice to support nesting patterns inside type patterns. At least, it'd allow
case Eq(a, b): Eq[u] =>
even though this might be less useful when case Eq[u](a, b) is supported.

Consider this example:
case class Eq[T](a: T, b: T)
class EqString(a: String, b: String) extends Eq[String](a, b)

I can't write this:
def f[T]: Eq[T] => Eq[T] = {
  case Eq(a, b): EqString => Eq("a", "b" + b.charAt(0))
}

Nor could I write:
def f[T]: Eq[T] => Eq[T] = {
  case Eq[String](a, b) => Eq("a", "b" + b.charAt(0))
}
because String is unchecked there, so the call to charAt would fail when passing 

Instead, I need to write this:
def f[T]: Eq[T] => Eq[T] = {
  case bound: EqString => Eq("a", "b" + bound.b.charAt(0))
}
Of course I can call extractors after the match, and match on them, and then match on their subterms, and so on, but the point of nested pattern matching is to avoid that. Look just at the pattern matches below:

val mergeMapsSimplified = new Transformer {
    def apply[T](e: Exp[T]) = e match {
      case Sym(m: MapNode[t, repr, u, that]) => //T = that
        m.base match {
          case Sym(m2: MapNode[t2, repr2, u2, that2]) =>
            (((m2.base map m2.f)(m2.c): Exp[repr with TraversableLike[t, repr]]) map m.f)(m.c) //works
          case _ => e
        }
      case _ => e
    }
  }

The above pattern matches should be mergeable in a single nested one.

You might wonder "But why the heck all those type annotations?" Because there I was trying to make map fusion _type-safe_. Yet, all that is just needed to rewrite a representation of `e map f map g` to another representation of the same expression. I stopped there because I'd need to make the compiler figure out that t >: u2, which seems hard in my scenario.

Paul Phillips

unread,
Oct 11, 2012, 10:20:23 AM10/11/12
to scala-i...@googlegroups.com
On Wed, Oct 10, 2012 at 6:56 PM, Paolo G. Giarrusso <p.gia...@gmail.com> wrote:
Do you mean "we can use virtualization" or just "the code is well-written, so I can change it without hell breaking loose"?

Let's not get ahead of ourselves with "well-written", but I do mean the second one, only with less generous phrasing.  I'm not super liberal with code praise.

case Eq[u](a, b) => //hopefully allowed by fixing SI-884?

Relatedly, take a look at:


Notice my comment at the top.

Adriaan Moors

unread,
Oct 11, 2012, 1:35:18 PM10/11/12
to scala-i...@googlegroups.com
As Paul pointed out, this is more of a type inference than a pattern matching problem.
GADT-style type inference is something that should definitely be cleaned up.
Not super super high on the priority list, unfortunately.

adriaan

ps: I'll take the praise I can get.

Paolo G. Giarrusso

unread,
Oct 12, 2012, 2:42:15 PM10/12/12
to scala-i...@googlegroups.com, adriaa...@typesafe.com


Il giorno giovedì 11 ottobre 2012 19:35:50 UTC+2, Adriaan Moors ha scritto:
As Paul pointed out, this is more of a type inference than a pattern matching problem.
GADT-style type inference is something that should definitely be cleaned up.
 
Lacking the automatic support, I'd like at least convenient syntax for binding variables and using them in type annotations. Type inference was surprisingly eager to not do that.

Not super super high on the priority list, unfortunately.
:-(.
Reply all
Reply to author
Forward
0 new messages