[personal profile] sassa_nf
Беда с applicative functors на scala kittens с тем, что коряво выходит nesting разных функторов. Допустим, как обработать Stream[Option[Int]]?

Вот здесь попытался изложить по-другому.

1. "апликативные макбрайдовские скобочки" ограничивают контекст применения одного апликатива.
2. помочь с nesting

object b extends Application {
  class IsFunction[A,B,C]
  implicit def isafunction[A,B]: IsFunction[A=>B,A,B] = null


  final case class Pure[+A](val a: A)

  final class Applicable[T[+_],+A,+C] (val apper: Applicative[T], val as: T[A]) {
    def apply[B, _ >: A <: B=>Any](bs: T[B]):Applicable[T,C,C] = new Applicable(apper, apper.ap(as.asInstanceOf[T[B=>C]], bs))
    def *>() : T[A] = as
  }

  implicit def applicablefunction[T[+_],A,B,C](as: Applicable[T,A,A])(implicit fs: IsFunction[A,B,C]) = as.asInstanceOf[Applicable[T,A,C]]

  trait Applicative[T[+_]] { self =>
    def pure[A](a: A): T[A]
    def ap[A,B](fs: T[A=>B], as: T[A]): T[B]

    // defining here, so that importing a particular Applicative enables the use of the "opening bracket"
    // also, you can use the Applicative implementation name directly, which nicely explains the context eg. ZapList.<* ..... *>
    def <*[A](as: T[A]): Applicable[T,A,A] = new Applicable[T,A,A](self, as)
    def <*[A](a: Pure[A]): Applicable[T,A,A] = new Applicable[T,A,A](self, pure(a.a))
  }


  object ZapList extends Applicative[Seq] {
    override def pure[A](a: A): Seq[A] = Stream.const(a)
    override def ap[A,B](fs: Seq[A=>B], as: Seq[A]): Seq[B] = (fs zip as) map (p => p._1(p._2))
  }

  object ApOption extends Applicative[Option] {
    override def pure[A](a: A): Option[A] = Some(a)
    override def ap[A,B](fs: Option[A=>B], as: Option[A]): Option[B] = (fs, as) match {
      case (Some(f),Some(x)) => Some(f(x))
      case _ => None
    }
  }

  import ZapList._

  def pp(i: Int) = (j:Int) => i + j*j

  val fs = Pure(pp _)
  val fs_ = Seq(pp(1), pp(2))
  val as = Seq(1, 2)
  val bs = Seq(10,20,30)
  println( <* (fs) *> )
  println( <* (Pure(pp _)) apply (as) *> )
  println( <* (fs_) *> )
  println( <* (fs_) (bs) *> )
  println( (<* (fs) (as) (bs) *>).toList )
  println( <* (Pure(pp _)) (as) (bs) *>() toList )
  // println( <* (as) (bs) *> ) // compilation error - correct!


  val xs = Seq(Some(1), None, Some(2));
  val ys = Seq(Some(10), Some(20), Some(30));
  println( <* (Pure( (x:Option[Int]) => (y:Option[Int]) => ApOption.<* (fs) (x) (y) *> )) (xs) *> );
  println( (<* (Pure( (x:Option[Int]) => (y:Option[Int]) => ApOption.<* (fs) (x) (y) *> )) (xs) (ys) *>).toList );
}


Многословно как-то.

1. не хочет хавать аргументы без скобочек: <* fs x y *> - никак не хочет
2. не умеет вывести тип аргументов: <* (fs) (_) (_) *> - вообще не умеет
3. нельзя просто взять и вызвать метод на результате апликатива: <* (fs) (x) (y) *> toList - совсем нельзя

Ну, хоть научился выводить тип функции без implicit аргумента. Потому что вот так работать не будет, если аргументов у as более одного:
    def apply[B, C](bs: T[B])(implicit fs: IsFunction[A,B,C]):Applicable[T,C,C] = ...


Зато связка:
  final class Applicable[T[+_],+A,+C] (val apper: Applicative[T], val as: T[A]) {
    def apply[B, _ >: A <: B=>Any](bs: T[B]):Applicable[T,C,C] = new Applicable(apper, apper.ap(as.asInstanceOf[T[B=>C]], bs))
    def *>() : T[A] = as
  }

  implicit def applicablefunction[T[+_],A,B,C](as: Applicable[T,A,A])(implicit fs: IsFunction[A,B,C]) = as.asInstanceOf[Applicable[T,A,C]]
позволяет делать implicit class cast Applicable[T,A,A] в Applicable[T,B=>C,C], т.е. выяснить тип результата, а apply() сделать применимым только в случае, когда тип A - это функция.

Profile

sassa_nf

February 2026

S M T W T F S
1234567
891011121314
15161718192021
222324252627 28

Style Credit

Expand Cut Tags

No cut tags
Page generated May. 22nd, 2026 02:24 am
Powered by Dreamwidth Studios