2011-10-18 26 views
8

Tengo dos funciones.Composable using scalaz Arrow?

def process(date: DateTime, invoice: Invoice, user: User, reference: Reference) : (Action, Iterable[Billable]) 

    def applyDiscount(billable: Billable) : Billable 

¿Cómo puedo componer éstos de modo que tenga una sola función del (DateTime, Factura, Usuario, de referencia) => (Acción, Iterable [facturable])

Aquí es la mala manera sirve de lo que quiero

def buildFromInvoice(user: User, order: Invoice, placementDate: DateTime, reference: Reference) = { 
    val ab = billableBuilder.fromInvoice(user, order, placementDate, reference) 
    (ab._1, ab._2.map(applyDiscount(_)) 
    } 
+0

que quieren una función que primero ejecuta '' process' y luego applyDiscount'? –

+0

Sí, exactamente. ¿Estas dos funciones se pueden componer usando la flecha de Scalaz y, de ser así, cuál es la sintaxis? – OleTraveler

Respuesta

9

lo que has (simplificando) es:

val f: A => (B, M[C]) //M is a Functor 
val g: C => C 

puedo pensar en algunas formas de haces g esto Creo que mi preferencia es:

(a: A) => g.lift[M].second apply f(a) 

O también:

(a: A) => f(a) :-> g.lift[M] 

Sin embargo, existe posiblemente una forma pointfree - aunque no necesariamente es así, por supuesto

  • lift es una método en Function1W que eleva la función al ámbito del functor M
  • second es un método en MAB que se aplica la función de abajo de la mano del lado derecho de un Bifunctor
  • :-> es un método disponible para Bifunctors denota la aplicación de una función en los RHS.

EDITAR-missingfaktor parece ser cierto al decir f andThen g.lift[M].second obras:

scala> import scalaz._; import Scalaz._ 
import scalaz._ 
import Scalaz._ 

scala> case class A(); case class B(); case class C() 
defined class A 
defined class B 
defined class C 

scala> lazy val f: A => (B, List[C]) = sys.error("") 
f: A => (B, List[C]) = <lazy> 

scala> lazy val g: C => C = sys.error("") 
g: C => C = <lazy> 

Pointfree:

scala> lazy val h = f andThen g.lift[List].second 
h: A => (B, List[C]) = <lazy> 
+1

Quizás 'fy luego g.lift [M] .second'. – missingfaktor

+0

Muy bien destilado, ¡qué cosas más claras son cuando solo * puedes ver los tipos! – retronym

+0

Awesome answer. Entiendo totalmente cada paso aquí después de jugar en el repl. Aplicando esto a mi problema, presenté estas dos soluciones: val bfc = billableBuilder.fromContract (_: User, _: Contract, _: DateTime, _: Option [Order]): -> (applyDiscount (_)). Lift [Iterable] y val bfc = (applyDiscount (_)). Lift [Iterable] .security apply billableBuilder.fromContract (_: User, _: Contract, _: DateTime, _: Option [Order]) – OleTraveler