juan_gandhi: (Default)
[personal profile] juan_gandhi
trait Applicative[T[_]] extends Functor[T] {
  def pure[A](a:A):T[A]
  def ap[A,B](tf:T[A=>B]): T[A] => T[B]
  def map[A,B](f:A=>B) = ap(pure(f))
}

abstract class Applicable[A, B, T[_]](fs: T[A=>B]) {
  def <*>(at: T[A]):T[B]
}
abstract class Lifted[A, B, T[_]](f: A=>B) {
  def <@>(ta:T[A]): T[B] // in Haskell it is <$>; can't use $ in Scala, and can't have lt;&s> either.
}

trait RichApplicative[T[_]] extends Applicative[T] {
  implicit def applicable[A,B](tf:T[A=>B]): Applicable[A, B, T]
  implicit def lift[A,B](f: A=>B) = new Lifted[A, B, T](f) { def <@>(at: T[A]) = ap(pure(f))(at)}
}

trait Traversable[T[_]] extends RichApplicative[T] {
  def traverse[A, B](f: A => T[B])(as: List[A]): T[List[B]] = as match {
    case Nil => pure(Nil)
    case head::tail => lift(cons[B] _) <@> f(head) <*> traverse(f)(tail)
  }

  def dist[A] = traverse(identity[T[A]] _) _
}


Work in progress. I'm on page 5. (dumb, eh)

Comments? Ideas?

Date: 2012-04-11 09:40 am (UTC)
From: [identity profile] sassa-nf.livejournal.com
А почему два разных класса Applicable и Lifted? (У МакБрайда понятно почему отдельно * и $)

Date: 2012-04-11 02:54 pm (UTC)
From: [identity profile] ivan-gandhi.livejournal.com
Да это трейты. Вот и разделил.

Date: 2012-04-11 04:41 pm (UTC)
From: [identity profile] sassa-nf.livejournal.com
так а в чём трейтовость? Вроде * от $ отличаются только первым аргументом, а в скальной реализации - только способом конструировать Applicable / Lifted. После конструирования разница есть? Вроде нет.

Date: 2012-04-11 04:44 pm (UTC)
From: [identity profile] ivan-gandhi.livejournal.com
Да я не вижу пока особого смысла в наличии <$>; посмотрю ещё.

Date: 2012-04-11 04:53 pm (UTC)
From: [identity profile] sassa-nf.livejournal.com
типа def lift(f) = applicative(pure f), а потому applicative(f)=new Applicative(f){ def <*>(at)=ap(f)(at) }

Date: 2012-04-11 06:01 pm (UTC)
From: [identity profile] ivan-gandhi.livejournal.com
Да, действительно; попробую. Я думал этот <@> будет где-то систематически нужен...

Date: 2012-04-11 10:27 am (UTC)
From: [identity profile] sassa-nf.livejournal.com
и второе: что-то с ленивостью не понятно как быть. Например, traverse бесконечный Stream.

Date: 2012-04-11 02:54 pm (UTC)
From: [identity profile] ivan-gandhi.livejournal.com
Хороший вопрос, посмотрю.

Date: 2012-04-12 12:25 pm (UTC)
From: [identity profile] sassa-nf.livejournal.com
а ещё
  def traverse[A, B](f: A => T[B])(as: List[A]): T[List[B]] = as match {
    case Nil => pure(Nil)
    case head::tail => lift(cons[B] _) <@> f(head) <*> traverse(f)(tail)
  }
кажется, означает рекурсию глубины as.size.

а давайте сделаем вот так:
  def foldR[A, B, L > Iterable](z: T[B])(f: (A, T[B]) => T[B])(as: L[A]): T[L[B]] = as.foldRight(z)(f _)
  def traverse[A, B](f: A => T[B])(as: List[A]): T[List[B]] = foldR(pure Nil)( (p,n) => lift(cons[B] _) <@> p <*> n )


а из-за ленивости Stream, видимо, нужно переписать <*> и т.п. с ленивым аргументом def <*>(at: =>T[A]):T[B]

  def traverse[A, B](f: A => T[B])(as: Stream[A]): T[Stream[B]] = if as.isEmpty pure(Stream.empty) else lift(Stream.cons[B] (f as.head) _) <*> traverse(f)(as.tail) )

Date: 2012-04-12 12:28 pm (UTC)
From: [identity profile] sassa-nf.livejournal.com
duh!..

def traverse[A, B](f: A => T[B])(as: List[A]): T[List[B]] = foldR(pure Nil)( (p,n) => lift(cons[B] _) <@> f(p) <*> n )


аналогично

def traverse[A, B](f: A => T[B])(as: Stream[A]): T[Stream[B]] = if as.isEmpty pure(Stream.empty) else lift(Stream.cons[B] _) <@> f(as.head) <*> traverse(f)(as.tail)

Date: 2012-04-12 05:17 pm (UTC)
From: [identity profile] ivan-gandhi.livejournal.com
о, конечно. спасибо!!!

Profile

juan_gandhi: (Default)
Juan-Carlos Gandhi

July 2025

S M T W T F S
  12345
6789 1011 12
13141516171819
20212223242526
2728293031  

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jul. 13th, 2025 12:41 am
Powered by Dreamwidth Studios