0

我有一个最终的无标签 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 指南,可能的实现如下所示:

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 的方式是什么?

4

2 回答 2

0

从问题中并不清楚您要达到什么目标,但让我尝试回答。

  1. ZIO 的R参数与构建 DSL 没有直接关系。一旦你构建了你的 DSL,R它可能会帮助你以符合人体工程学的方式将它传递给你的计算(但可能不是)。

  2. DSL 不是一个精确的术语,但它仍然不太ZIO可能帮助您构建它。DSL 通常基于简单的可自省数据类型(所谓的初始编码)或具有大量Fs 的抽象数据类型(最终编码)。ZIO数据类型既不是抽象的,也不是可自省的。

于 2020-12-07T23:52:18.090 回答
0

通过更好地了解 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))
于 2021-02-18T07:07:57.100 回答