2011-10-18 15 views
8

Ho due funzioni.Composable using scalaz Arrow?

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

    def applyDiscount(billable: Billable) : Billable 

Come posso comporre questi in modo da avere una singola funzione di (DateTime, fattura, l'utente, di riferimento) => (Azione, Iterable [Billable])

Qui è il modo mans poveri quello che voglio

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

si desidera una funzione che prima esegue 'processo' e poi' applyDiscount'? –

+0

Sì, esattamente. Queste due funzioni sono componibili usando la freccia di Scalaz e, in tal caso, qual è la sintassi? – OleTraveler

risposta

9

quello che avete (semplificando) è:

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

mi vengono in mente alcuni modi di doin questo Credo che la mia preferenza è:

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

O anche:

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

Tuttavia, v'è forse un modo pointfree - anche se non necessariamente così, naturalmente

  • lift è un metodo su Function1W che solleva la funzione nel regno del functor M
  • second è un metodo su MAB cui si applica la funzione di abbassamento di destra-lato di un Bifunctor
  • :-> è un metodo disponibile per Bifunctors denota l'applicazione di una funzione sulle sd.

EDIT-missingfaktor sembra essere corretto nel dire f andThen g.lift[M].second opere:

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

Forse 'f e poi g.lift [M] .secondo'. – missingfaktor

+0

Ben distillato, incredibile quanto sono le cose più chiare quando è possibile * solo * vedere i tipi! – retronym

+0

Risposta stupenda. Capisco perfettamente ogni passo qui dopo aver giocato nel repl. Applicando questo al mio problema, ho trovato queste due soluzioni: val bfc = billableBuilder.fromContract (_: Utente, _: Contratto, _: DateTime, _: Opzione [Ordine]): -> (applyDiscount (_)). [Iterable] e val bfc = (applyDiscount (_)). Lift [Iterable] .secondo apply billableBuilder.fromContract (_: User, _: Contract, _: DateTime, _: Option [Order]) – OleTraveler