[英]How to interpret a final tagless DSL with ZIO?
我有一個最終的無標簽 DSL 來構建簡單的數學表達式:
trait Entity[F[_]] {
def empty: F[Int]
def int(value: Int): F[Int]
}
trait Operation[F[_]] {
def add(a: F[Int], b: F[Int]): F[Int]
}
我想實現一個 ZIO 解釋器。 根據module-pattern
guide ,可能的實現如下所示:
type Entity = Has[Entity[UIO]]
object Entity {
val test: ULayer[Entity] =
ZLayer.succeed {
new Entity[UIO] {
override def empty: UIO[Int] =
ZIO.succeed(0)
override def int(value: Int): UIO[Int] =
ZIO.succeed(value)
}
}
def empty: URIO[Entity, Int] =
ZIO.accessM(_.get.empty)
def int(value: Int): URIO[Entity, Int] =
ZIO.accessM(_.get.int(value))
}
type Operation = Has[Operation[UIO]]
object Operation {
val test: ULayer[Operation] =
ZLayer.succeed {
new Operation[UIO] {
override def add(a: UIO[Int], b: UIO[Int]): UIO[Int] =
ZIO.tupled(a, b).map { case (x, y) => x + y }
}
}
def add(a: UIO[Int], b: UIO[Int]): URIO[Operation, Int] =
ZIO.accessM(_.get.add(a, b))
}
使用此實現構建表達式時,必須像這樣重復調用provideLayer
:
Operation.subtract(
Entity.empty.provideLayer(Entity.test),
Entity.int(10).provideLayer(Entity.test)
).provideLayer(Operation.test)
這看起來更像是一種反模式。 解釋 DSL 的最慣用或最 ZIO 的方式是什么?
從問題中並不清楚您要達到什么目標,但讓我嘗試回答。
ZIO 的R
參數與構建 DSL 沒有直接關系。 一旦你構建了你的 DSL, R
可以潛在地幫助你以符合人體工程學的方式將它傳遞給你的計算(但可能不是)。
DSL 不是一個精確的術語,但ZIO
仍然不太可能幫助您構建它。 DSL 通常基於簡單的可自省數據類型(所謂的初始編碼)或具有大量F
的抽象數據類型(最終編碼)。 ZIO
數據類型既不是抽象的也不是可自省的。
通過更好地了解 ZIO 回到這個問題,我找到了解決方案。 這是一種變通方法,不符合 ZIO 的精神,不過,我認為它可能值得分享。
我更新了 ZIO 的操作實現:
type Operation = Has[Service[URIO[Entity, *]]]
object Operation {
val live: ULayer[Operation] =
ZLayer.succeed {
new Service[URIO[Entity, *]] {
override def add(a: URIO[Entity, Int])(b: URIO[Entity, Int]): URIO[Entity, Int] =
a.zip(b).map { case (x, y) => x + y }
}
}
}
def add(a: URIO[Entity, Int])(b: URIO[Entity, Int]): URIO[Entity with Operation, Int] =
ZIO.accessM(_.get[Service[URIO[Entity, *]]].add(a)(b))
這樣實體和操作可以像這樣組合:
operation.add(entity.int(5))(entity.int(37))
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.