Last active
February 12, 2018 20:17
-
-
Save ioleo/59d453e11ed06a3ad07a208003118cc4 to your computer and use it in GitHub Desktop.
Example of generic tagless algebra with Cats and Freestyle. Additional type args beyond F[_] in algebras are not currently supported. To work around we use path dependent types.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import cats.data.State | |
import freestyle.tagless._ | |
/* domain objects */ | |
sealed trait Acme | |
object Acme { | |
case object AcmeUK extends Acme | |
case object AcmeUS extends Acme | |
} | |
case class CommonId(id: String) | |
trait Item[A <: Acme] { | |
val id: CommonId | |
} | |
case class AcmeUKItem(id: CommonId) extends Item[Acme.AcmeUK.type] | |
case class AcmeUSItem(id: CommonId) extends Item[Acme.AcmeUS.type] | |
/* state */ | |
trait MapState[K, V] { | |
type Type = Map[K, V] | |
type TypeA[A] = State[Type, A] | |
def apply(state: Map[K, V]): Type = state | |
def apply(state: (K, V)*): Type = state.toMap | |
def empty: Type = Map.empty[K, V] | |
} | |
trait CommonState[A <: Acme] extends MapState[CommonId, Item[A]] | |
object AcmeUKState extends CommonState[Acme.AcmeUK.type] | |
object AcmeUSState extends CommonState[Acme.AcmeUS.type] | |
/* freestyle tagless */ | |
trait AcmeStorage[A <: Acme] { | |
@tagless trait Algebra[M[_]] { | |
def put(item: Item[A]): M[Unit] | |
def get(id: CommonId): M[Option[Item[A]]] | |
} | |
} | |
object GenericTaglessAcme extends App { | |
object AcmeUKStorage extends AcmeStorage[Acme.AcmeUK.type] | |
implicit val acmeUKStorageHandler = new AcmeUKStorage.Algebra[AcmeUKState.TypeA] { | |
def put(item: Item[Acme.AcmeUK.type]): AcmeUKState.TypeA[Unit] = State.modify(_.updated(item.id, item)) | |
def get(id: CommonId): AcmeUKState.TypeA[Option[Item[Acme.AcmeUK.type]]] = State.inspect(_.get(id)) | |
} | |
val ukOps = AcmeUKStorage.Algebra[AcmeUKState.TypeA] | |
val inputState = AcmeUKState.empty | |
val (id1, id2, id3) = (CommonId("foo"), CommonId("bar"), CommonId("baz")) | |
val (ukItem1, ukItem2, ukItem3) = (AcmeUKItem(id1), AcmeUKItem(id2), AcmeUKItem(id3)) | |
val program = for { | |
_ <- ukOps.put(ukItem1) | |
_ <- ukOps.put(ukItem2) | |
_ <- ukOps.put(ukItem3) | |
mid <- ukOps.get(id2) | |
} yield mid | |
val (outputState, result) = program.run(inputState).value | |
val assertion1 = outputState == AcmeUKState(id1 -> ukItem1, id2 -> ukItem2, id3 -> ukItem3) | |
val assertion2 = result == Some(ukItem2) | |
println("%s << outputState == AcmeUKState(id1 -> ukItem1, id2 -> ukItem2, id3 -> ukItem3)".format(assertion1)) | |
// true << outputState == AcmeUKState(id1 -> ukItem1, id2 -> ukItem2, id3 -> ukItem3) | |
// true << result == Some(ukItem2) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment