ZIO环境搭建
ZIO Environment construction
我开始尝试使用 ZIO,并尝试 运行 以下高度复杂的程序:
import logger.{Logger, _}
import zio.console._
import zio.{system, _}
object MyApp extends App {
override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
app
.provideSome[Logger](_ => Slf4jLogger.create) //1
.fold(_ => 1, _ => 0)
}
val app: ZIO[Console with system.System with Logger, SecurityException, Unit] =
for {
_ <- info("This message from the logger") //2
maybeUser <- system.env("USER")
_ <- maybeUser match {
case Some(userName) => putStrLn(s"Hello ${userName}!")
case None => putStrLn("I don't know your name")
}
} yield ()
}
(Slf4jLogger 是 https://github.com/NeQuissimus/zio-slf4j)
如果我注释行 //1
和 //2
一切正常。但是在上面的表格中我得到了一个类型不匹配的错误:
Error:(13, 45) type mismatch;
found : logger.Slf4jLogger
required: zio.console.Console with zio.system.System with logger.Logger
.provideSome[Logger](_ => Slf4jLogger.create)
我不明白以下内容:
该程序在环境中需要一个 Console
和一个 System
实例,但我以前不需要 .provide
它,当时我没有登录.为什么?为什么我突然需要它?
根据 scaladoc,.provideSome
提供了 运行 这种效果所需的 *一些* 环境,剩下的 R0。 对我来说,这意味着我不必提供完整的环境类型,我可以一个一个地添加所需的模块 - 但它似乎期望完整的 ZEnv 类型,就像 .provide
- 那是什么点?
我无法通过new Logger with Console.Live with system.System.Live
实例化一个匿名的class,因为Slf4jLogger在伴生对象中有一个工厂方法。如何将此工厂方法与其他特征一起使用?
既然在 Java 中创建一个记录器实例有点有效,那么 .provide
甚至是正确的调用函数吗?
PS:我能够以一种丑陋的方式让它工作:
app
.provideSome[ZEnv](_ =>
new Console with Logger with system.System {
override val console = Console.Live.console
override val system = System.Live.system
override val logger = Slf4jLogger.create.logger
}
) //1
.fold(_ => 1, _ => 0)
这编译和 运行s,但是覆盖特征内部成员的混合似乎不正确...
它的工作方式与 .provide
完全相同:
app
.provide(
new Console with Logger with system.System {
override val console = Console.Live.console
override val system = System.Live.system
override val logger = Slf4jLogger.create.logger
}
) //1
.fold(_ => 1, _ => 0)
这是怎么回事?
让我试着解释一下。
如果您看一下 ZEnv
是什么,它是 Clock with Console with System with Random with Blocking
的别名。因此,当您开始实施 def run(args: List[String]): ZIO[ZEnv, Nothing, Int]
时,zio 已经为您提供了这些功能。
您的 app
变量签名具有 return 类型的 zio 和环境 Console with System with Logger
- 突出的一件事是 Logger
功能。它不是标准的,因此 ZIO 无法为您提供。必须自己提供。
这就是您使用 .provideSome[Logger]
所做的 - 您从环境要求中删除了一项功能,使其类型与标准兼容:
type ZEnv = Clock with Console with System with Random with Blocking
type YourEnv = Console with System
type Proof = ZEnv <:< YourEnv
恐怕您必须 return 一个实现您想要提供的所有特征的实例。
如果您查看 provideSome
的 ZIO 文档中的示例,您会发现他们在做完全相同的事情:他们将 Console
转换为 Console with Logging
.
/**
* Provides some of the environment required to run this effect,
* leaving the remainder `R0`.
*
* {{{
* val effect: ZIO[Console with Logging, Nothing, Unit] = ???
*
* effect.provideSome[Console](console =>
* new Console with Logging {
* val console = console
* val logging = new Logging {
* def log(line: String) = console.putStrLn(line)
* }
* }
* )
* }}}
*/
For me that means that I don't have to provide the full environment type, I could add the required modules one by one
没有。您必须为要包装的效果提供完整环境类型的实例(因为它需要)。我认为这是因为我们想在编译时检查它,并且没有办法(没有宏)生成 "mash-up" 堆叠环境而不说明如何做到这一点。以后可能会有一些宏。
just like .provide - so what's the point?
不同之处在于 .provide
您必须从头开始构建所需环境的实例,而无需任何输入。因此,效果(使用您的包装)不再需要任何东西。
而对于 .provideSome
,您自己可以请求一个环境来帮助您构建您提供的实例。该环境将传递到您的函数中。在上面的示例中,他们需要 Console
并将其扩充为 Console with Logging
(通过使用给定的 console
实例)。因此,effect.provideSome[Console](...)
仍然需要一个 Console
(而用 .provide
编写它需要 Nothing
)。
.provideSome[ZEnv](_ =>
new Console with Logger with system.System {
override val console = Console.Live.console
由于您正在使用 provideSome[ZEnv]
,您可能不应该访问全局单例 Console.Live
,但从传入的 env
中获取:
.provideSome[ZEnv](env =>
new Console with Logger with system.System {
override val console = env.console
The program required a Console and a System instance in the environment, yet I did not have to .provide
it before
那是因为ZEnv
,默认环境已经提供了这两个
Since creating a logger instance in Java is kind of effectful, is .provide even the right function to call?
就个人而言,我会忽略构造记录器是有效的。它似乎不值得追踪。我认为它是一些基本设施,它几乎是 class-loading 的一部分。
如果你确实想跟踪效果,你可以这样做
app
.provideSomeM(env => for {
logger <- UIO(Slf4jLogger.create)
} yield new MyEnvironment(env, logger)
)
这是我使用的方式:
import logger.{Logger, _}
import zio.console._
import zio.{system, _}
object MyApp extends App {
override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
app
.fold(_ => 1, _ => 0)
}
val app: ZIO[Environment, SecurityException, Unit] =
for {
_ <- info("This message from the logger").provide( Slf4jLogger.create) // 1
maybeUser <- system.env("USER")
_ <- maybeUser match {
case Some(userName) => putStrLn(s"Hello ${userName}!")
case None => putStrLn("I don't know your name")
}
} yield ()
}
- 我直接在应用程序的
for-comprehension
中提供它。 zio.App
. 中的所有其他内容
我开始尝试使用 ZIO,并尝试 运行 以下高度复杂的程序:
import logger.{Logger, _}
import zio.console._
import zio.{system, _}
object MyApp extends App {
override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
app
.provideSome[Logger](_ => Slf4jLogger.create) //1
.fold(_ => 1, _ => 0)
}
val app: ZIO[Console with system.System with Logger, SecurityException, Unit] =
for {
_ <- info("This message from the logger") //2
maybeUser <- system.env("USER")
_ <- maybeUser match {
case Some(userName) => putStrLn(s"Hello ${userName}!")
case None => putStrLn("I don't know your name")
}
} yield ()
}
(Slf4jLogger 是 https://github.com/NeQuissimus/zio-slf4j)
如果我注释行 //1
和 //2
一切正常。但是在上面的表格中我得到了一个类型不匹配的错误:
Error:(13, 45) type mismatch;
found : logger.Slf4jLogger
required: zio.console.Console with zio.system.System with logger.Logger
.provideSome[Logger](_ => Slf4jLogger.create)
我不明白以下内容:
该程序在环境中需要一个
Console
和一个System
实例,但我以前不需要.provide
它,当时我没有登录.为什么?为什么我突然需要它?根据 scaladoc,
.provideSome
提供了 运行 这种效果所需的 *一些* 环境,剩下的 R0。 对我来说,这意味着我不必提供完整的环境类型,我可以一个一个地添加所需的模块 - 但它似乎期望完整的 ZEnv 类型,就像.provide
- 那是什么点?我无法通过
new Logger with Console.Live with system.System.Live
实例化一个匿名的class,因为Slf4jLogger在伴生对象中有一个工厂方法。如何将此工厂方法与其他特征一起使用?既然在 Java 中创建一个记录器实例有点有效,那么
.provide
甚至是正确的调用函数吗?
PS:我能够以一种丑陋的方式让它工作:
app
.provideSome[ZEnv](_ =>
new Console with Logger with system.System {
override val console = Console.Live.console
override val system = System.Live.system
override val logger = Slf4jLogger.create.logger
}
) //1
.fold(_ => 1, _ => 0)
这编译和 运行s,但是覆盖特征内部成员的混合似乎不正确...
它的工作方式与 .provide
完全相同:
app
.provide(
new Console with Logger with system.System {
override val console = Console.Live.console
override val system = System.Live.system
override val logger = Slf4jLogger.create.logger
}
) //1
.fold(_ => 1, _ => 0)
这是怎么回事?
让我试着解释一下。
如果您看一下 ZEnv
是什么,它是 Clock with Console with System with Random with Blocking
的别名。因此,当您开始实施 def run(args: List[String]): ZIO[ZEnv, Nothing, Int]
时,zio 已经为您提供了这些功能。
您的 app
变量签名具有 return 类型的 zio 和环境 Console with System with Logger
- 突出的一件事是 Logger
功能。它不是标准的,因此 ZIO 无法为您提供。必须自己提供。
这就是您使用 .provideSome[Logger]
所做的 - 您从环境要求中删除了一项功能,使其类型与标准兼容:
type ZEnv = Clock with Console with System with Random with Blocking
type YourEnv = Console with System
type Proof = ZEnv <:< YourEnv
恐怕您必须 return 一个实现您想要提供的所有特征的实例。
如果您查看 provideSome
的 ZIO 文档中的示例,您会发现他们在做完全相同的事情:他们将 Console
转换为 Console with Logging
.
/**
* Provides some of the environment required to run this effect,
* leaving the remainder `R0`.
*
* {{{
* val effect: ZIO[Console with Logging, Nothing, Unit] = ???
*
* effect.provideSome[Console](console =>
* new Console with Logging {
* val console = console
* val logging = new Logging {
* def log(line: String) = console.putStrLn(line)
* }
* }
* )
* }}}
*/
For me that means that I don't have to provide the full environment type, I could add the required modules one by one
没有。您必须为要包装的效果提供完整环境类型的实例(因为它需要)。我认为这是因为我们想在编译时检查它,并且没有办法(没有宏)生成 "mash-up" 堆叠环境而不说明如何做到这一点。以后可能会有一些宏。
just like .provide - so what's the point?
不同之处在于 .provide
您必须从头开始构建所需环境的实例,而无需任何输入。因此,效果(使用您的包装)不再需要任何东西。
而对于 .provideSome
,您自己可以请求一个环境来帮助您构建您提供的实例。该环境将传递到您的函数中。在上面的示例中,他们需要 Console
并将其扩充为 Console with Logging
(通过使用给定的 console
实例)。因此,effect.provideSome[Console](...)
仍然需要一个 Console
(而用 .provide
编写它需要 Nothing
)。
.provideSome[ZEnv](_ =>
new Console with Logger with system.System {
override val console = Console.Live.console
由于您正在使用 provideSome[ZEnv]
,您可能不应该访问全局单例 Console.Live
,但从传入的 env
中获取:
.provideSome[ZEnv](env =>
new Console with Logger with system.System {
override val console = env.console
The program required a Console and a System instance in the environment, yet I did not have to
.provide
it before
那是因为ZEnv
,默认环境已经提供了这两个
Since creating a logger instance in Java is kind of effectful, is .provide even the right function to call?
就个人而言,我会忽略构造记录器是有效的。它似乎不值得追踪。我认为它是一些基本设施,它几乎是 class-loading 的一部分。
如果你确实想跟踪效果,你可以这样做
app
.provideSomeM(env => for {
logger <- UIO(Slf4jLogger.create)
} yield new MyEnvironment(env, logger)
)
这是我使用的方式:
import logger.{Logger, _}
import zio.console._
import zio.{system, _}
object MyApp extends App {
override def run(args: List[String]): ZIO[ZEnv, Nothing, Int] = {
app
.fold(_ => 1, _ => 0)
}
val app: ZIO[Environment, SecurityException, Unit] =
for {
_ <- info("This message from the logger").provide( Slf4jLogger.create) // 1
maybeUser <- system.env("USER")
_ <- maybeUser match {
case Some(userName) => putStrLn(s"Hello ${userName}!")
case None => putStrLn("I don't know your name")
}
} yield ()
}
- 我直接在应用程序的
for-comprehension
中提供它。zio.App
. 中的所有其他内容