第一个最终无标签方法
The first final tagless approach
我第一次尝试在 Scala 中使用无标记最终模式,但遇到了一些困难。
我有以下代数定义:
trait DbSetting[F[_]] {
def read(url: String, user: String, pw: String): F[DbParameter]
}
trait Environment[F[_]] {
def get(v: String) : F[Option[String]]
}
和解释器实现:
final case class DbParameter(url: String, user: String, pw: String)
sealed trait DbError extends NoStackTrace
case object DbSettingError extends DbError
sealed trait DbError extends NoStackTrace
case object DbSettingError extends DbError
// Environment implementation
object Environment {
def apply[F[_]](implicit ev: Environment[F]): ev.type = ev
def impl[F[_]: Sync]: Environment[F] = new Environment[F] {
override def get(v: String): F[Option[String]] =
Sync[F].delay(sys.env.get(v))
}
}
// DbSetting implementation
class DbSystemEnvironment[F[_] : MonadError[*, Throwable]] private(env: Environment[F])
extends DbSetting[F] {
override def read(url: String, user: String, pw: String): F[DbParameter] = env.get(url)
}
我想做的是,将 Environment
组合成 DbSystemEnvironment
。这里的问题是,我无法从 env.get(url)
中获取值,因为我对 DbSystemEnvironment
中的 F
一无所知,除了它是一个 MonadError
。
如何从 env.get(url)::F[Option[String]]
中获取值?
此外,如果env.get(url)
returns Nothing
在read
函数中,那么应该return MonadError
.
如果我正确理解你的问题,你是在问如何从调用 env.get(url)
中提取返回值,然后将其映射到 F[DbParameter]
.
由于您的 F[_]
有 MonadError
,您应该能够通过执行以下操作很容易地映射结果:
import cats.syntax.flatMap._
import cats.syntax.applicative._
import cats.syntax.applicativeError._
override def read(url: String, user: String, pw: String): F[DbParameter] =
env.get(url).flatMap {
case Some(ev) => DbParameter(ev, user, pw).pure[F]
case None => (new Exception("No environment parameter found!")).raiseError[F, DbParameter]
}
我第一次尝试在 Scala 中使用无标记最终模式,但遇到了一些困难。
我有以下代数定义:
trait DbSetting[F[_]] {
def read(url: String, user: String, pw: String): F[DbParameter]
}
trait Environment[F[_]] {
def get(v: String) : F[Option[String]]
}
和解释器实现:
final case class DbParameter(url: String, user: String, pw: String)
sealed trait DbError extends NoStackTrace
case object DbSettingError extends DbError
sealed trait DbError extends NoStackTrace
case object DbSettingError extends DbError
// Environment implementation
object Environment {
def apply[F[_]](implicit ev: Environment[F]): ev.type = ev
def impl[F[_]: Sync]: Environment[F] = new Environment[F] {
override def get(v: String): F[Option[String]] =
Sync[F].delay(sys.env.get(v))
}
}
// DbSetting implementation
class DbSystemEnvironment[F[_] : MonadError[*, Throwable]] private(env: Environment[F])
extends DbSetting[F] {
override def read(url: String, user: String, pw: String): F[DbParameter] = env.get(url)
}
我想做的是,将 Environment
组合成 DbSystemEnvironment
。这里的问题是,我无法从 env.get(url)
中获取值,因为我对 DbSystemEnvironment
中的 F
一无所知,除了它是一个 MonadError
。
如何从 env.get(url)::F[Option[String]]
中获取值?
此外,如果env.get(url)
returns Nothing
在read
函数中,那么应该return MonadError
.
如果我正确理解你的问题,你是在问如何从调用 env.get(url)
中提取返回值,然后将其映射到 F[DbParameter]
.
由于您的 F[_]
有 MonadError
,您应该能够通过执行以下操作很容易地映射结果:
import cats.syntax.flatMap._
import cats.syntax.applicative._
import cats.syntax.applicativeError._
override def read(url: String, user: String, pw: String): F[DbParameter] =
env.get(url).flatMap {
case Some(ev) => DbParameter(ev, user, pw).pure[F]
case None => (new Exception("No environment parameter found!")).raiseError[F, DbParameter]
}