ProjectSeptemberInc / freek

Freek, a freaky simple Free to combine your DSL seamlessly
Other
198 stars 19 forks source link

Cannot combine local programs without knowing that they can be combined a priori #9

Open marcin-rzeznicki opened 8 years ago

marcin-rzeznicki commented 8 years ago

The following program compiles and works:

import cats.free.Free
import cats.free.Free.liftF
import freek._

sealed trait DSL[R]
case class Get(key: String) extends DSL[Option[Int]]
case class Put(key: String, value: Int) extends DSL[Int]

type Program = DSL :|: FXNil

def get(key: String): Free[Program#Cop, Option[Int]] = Get(key).freek[Program]

sealed trait DSLExtension[A]
case class Log(message: String) extends DSLExtension[Unit]

type Extended = DSLExtension :|: Program

def getAndLog(key: String): Free[Extended#Cop, Option[Int]] = for {
  maybeFound <- get(key).expand[Extended]
  _ <- Log(s"Get performed with result $maybeFound").freek[Extended]
} yield maybeFound

showing we can easily combine "local" DSLs. But there is one issue. The first DSL must be written with that in mind. If it was written without Freek you cannot expand it later without rewriting (at least I do not know how). I would expect the following to work:

import cats.free.Free
import cats.free.Free.liftF
import freek._

sealed trait DSL[R]
case class Get(key: String) extends DSL[Option[Int]]
case class Put(key: String, value: Int) extends DSL[Int]

def get(key: String): Free[DSL, Option[Int]] = liftF(Get(key))

sealed trait DSLExtension[A]
case class Log(message: String) extends DSLExtension[Unit]

type Extended = DSLExtension :|: DSL :|: FXNil

def getAndLog(key: String): Free[Extended#Cop, Option[Int]] = for {
  maybeFound <- get(key).expand[Extended] // ar any other method
  _ <- Log(s"Get performed with result $maybeFound").freek[Extended]
} yield maybeFound
yilinwei commented 8 years ago

@marcin-rzeznicki

See #3.