#scala #scalaz
#scala #scalaz
Вопрос:
У меня есть две функции.
def process(date: DateTime, invoice: Invoice, user: User, reference: Reference) : (Action, Iterable[Billable])
def applyDiscount(billable: Billable) : Billable
Как я могу составить их так, чтобы у меня была одна функция (дата-время, счет-фактура, пользователь, ссылка) => (Действие, итерируемое [Оплачиваемое])
Вот бедный способ того, что я хочу
def buildFromInvoice(user: User, order: Invoice, placementDate: DateTime, reference: Reference) = {
val ab = billableBuilder.fromInvoice(user, order, placementDate, reference)
(ab._1, ab._2.map(applyDiscount(_))
}
Комментарии:
1. вам нужна функция, которая сначала выполняется
process
, а затемapplyDiscount
?2. Да, именно. Являются ли эти две функции составными с использованием Scalaz arrow, и если да, то каков синтаксис?
Ответ №1:
То, что у вас есть (упрощение), это:
val f: A => (B, M[C]) //M is a Functor
val g: C => C
Я могу придумать несколько способов сделать это. Я думаю, что мое предпочтение:
(a: A) => g.lift[M].second apply f(a)
Или также:
(a: A) => f(a) :-> g.lift[M]
Однако, возможно, есть способ без точек — хотя, конечно, это не обязательно
lift
это методFunction1W
, который переводит функцию в область функтора Msecond
это метод, кMAB
которому применяется функция вниз по правой частиBifunctor
:->
доступен ли метод дляBifunctors
обозначения применения функции в rhs.
РЕДАКТИРОВАТЬ — missingfaktor, похоже, правильно говорит f andThen g.lift[M].second
, что работает:
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>
Без точек:
scala> lazy val h = f andThen g.lift[List].second
h: A => (B, List[C]) = <lazy>
Комментарии:
1. Возможно
f andThen g.lift[M].second
.2. Красиво обработано, удивительно, насколько все становится понятнее, когда вы можете видеть только типы!
3. Потрясающий ответ. Я полностью понимаю каждый шаг здесь после игры в repl. Применяя это к моей проблеме, я пришел к этим двум решениям: val bfc = billableBuilder.fromContract( : User, _: Contract, _: DateTime, _: Option[Order]) :-> (applyDiscount( )).lift[Iterable] и val bfc = (applyDiscount( )).поднимите [Итерируемый].во-вторых, примените billableBuilder.fromContract( : User, _: Contract, _: DateTime, _: Option[Заказ])
4. Также обратите внимание, что я не смог заставить ‘andThen’ работать в моей ситуации. И тогда, похоже, определено только для Function1, где as apply определяется для всех признаков FunctionXX.
5. @oxbow_lakes У вас есть какое-либо представление о том, почему
:->
неявно работает со вторым аргументом (и нет симметричного способа применить это к первому аргументу). Или это стоило бы другого вопроса.