Pergunta

Eu tenho duas PartialFunctions f e g.Eles não têm efeitos colaterais e são rápidos de executar.Qual é a melhor maneira de compô-los em outra função parcial h de tal modo queh.isDefinedAt(x) se f.isDefinedAt(x) && g.isDefinedAt(f(x))?

Também está tudo bem se h é uma função que retorna um Option em vez de uma função parcial.

Estou desapontado com isso f andThen g não faz o que eu quero:

scala> val f = Map("a"->1, "b"->2)
f: scala.collection.immutable.Map[String,Int] = Map(a -> 1, b -> 2)

scala> val g = Map(1->'c', 3->'d')
g: scala.collection.immutable.Map[Int,Char] = Map(1 -> c, 3 -> d)

scala> (f andThen g).isDefinedAt("b")
res3: Boolean = true

scala> (f andThen g).lift("b")
java.util.NoSuchElementException: key not found: 2
    at scala.collection.MapLike$class.default(MapLike.scala:228)
Foi útil?

Solução

Aqui está um caminho mais curto do que a pergunta vinculada, retirada de este tópico:

  val f = Map("a" -> 1, "b" -> 2)                 

  val g = Map(1 -> 'c', 3 -> 'd')                 

  def andThenPartial[A, B, C](pf1: PartialFunction[A, B], pf2: PartialFunction[B, C]): PartialFunction[A, C] = {
    Function.unlift(pf1.lift(_) flatMap pf2.lift)
  }                                               

  val h = andThenPartial(f, g)            //> h  : PartialFunction[String,Char]

  h.isDefinedAt("a")                      //> res2: Boolean = true
  h.isDefinedAt("b")                      //> res3: Boolean = false
  h.lift("a")                             //> res4: Option[Char] = Some(c)
  h.lift("b")                             //> res5: Option[Char] = None

Isso também pode ser encerrado como uma classe implícita, é claro:

  implicit class ComposePartial[A, B](pf: PartialFunction[A, B]) {
    def andThenPartial[C](that: PartialFunction[B, C]): PartialFunction[A, C] =
      Function.unlift(pf.lift(_) flatMap that.lift)
  }

  val h2 = f andThenPartial g         //> h2  : PartialFunction[String,Char]

  h2.isDefinedAt("a")                 //> res6: Boolean = true
  h2.isDefinedAt("b")                 //> res7: Boolean = false
  h2.lift("a")                        //> res8: Option[Char] = Some(c)
  h2.lift("b")                        //> res9: Option[Char] = None

Outras dicas

val h = f.mapValues(g)

Mas isso só funciona para mapas.Não acho que exista uma maneira rápida de fazer isso para qualquer tipo de função parcial, você apenas terá que criar um novo objeto PartialFunction manualmente.

editar:Vejo que meu código acima não é o que você queria.Mas talvez isso seja melhor

val h = f.collect { case (k, v) if(g.contains(v)) => (k, g(v)) }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top