[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 - это функция.
This account has disabled anonymous posting.
If you don't have an account you can create one now.
HTML doesn't work in the subject.
More info about formatting

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 03:13 am
Powered by Dreamwidth Studios