Re: [scalaz] Re: Working through a Free/Cofree example LPP

61 views
Skip to first unread message

Anwar Rizal

unread,
May 14, 2013, 1:27:41 PM5/14/13
to sca...@googlegroups.com

And

On May 14, 2013 7:01 PM, "eric thul" <eric...@gmail.com> wrote:
Regarding taking the coproduct of two algebras, is it the scalaz.Coproduct that you are referring to?

I was looking into this, but I am running into a variance issue using that with Free.

I have a complete example below, but it seems that the issue is caused since I define the coproduct  of the algebras as

type FooBarLang[A] = Coproduct[FooLanguage, BarLanguage, A]

instead of

type FooBarLang[+A] = Coproduct[FooLanguage, BarLanguage, A]

Would it be feasible define Coproduct as `sealed trait Coproduct[F[+_], G[+_], +A]`? However, perhaps there is a better way to go about this.

Thanks,
 -Eric


PS - Example


import scalaz.{-\/, \/-, \/, ~>, Cofree, Free, Functor, Zap}
import Free.{Gosub, Return, Suspend}

object tester {
  type Foo = String
  type Bar = String

  sealed trait FooLanguage[+A]
  case class GetFoo[+A](id: String, h: Foo => A) extends FooLanguage[A]

  sealed trait BarLanguage[+A]
  case class GetBar[+A](id: String, h: Bar => A) extends BarLanguage[A]

  implicit val fooLanguageFunctor: Functor[FooLanguage] =
    new Functor[FooLanguage] {
      def map[A, B](a: FooLanguage[A])(f: A => B): FooLanguage[B] = a match {
        case GetFoo(i, h) => GetFoo(i, x => f(h(x)))
      }
    }

  implicit val barLanguageFunctor: Functor[BarLanguage] =
    new Functor[BarLanguage] {
      def map[A, B](a: BarLanguage[A])(f: A => B): BarLanguage[B] = a match {
        case GetBar(i, h) => GetBar(i, x => f(h(x)))
      }
    }

  def getFoo(id: String): Free[FooLanguage, Foo] =
    Suspend[FooLanguage, Foo](GetFoo(id, Return[FooLanguage, Foo](_)))

  def getBar(id: String): Free[BarLanguage, Bar] =
    Suspend[BarLanguage, Bar](GetBar(id, Return[BarLanguage, Foo](_)))

  // Cause of the issue using A and not +A
  type FooBarLang[A] = Coproduct[FooLanguage, BarLanguage, A]

  def foo = new (FooLanguage ~> FooBarLang) {
    def apply[A](foo: FooLanguage[A]) = Coproduct.leftc(foo)
  }

  def bar = new (BarLanguage ~> FooBarLang) {
    def apply[A](bar: BarLanguage[A]) = Coproduct.rightc(bar)
  }

  //[error]inferred kinds of the type arguments (tester.FooBarLang) do
  //not conform to the expected kinds of the type parameters (type T).
  //[error] tester.FooBarLang's type parameters do not match type T's
  //expected parameters: [error] type A is invariant, but type _ is
  //declared covariant
  //[error]   val test = getFoo("a").mapSuspension(foo)
  //[error]                          ^
  val test = getFoo("a").mapSuspension(foo)
}

On Monday, May 13, 2013 8:23:46 PM UTC-4, Runar Bjarnason wrote:
I am taking an approach like that in building an API for accessing CouchDB. So far it's working really well. For example, we can have different algebras for reading and writing a database, and use the coproduct of the two for read/write access. Also, I have different languages for "things that operate on databases at the global couch level", and "things that operate on individual databases".

Sorry I don't have an answer for your first (free/cofree) question. I haven't had the time recently to look into it.

Runar



On Mon, May 13, 2013 at 7:27 PM, eric thul <eric...@gmail.com> wrote:
hi All,

To steer the topic of this thread in somewhat of a different direction, I have been considering integrating Free monads and little languages into an application, and I am curious about anyone's experience going this route. Let's say that there would be at least a few languages in the application that one might want to compose to produce larger Free monad language-based APIs. 

