如何通过猫效应效应误差积累?
我一直在努力解决效果中的错误累积问题,我想知道使用猫效应进行建模的惯用方法是什么。
在不涉及效果的情况下,我会做这样的事情:
import cats._
import cats.data._
import cats.implicits._
import cats.effect._
opaque type Version = String
opaque type Path = String
case class ExampleConfig(version: Version, path: Path)
enum ValidationError:
case InvalidVersion
case InvalidPath
// Implementation irrelevant to the example
def validateVersion(version: String): ValidatedNec[ValidationError, Version] = ???
def validatePath(path: String): ValidatedNec[ValidationError, Path] = ???
def validateConfig(version: String, path: String): ValidatedNec[ValidationError, ExampleConfig] =
(validateVersion(version), validatePath(path)).mapN(ExampleConfig.apply)
但是,如果我们现在想象 validatePath
实际上验证文件系统上是否存在该路径,它就会变成类似 Sync
的效果。这使得这种情况变得更加复杂,因为我们现在拥有:
- 一个我们不想使用的额外错误通道,但确实需要处理
- 嵌套类型,这在混合有效验证和常规验证以及存在依赖项时很快就会变得麻烦它们之间,需要某种类型的杂耍
// Implementation irrelevant to the example
def pathExists[F[_]: Sync](path: Path): F[Boolean] = ???
def validatePath2[F[_]: Sync](path: String): F[ValidatedNec[ValidationError, Path]] =
// Such a dependency between validations leads to major painpoints,
// as we now have an effect inside a validation, while we would want it the other way around
validatePath(path)
.fold(
e => Sync[F].delay(e.invalid),
path => Sync[F].ifF(pathExists(path))(path.validNec, ValidationError.InvalidPath.invalidNec)
)
def validateConfig2[F[_]: Sync](version: String, path: String): F[ValidatedNec[ValidationError, ExampleConfig]] =
// We now have a distinction between our regular validations, and effectful validations
val versionValid: ValidatedNec[ValidationError, Version] = validateVersion(version)
for {
pathValid: ValidatedNec[ValidationError, Path] <- validatePath2(path)
// We need to deal with any errors in Syncs error channel,
// in addition to our validation error domain,
// as there technically can be additional errors in here that we want to map to validation errors
.handleError(e => ValidationError.InvalidPath.invalidNec)
} yield (versionValid, pathValid).mapN(ExampleConfig.apply)
是否有更好的、惯用的、使用猫效应建模错误累积效应的方法?
I've been struggling with error accumulation with effects, and I was wondering what the idiomatic way of modeling this is using Cats Effect.
Without involving effects, I would do something like this:
import cats._
import cats.data._
import cats.implicits._
import cats.effect._
opaque type Version = String
opaque type Path = String
case class ExampleConfig(version: Version, path: Path)
enum ValidationError:
case InvalidVersion
case InvalidPath
// Implementation irrelevant to the example
def validateVersion(version: String): ValidatedNec[ValidationError, Version] = ???
def validatePath(path: String): ValidatedNec[ValidationError, Path] = ???
def validateConfig(version: String, path: String): ValidatedNec[ValidationError, ExampleConfig] =
(validateVersion(version), validatePath(path)).mapN(ExampleConfig.apply)
However, if we now imagine validatePath
actually verifies whether the path exists on the filesystem, it becomes an effect like Sync
. This makes this case significantly more complex, as we now have:
- an additional error channel that we don't want to use, but do need to deal with
- nested types, which quickly become a hassle when mixing effectful and regular validations and when there's dependencies between them, requiring some type juggling
// Implementation irrelevant to the example
def pathExists[F[_]: Sync](path: Path): F[Boolean] = ???
def validatePath2[F[_]: Sync](path: String): F[ValidatedNec[ValidationError, Path]] =
// Such a dependency between validations leads to major painpoints,
// as we now have an effect inside a validation, while we would want it the other way around
validatePath(path)
.fold(
e => Sync[F].delay(e.invalid),
path => Sync[F].ifF(pathExists(path))(path.validNec, ValidationError.InvalidPath.invalidNec)
)
def validateConfig2[F[_]: Sync](version: String, path: String): F[ValidatedNec[ValidationError, ExampleConfig]] =
// We now have a distinction between our regular validations, and effectful validations
val versionValid: ValidatedNec[ValidationError, Version] = validateVersion(version)
for {
pathValid: ValidatedNec[ValidationError, Path] <- validatePath2(path)
// We need to deal with any errors in Syncs error channel,
// in addition to our validation error domain,
// as there technically can be additional errors in here that we want to map to validation errors
.handleError(e => ValidationError.InvalidPath.invalidNec)
} yield (versionValid, pathValid).mapN(ExampleConfig.apply)
Is there a better, idiomatic, way of modeling error accumulating effect using Cats Effect?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论