Reputation: 10701
I already found that it is possible to bind the type parameter in a pattern matching
Why does not that work in that case ?
trait T
case class S[A](a: A) extends T
def pr(t1: T, t2: T) = (t1, t2) match {
case (S(a): S[ta], S(b): S[tb]) => println(a); println(b)
}
^
error: '=>' expected but ':' found.
For information, this works:
def pr(t1: T, t2: T) = (t1, t2) match {
case (s1: S[a], s2: S[b]) => println(s1.a); println(s2.a)
}
And this as well:
def pr(t1: T, t2: T) = (t1, t2) match {
case (S(a), S(b)) => println(a); println(b)
}
I need to recover the type to define other functions whose type cannot be inferred because in the context of eta-expansion.
UPDATE
As mentionned in the comments, I need the types just for correct type checking, not anything else.
For example:
trait T
case class S[A](a: A, w: A => Int) extends T
def makeTwo(t1: T, t2: T) = (t1, t2) match {
case (S(a1, w1), S(a2, w2)) =>
val wNew = { (a, b) => w1(a) + w2(b) }
S((a, b), wNew)
}
error: missing parameter type
val wNew = { (a, b) => w1(a) + w2(b) }
^
Upvotes: 3
Views: 421
Reputation: 8851
Quoting from Scala syntax rules:
varid ::= lower idrest
idrest ::= {letter | digit} [‘_’ op]
op ::= opchar {opchar}
opchar ::= “all other characters in \u0020-007F and Unicode
categories Sm, So except parentheses ([]) and periods”
// 'a' and 'a_-' is valid, 'a(' is not.
Rule for Typed Pattern match says:
Pattern1 ::= varid ‘:’ TypePat
| ‘_’ ‘:’ TypePat
So
def pr(list: Any) = list match {
case a :String => // works
case a_- :String => // works a_- is valid instance of 'varid'
case a() :String => // does not work.
case a(b) :List[Int] // does not work either!
}
Hence:
case S(a): S[ta] is not valid syntax for pattern match.
However following is valid
case (s1 :S[a], s2: S[b])
according to Tuple Pattern matching rule:
SimplePattern ::= ‘(’ [Patterns] ‘)’
Patterns ::= Pattern {‘,’ Patterns}
Apart from the two possible options that you have listed, you may also use:
case tup: (S[_], S[_]) =>
Following seems to work:
trait T
case class S[A](a: A, w: A => Int) extends T
def makeTwo(t1: T, t2: T) = (t1, t2) match {
case (S(a1, w1), S(a2, w2)) =>
val wNew = { tup:(Any, Any) => w1(tup._1) + w2(tup._2) }
S((a1, a2), wNew)
}
def someString (s: String) = { s.length }
val twoS = makeTwo(S("Hello", someString), S("World!", someString))
println(twoS.w(twoS.a)) // gives 11
Upvotes: 1
Reputation: 26486
In at least some circumstances you can get what you want.
If you add a context bound (syntactic sugar for an implicit parameters) of the type ClassTag
to the type parameter you want enforced by the compiler, it will have what it needs to do that.
E.g., I have a generic bit of Akka plumbing I used to buffer messages between producers and consumers which I want to be type-safe.
The class is defined like this:
class TimedBatchQueue[T : ClassTag](batchLimit: Int,
MaxQueueTime: FiniteDuration,
receiver: ActorRef)
extends Actor
The receive function includes a case for the incomming messages it is to buffer:
def receive = {
...
case mesg: T => /* Enqueue the message */
case mesg => /* Bounce the unacceptable message back to the sender encapsulated in a reject message */
}
Upvotes: 0