Since extractors cannot take custom parameters (as answered in Stack Overflow: Can extractors be customized...), I try to find an alternative way of solving the following problem.
I have a lot of translations which can be combined. In my code snippet, a dimension can be combined with a factor. For instance "width multiplied by 2"
. But it can also be "width"
(unmultiplied). And there will be further cases like that. I try to classify those string inputs using pattern matching. "width"
and "width multiplied by x"
should be classified as "width" (key "w"
), "height"
and "height multiplied by x"
should be classified as "height" (key "h"
), and so on.
That should be done by the last match
in the following example code snippet, which will contain many cases (6 in the example code snippet) each of which should take a key: String
parameter ("w"
, "h"
, "l"
, "r"
, "t"
, "b"
).
What I try to achieve is passing the key (that is "w"
, "h"
, "l"
, "r"
, "t"
, "b"
and so on) to the case Untranslation(v)
. But obviously I cannot do that (the unapply
function can take implicit parameters, but no additional explicit ones).
Now I try to find an alternative but still concise way of classifying my string inputs.
implicit val translations = Map(
"w" -> "width",
"h" -> "height",
"l" -> "left",
"r" -> "right",
"t" -> "top",
"b" -> "bottom",
// + some more translations
"m" -> "multiplied by"
)
sealed trait CommandType
object CommandType {
case object Unmodified extends CommandType
case object Multiplied extends CommandType
// ...
}
object Untranslation {
def unapply(s: String)(implicit t: Map[String, String]): Option[CommandType] = {
val key: String = "w" // should be variable by case
val a: List[String] = t(key).split(" ").toList
val b: List[String] = t("m").split(" ").toList
val ab: List[String] = a ++ b
s.split(" ").toList match {
case `a` => Some(CommandType.Unmodified)
case `ab` :+ value => Some(CommandType.Multiplied)
// + some more cases
case _ => None
}
}
}
"width multiplied by 2" match {
case Untranslation(v) => println(v) // here I would like to pass the key ("w"/"h"/"l"/...)
case _ => println("nothing found")
}
// outputs: Multiplied
Possibly your question duplicates this one.
package ex
import language._
object units extends Dynamic {
class Helper(kind: String) {
val kindof = kind match {
case "s" => Symbols.s
case "m" => Symbols.m
}
def value = raw"(\d+)${kindof.name}".r
object pair {
def unapply(s: String): Option[(Int, Symbol)] =
value.unapplySeq(s).map(vs => (vs.head.toInt, kindof))
}
}
def selectDynamic(kind: String) = new Helper(kind)
object Symbols { val s = 'sec ; val m = 'min }
}
object Test {
def main(args: Array[String]): Unit = println {
args(0) match {
case units.s.pair(x, s) => s"$x ${s.name}"
case units.s.value(x) => s"$x seconds"
case units.m.value(x) => s"$x minutes"
}
}
}
The customization is built into the selection in the case expression. That string is used to construct the desired extractor.
$ scalac ex.scala && scala ex.Test 24sec
24 sec
$ scalac ex.scala && scala ex.Test 60min
60 minutes