Составляется с помощью стрелки scalaz?

#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 , который переводит функцию в область функтора M
  • second это метод, к 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 У вас есть какое-либо представление о том, почему :-> неявно работает со вторым аргументом (и нет симметричного способа применить это к первому аргументу). Или это стоило бы другого вопроса.