Scala FunctionK的类型参数的界限
我正在使用猫。下面是代数的简化版本:Scala FunctionK的类型参数的界限,scala,scala-cats,Scala,Scala Cats,我正在使用猫。下面是代数的简化版本: sealed trait Op[A] object Op { final case class Get[T](name: String) extends Op[T] type OpF[A] = Free[Op, A] def get[T](name: String): OpF[T] = liftF[Op, T](Get[T](name)) } 其中一个口译员将是第三方库的包装器,在这里称为Client,其get方法的签名类似于
sealed trait Op[A]
object Op {
final case class Get[T](name: String) extends Op[T]
type OpF[A] = Free[Op, A]
def get[T](name: String): OpF[T] = liftF[Op, T](Get[T](name))
}
其中一个口译员将是第三方库的包装器,在这里称为Client
,其get
方法的签名类似于:
class Client {
def get[O <: Resource](name: String)
(implicit f: Format[O], d: Definition[O]): Future[O] = ???
}
我尝试了一些方法,比如给我的apply
(比如apply[A(我最初的回答包含了相同的想法,但显然没有提供足够的实现细节。这次,我编写了一份更详细的分步指南,其中讨论了每个中间步骤。每个部分都包含一个单独的可编译代码段。)
TL;DR
在get[T]
中出现的每种类型T
都需要隐式,因此它们必须在构造DSL程序时插入并存储,而不是在执行DSL程序时。这就解决了隐式的问题
有一种通用的策略,可以从几个受限制的自然转换中粘合自然转换~>
trait RNT[R,F[\up>我想我已经找到了一种解决问题的方法,将a与:
导入scala.concurrent.Future
进口猫。~>
导入cats.data.ReaderT
进口猫。免费。免费
对象自由单体{
密封件Op[A]
对象操作{
最后一个案例类Get[T](名称:String)扩展了Op[T]
类型OpF[A]=自由[Op,A]
def get[T](名称:String):OpF[T]=Free.liftF[Op,T](get[T](名称))
}
性状资源
特征格式[A]
特征定义[A]
特质客户{
def get[O结果){
def应用[A](fa:Op[A]):结果[A]=
足总杯比赛{
case Op.Get(名称:String)=>
里德尔{
案例(格式、定义)=>
//'Future[A]`类型归属使Intellij IDEA的类型
//检查者接受代码。
client.get(名称)(格式、定义):Future[A]
}
}
}
}
其基本思想是从Op
生成Reader
,并且Reader
接收可用于隐式参数的值。这解决了类型O
具有格式和定义实例的问题
另一个问题是O
是Resource
的一个子类型。为了解决这个问题,我们只是说格式和定义
实例不仅仅是任何a
的实例,而是碰巧也是资源的任何a
的实例
如果您在使用FutureOp
时遇到问题,请告诉我,一个想法是首先从Op[A]
转到({type L[A]=ReaderT[Future,(Format[A],Definition[A])L
,然后最后从那转到Future[A]
。不确定它是否有效,但我会尝试这样做。换句话说,转换到读卡器以获得(隐式)params,然后调用客户机
方法。我已经尝试过了,但不幸的是,由于资源
子类型的限制,它不起作用:你能用一个如何使用Op
DSL的示例更新这个问题吗?@ionuț-g-stan刚刚感谢你的回答,它真的很有帮助。现在我需要一个Monad
例如,Result
能够运行它,对吗?有一个类似于的运行方法:def run[F[\u]:Monad,a](intp:Op~>F,Op:OpF[a]):F[a]=Op.foldMap(intp)
cats文档说“只要选择了F[\u]它就有一个Monad实例。”,而且由于F是未来
,我已经导入了猫.实例.期货.
和猫.隐式.
但仍有错误。@racetrack您可能需要范围内的隐式执行上下文
。@ionuțg-stan我有一个。@ionuțg.stan我是否正确理解此解决方案现在需要执行上下文
必须以某种方式为所有可能的类型A
提供rmat
和定义
?这将限制格式
和定义
只适用于A
中自然的事物,但我不确定OP希望从何处获得适用于所有类型的高度规则和良好的格式
不知何故,在我看来,这个解决方案似乎是这样说的:“假设我们所有A
都有格式
s和定义
s……”,只是将格式的问题推到更深一层?谢谢你的回答。我不明白的是,在DSL中更改get
如何解决调用客户端的问题。使用[A]获取
?问题是A
的边界没有在apply
中指定。问题是如果我没有在client.get
中指定类型参数,我将得到发散隐式扩展
错误。如果我只说client.get[A]
,我将得到类型参数[A]不符合方法get的类型参数边界[O@racetrack为什么不在客户端中指定类型参数。get
?一旦格式和定义存储在中,get[A
可以调用客户端。get[A](名称)(fmt,dfn)
显式。问题是这样做行不通。它会抛出一个错误,即它不符合方法get的类型参数界限[O
class FutureOp extends (Op ~> Future) {
val client = new Client()
def apply[A](fa: Op[A]): Future[A] =
fa match {
case Get(name: String) =>
client.get[A](name)
}
}
def run[F[_]: Monad, A](intp: Op ~> F, op: OpF[A]): F[A] = op.foldMap(intp)
val p: Op.OpF[Foo] = Op.get[Foo]("foo")
val i = new FutureOp()
run(i, d)
libraryDependencies += "org.typelevel" %% "cats-core" % "1.0.1"
libraryDependencies += "org.typelevel" %% "cats-free" % "1.0.1"
import scala.language.higherKinds
import cats.free.Free
import cats.free.Free.liftF
sealed trait DslOp[A]
case class Get[A](name: String) extends DslOp[A]
type Dsl[A] = Free[DslOp, A]
def get[A](name: String): Dsl[A] = liftF[DslOp, A](Get[A](name))
import scala.concurrent.Future
trait Resource
trait Format[A <: Resource]
trait Definition[A <: Resource]
object Client {
def get[A <: Resource](name: String)
(implicit f: Format[A], d: Definition[A]): Future[A] = ???
}
import scala.concurrent.Future
trait Format[A]
trait Definition[A]
object Client {
def get[A](name: String)(implicit f: Format[A], d: Definition[A])
: Future[A] = ???
}
import cats.free.Free
import cats.free.Free.liftF
import cats.~>
sealed trait DslOp[A]
case class Get[A](name: String, f: Format[A], d: Definition[A])
extends DslOp[A]
type Dsl[A] = Free[DslOp, A]
def get[A](name: String)(implicit f: Format[A], d: Definition[A])
: Dsl[A] = liftF[DslOp, A](Get[A](name, f, d))
val clientInterpreter_1: (DslOp ~> Future) = new (DslOp ~> Future) {
def apply[A](op: DslOp[A]): Future[A] = op match {
case Get(name, f, d) => Client.get(name)(f, d)
}
}
import scala.concurrent.Future
trait Resource
object Client {
def get[A <: Resource](name: String): Future[A] = ???
}
trait RestrictedNat[R, F[_ <: R], G[_]] {
def apply[A <: R](fa: F[A]): G[A]
}
import cats.free.Free
import cats.free.Free.liftF
import cats.~>
sealed trait DslOp[A]
case class Get[A <: Resource](name: String) extends DslOp[A] {
def accept[G[_]](f: RestrictedNat[Resource, Get, G]): G[A] = f(this)
}
type Dsl[A] = Free[DslOp, A]
def get[A <: Resource](name: String): Dsl[A] =
liftF[DslOp, A](Get[A](name))
val clientInterpreter_2: (DslOp ~> Future) = new (DslOp ~> Future) {
def apply[A](op: DslOp[A]): Future[A] = op match {
case g @ Get(name) => {
val f = new RestrictedNat[Resource, Get, Future] {
def apply[X <: Resource](g: Get[X]): Future[X] = Client.get(g.name)
}
g.accept(f)
}
}
}
import scala.concurrent.Future
import cats.free.Free
import cats.free.Free.liftF
import cats.~>
// Client-definition with both obstacles: implicits + type bound
trait Resource
trait Format[A <: Resource]
trait Definition[A <: Resource]
object Client {
def get[A <: Resource](name: String)
(implicit fmt: Format[A], dfn: Definition[A])
: Future[A] = ???
}
// Solution:
trait RestrictedNat[R, F[_ <: R], G[_]] {
def apply[A <: R](fa: F[A]): G[A]
}
sealed trait DslOp[A]
case class Get[A <: Resource](
name: String,
fmt: Format[A],
dfn: Definition[A]
) extends DslOp[A] {
def accept[G[_]](f: RestrictedNat[Resource, Get, G]): G[A] = f(this)
}
type Dsl[A] = Free[DslOp, A]
def get[A <: Resource]
(name: String)
(implicit fmt: Format[A], dfn: Definition[A])
: Dsl[A] = liftF[DslOp, A](Get[A](name, fmt, dfn))
val clientInterpreter_3: (DslOp ~> Future) = new (DslOp ~> Future) {
def apply[A](op: DslOp[A]): Future[A] = op match {
case g: Get[A] => {
val f = new RestrictedNat[Resource, Get, Future] {
def apply[X <: Resource](g: Get[X]): Future[X] =
Client.get(g.name)(g.fmt, g.dfn)
}
g.accept(f)
}
}
}
import scala.concurrent.Future
import cats.~>
import cats.data.ReaderT
import cats.free.Free
object FreeMonads {
sealed trait Op[A]
object Op {
final case class Get[T](name: String) extends Op[T]
type OpF[A] = Free[Op, A]
def get[T](name: String): OpF[T] = Free.liftF[Op, T](Get[T](name))
}
trait Resource
trait Format[A]
trait Definition[A]
trait Client {
def get[O <: Resource](name: String)
(implicit f: Format[O], d: Definition[O]): Future[O]
}
type Result[A] = ReaderT[
Future,
(Format[A with Resource], Definition[A with Resource]),
A,
]
class FutureOp(client: Client) extends (Op ~> Result) {
def apply[A](fa: Op[A]): Result[A] =
fa match {
case Op.Get(name: String) =>
ReaderT {
case (format, definition) =>
// The `Future[A]` type ascription makes Intellij IDEA's type
// checker accept the code.
client.get(name)(format, definition): Future[A]
}
}
}
}