这是人为登录过程的基本 Scala Tagless Final 模式实现。它不会编译,因为它在结尾附近显示“没有找到参数的隐式......”
但是,如果我从程序泛型类型中删除
': Monad: LoginProcessAlgebra[F]'
,特定错误就会消失,但理解开始抱怨,因为 F[_]
不再缩小到 Monad
问题: 为什么 Scala 认为 State 不是 Monad?
import cats.Monad
import cats.data.State
import cats.implicits._
import java.util.UUID
import scala.language.higherKinds
case class Credentials(uid: String, pwd: String)
case class Session(sessionId: String, credentials: Credentials)
object LoginProcessTaglessFinal {
trait LoginProcessAlgebra[F[_]] {
def captureCredentials(name: String, password: String): F[Credentials]
def login(credentials: Credentials): F[Session]
}
type LoginProcessState = State[LoginProcessAlgebra[_], _]
type LoginProcessStateA[A] = LoginProcessState[A]
implicit object LoginProcessInterpreterUsingState extends LoginProcessAlgebra[LoginProcessStateA] {
override def captureCredentials(name: String, password: String): LoginProcessStateA[Credentials] =
State(login => (login, Credentials(name, password)))
override def login(credentials: Credentials): LoginProcessStateA[Session] =
State(login => (login, Session(UUID.randomUUID().toString, credentials)))
}
def program[F[_]: Monad: LoginProcessAlgebra[F]](userName: String, password: String)
(implicit interpreter: LoginProcessAlgebra[F]): F[Session] = for {
credentials <- interpreter.captureCredentials(userName, password)
session <- interpreter.login(credentials)
} yield session
val sessionState = program("someUserName", "p455w0rd")
//compile error here
//due to 'No implicits found for parameters ...'
}
import scala.language.higherKinds
已弃用。没有必要。
编译错误更早开始
https://scastie.scala-lang.org/DmytroMitin/cVmdwXy7RKSWUbn9V0TBGw(Scala 2)
https://scastie.scala-lang.org/DmytroMitin/cVmdwXy7RKSWUbn9V0TBGw/6(Scala 3)
你在这些行中的种类不正确
type LoginProcessState = State[LoginProcessAlgebra[_], _]
type LoginProcessStateA[A] = LoginProcessState[A]
这似乎是 Scala 3.
我换了
type LoginProcessState = State[LoginProcessAlgebra[_], _]
与
// scalacOptions += "-Ykind-projector"
type LoginProcessState = State[LoginProcessAlgebra[?], *]
(即 类型 lambda
[A] =>> State[LoginProcessAlgebra[?], A]
到 存在类型 LoginProcessAlgebra[?]
,另见 Polymorphic method works with type lambda, but not with type wildcard in Scala 3)。
我也换了
def program[F[_]: Monad: LoginProcessAlgebra[F]](userName: String, password: String)
(implicit interpreter: LoginProcessAlgebra[F]): F[Session]
与
def program[F[_]: Monad](userName: String, password: String)
(implicit interpreter: LoginProcessAlgebra[F]): F[Session]
(
LoginProcessAlgebra
可以是上下文绑定,而不是 LoginProcessAlgebra[F]
;你也有上下文绑定和相同的隐式再次,这是不正确的)。
现在错误是
Ambiguous given instances: both value catsStdInstancesForOption in trait OptionInstances and value catsStdInstancesForVector in trait VectorInstances match type cats.Monad[F] of an implicit parameter of method program in object LoginProcessTaglessFinal
https://scastie.scala-lang.org/DmytroMitin/cVmdwXy7RKSWUbn9V0TBGw/3
你只需要指定类型参数
LoginProcessStateA
。无法推断。
val sessionState = program[LoginProcessStateA]("someUserName", "p455w0rd")
https://scastie.scala-lang.org/DmytroMitin/cVmdwXy7RKSWUbn9V0TBGw/5
LoginProcessStateA
好像和LoginProcessState
一样。我正在删除前者。
https://scastie.scala-lang.org/DmytroMitin/cVmdwXy7RKSWUbn9V0TBGw/13