Pattern Matching for Sequences
Sequences (anything built from the IS
Scala library classes) can be pattern-matched using the class name (constructor) (e.g., ISZ
) as illustrated in the example below.
// Patterns in declarations - sequences
val seq1 = ISZ("a", "b", "c")
var ISZ(str1,_,str3) = seq1
assert(str1 == "a" && str3 == "c")
// match case - basic sequence matching
@pure def matchSeq(seq: ISZ[Z]): Option[Z] = {
seq match { // pattern match on sequence seq
case ISZ(n1, n2, n3) => return Some(n1 + n2 + n3)
case ISZ(n1, n2) => return Some(n1 + n2)
case ISZ(n1) => return Some(n1)
case ISZ() => return Some(0)
case _ => return None()
}
}
assert(matchSeq(ISZ(4,5,6)) == Some(15))
assert(matchSeq(ISZ()) == Some(0))
assert(matchSeq(ISZ(4,5,6,7)) == None[Z]()) // need to give element type for None to make Slang type-checker happy
The following example illustrates nested matching for sequence containing tuples.
// match case - nested matching on sequences
@pure def matchSeqNested(seq: ISZ[(String,String)]): B = {
seq match { // pattern match on sequence of pairs
case ISZ(("a",_), ("a",_)) => return T // matching tuples in sequences (nesting patterns)
case _ => return F
}
}
assert(matchSeqNested(ISZ(("a","HHH"),("a","JJJ"))))
assert(!matchSeqNested(ISZ(("b","KKK"))))
Patterns for Slang sequences (IS
and MS
) can use the Scala sequence wildcard _*
which matches 0 or more elements of a sequence.
// match case - sequence wildcards _*
@pure def matchSeqWildcard(seq: ISZ[Z]): B = {
seq match {
case ISZ(hd, _*) => return T // sequence wildcard _* matches 0 or more elements of a sequence
// case ISZ(hd, tl @ _*) => return T // ERROR: naming _* via pattern binding NOT SUPPORTED IN SLANG
case _ => return F
}
}
assert(matchSeqWildcard(ISZ(5,4,3,2,1))) // _* matches 4,3,2,1
assert(matchSeqWildcard(ISZ(5,4))) // _* matches 4
assert(matchSeqWildcard(ISZ(5))) // _* matches 0 elements
assert(!matchSeqWildcard(ISZ()))
One might hope to take advantage of the pattern binding concept to name the “tail” of the sequence in the example above. The grammar for Scala pattern sequences indicates that this is accepted in Scala, but it is not supported in Slang.
Scala Connection
Slang pattern matching on sequences is similar to Scala’s (see, for example, this tutorial).
Sequence pattern matching in both Scala and Slang is based on the fact that Scala allows pattern matching using constructors of non-case classes as long as the class defines an unapply
or unapplySeq
methods (these are called “extractor patterns” see Scala documentation for pattern matching). This is the strategy used to realize pattern matching for the IS
family of Slang types, since IS
is a Slang library class that is not a case class (similarly for MS
).
However, Slang’s pattern matching is limited to matching on the primary constructor (e.g., ISZ(...)
) and, in contrast to Scala, does not support matching on infix operations such as +:
, ::
, or :+
. This means that one cannot use Slang pattern matching to break a sequence apart into named head and tail (e.g., hd +: tl
) (as one might want to do when using sequences in a manner similar to cons-based lists in a functional language). Retreiving a named Slang sequence head
can be accomplished using the sequence wildcard (e.g., ISZ(hd, _*)
). To enable pattern matching with the sequence wildcard, Scala classes must implement the unapplySeq
method, and Slang IS
and MS
supports this.
Note
JH: To Robby, check the description above ….