For those who have done this before, what are your thoughts on this approach? How did it work out at the end of the day? Were there any gotchas that came up along the way?

I would very much appreciate any thoughts or feedback on the subject.

Best,
 -Eric


On Saturday, May 4, 2013 8:05:57 PM UTC-4, eric thul wrote:
hi All,

I have example (below) of a Free language along with its dual. I was looking into using the zapWith functionality on the Free type to produce a result. However, I am a bit stumped as to why the call to zapWith (below) yields a stack overflow instead of the desired result. There must be something I a missing here, any pointers would be most appreciated.

Also, I am curious whether the usage of Cofree in the example below is on the mark or not. What I mean is that I would like to perhaps yield an optional value when I access the id from the DB type. For example, I am not sure I understand how this might work if I wanted to call `db.get(id)` as opposed to just `db(id)`.

Thanks,
 -Eric

PS - This is using scalaz 7.0.0 on scala 2.10.0


import scalaz.{-\/, \/-, \/, Cofree, Free, Functor, Zap}
import Free.{Gosub, Return, Suspend}

object tester {
  type Foo = String

  sealed trait FooLanguage[+A]
  case class GetFoo[+A](id: String, h: Foo => A) extends FooLanguage[A]

  sealed trait FooLanguageDual[+A]
  case class GetFooDual[+A](a: A, k: String => Foo) extends FooLanguageDual[A]

  implicit val fooLanguageFunctor: Functor[FooLanguage] =
    new Functor[FooLanguage] {
      def map[A, B](a: FooLanguage[A])(f: A => B): FooLanguage[B] = a match {
        case GetFoo(i, h) => GetFoo(i, x => f(h(x)))
      }
    }

  implicit val fooLanguageDualFunctor: Functor[FooLanguageDual] =
    new Functor[FooLanguageDual] {
      def map[A, B](a: FooLanguageDual[A])(f: A => B): FooLanguageDual[B] = a match {
        case GetFooDual(a, k) => GetFooDual(f(a), k)
      }
    }

  implicit val fooLanguageDualZap: Zap[FooLanguage, FooLanguageDual] =
    new Zap[FooLanguage, FooLanguageDual] {
      def zapWith[A, B, C](fa: FooLanguage[A], gb: FooLanguageDual[B])(f: (A, B) => C) = (fa, gb) match {
        case (GetFoo(i, h), GetFooDual(b, k)) => f(h(k(i)), b)
      }
    }

  def getFoo(id: String): Free[FooLanguage, Foo] =
    Suspend[FooLanguage, Foo](GetFoo(id, Return[FooLanguage, Foo](_)))

  type DB = Map[String, Foo]

  val db: DB = Map("test" -> "foo")

  def run(db: DB): Cofree[FooLanguageDual, DB] =
    Cofree.unfoldC[FooLanguageDual, DB](db) { db =>
      GetFooDual(db, db(_))
    }

  val program =
    for {
      x <- getFoo("test")
    } yield s"howdy $x"

  // Stackoverflows
  lazy val res: String = program.zapWith(run(db))((a, _) => a)

  def run2[A](p: Free[FooLanguage, A], db: DB): A =
    p.resume.fold({
      case GetFoo(i, h) => run2(h(db(i)), db)
    }, a => a)

  // Produces "howdy foo"
  lazy val res2: String = run2(program, db)
}

--
You received this message because you are subscribed to the Google Groups "scalaz" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scalaz+un...@googlegroups.com.
To post to this group, send email to sca...@googlegroups.com.
Visit this group at http://groups.google.com/group/scalaz?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

--
You received this message because you are subscribed to the Google Groups "scalaz" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scalaz+un...@googlegroups.com.
To post to this group, send email to sca...@googlegroups.com.
Visit this group at http://groups.google.com/group/scalaz?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.
 
 
Reply all
Reply to author
Forward
0 new messages