Extratores Scala simplificados

Os extratores parecem nada mais do que içados e embrulhados PartialFunction:

type ?=>[A, B] = PartialFunction[A, B]

trait
Extractor[A, B] { def unapply(x: A): Option[B] }
def Extractor[A, B](fn: A ?=> B) = new Extractor[A, B] {
def unapply(x: A): Option[B] = fn.lift(x)
}

Vamos usar essa estrutura em alguns dados:

val people = List(
Person("Bradley", "Smith"),
Person("Paul", "Freeman", Some(Position("Programmer"))),
Person("Mary", "Martyr", Some(Position("Manager", Some(Company("IBM", Some(1881)))))))

Agora temos a opção de definir um extrator para obter a empresa em que a pessoa trabalha, se houver, ou, em vez disso, começar com uma função mais básica; vamos ao básico primeiro:

val getCompany: Person ?=> Company = {
case Person(_, _, Some(Position(_, Some(c)))) => c
}

Teríamos que usar uma sintaxe mais longa aqui se, em vez de getCompany, tivéssemos definido um extrator completo imediatamente:

val companies = people.collect(getCompany).distinct

Agora podemos converter getCompanyem um extrator chamado EmployedAtpara maior conveniência de correspondência de padrões:

val EmployedAt = Extractor(getCompany)

Os extratores compõem melhor em consultas de correspondência de padrões mais complexas:

def getEmployees(company: Company) =
people
.collect { case p @ EmployedAt(`company`) => p }