pattern - scala for
Coincidencia de patrones con conjunciones(PatternA AND PatternB) (2)
Scala tiene una función de idioma para admitir disyunciones en la coincidencia de patrones (''Alternativas de patrón''):
x match {
case _: String | _: Int =>
case _ =>
}
Sin embargo, a menudo necesito activar una acción si el escrutinio cumple con PatternA y PatternB (conjunción).
Creé un combinador de patrones ''&&'' que agrega esta capacidad. ¡Tres pequeñas líneas que me recuerdan por qué amo a Scala!
// Splitter to apply two pattern matches on the same scrutiny.
object && {
def unapply[A](a: A) = Some((a, a))
}
// Extractor object matching first character.
object StartsWith {
def unapply(s: String) = s.headOption
}
// Extractor object matching last character.
object EndsWith {
def unapply(s: String) = s.reverse.headOption
}
// Extractor object matching length.
object Length {
def unapply(s: String) = Some(s.length)
}
"foo" match {
case StartsWith(''f'') && EndsWith(''f'') => "f.*f"
case StartsWith(''f'') && EndsWith(e) && Length(3) if "aeiou".contains(e) => "f..[aeiou]"
case _ => "_"
}
Puntos para discusión
- ¿Hay alguna forma de hacerlo?
- ¿Hay problemas con este enfoque?
- ¿Puede este enfoque crear cualquier otro combinador útil? (por ejemplo,
Not
) - ¿Se debería agregar tal combinador a la biblioteca estándar?
ACTUALIZACIÓN Me acaban de preguntar cómo interpreta el compilador el case A && B && C
Estos son patrones de operador infijo (Sección 8.1.9 de la Referencia de Scala). También podría expresar esto con patrones de extracto estándar (8.1.7) como &&(&&(A, B), C).'' Notice how the expressions are associated left to right, as per normal infix operator method calls like
&&(&&(A, B), C).'' Notice how the expressions are associated left to right, as per normal infix operator method calls like
Boolean # && in
val b = true && false && true`.
Me gusta mucho este truco. No conozco ninguna forma de hacerlo, y no preveo ningún problema, aunque eso no significa mucho. No puedo pensar en ninguna forma de crear un Not
En cuanto a agregarlo a la biblioteca estándar ... tal vez. Pero creo que es un poco difícil. Por otro lado, ¿qué hay de hablarle a la gente de Scalaz para que lo incluya? Se parece mucho más a su propia bailía.
Un posible problema con esto es la traducción inflada que genera el generador de patrones. Aquí está la translation del programa de ejemplo, generado con scalac -print
. Incluso -optimise
no simplifica if (true) "_" else throw new MatchError()
expresiones if (true) "_" else throw new MatchError()
.
Las coincidencias de patrones grandes ya generan más bytecode de lo que es legal para un solo método, y el uso de este combinador puede amplificar ese problema.
Si &&
fue construido en el idioma, quizás la traducción podría ser más inteligente. Alternativamente, pequeñas mejoras a la -optimise
podrían ayudar.