【发布时间】:2020-03-05 00:50:37
【问题描述】:
我创建了一个简单的trait 和他的实现:
trait UserRepositoryAlg[F[_]] {
def find(nick: String): F[User]
def update(user: User): F[User]
}
class UserRepositoryInterpreter extends UserRepositoryAlg[Either[Error, *]] {
override def find(nick: String): Either[Error, User] = for {
res <- users.find(user => user.nick == nick).toRight(UserError)
} yield res
override def update(user: User): Either[Error, User] = for {
found <- users.find(u => u.nick == user.nick).toRight(UserError)
updated = found.copy(points = found.points + user.points)
} yield updated
}
在这里,我想使用Either 或EitherT 来“捕获”错误,但我也想使用IO 或Future 作为主monad。在我的主类中,我创建了对这个实现的调用:
object Main extends App {
class Pointer[F[_] : Monad](repo: UserRepositoryAlg[F]) {
def addPoints(nick: String): EitherT[F, Error, User] = {
for {
user <- EitherT.right(repo.find(nick))
updated <- EitherT.right(repo.update(user))
} yield Right(updated)
}
}
val pointer = new Pointer[IO](new UserRepositoryInterpreter{}).addPoints("nick")
}
但是在创建pointer 的行中,IntelliJ 向我显示了一个错误:Type mismatch - required: UserRepositoryAlg[F], found: UserRepositoryInterpreter,我不明白为什么。我用F[_] 创建了Pointer 类作为IO 并想使用UserRepositoryAlg[F] 的实现。我该如何解决这个问题或者在这种情况下有什么好的做法?如果我想实现这样的目标:IO[Either[Error, User]] 或 EitherT[IO, Error, User]。
我尝试将class UserRepositoryInterpreter extends UserRepositoryAlg[Either[Error, *]] 更改为class UserRepositoryInterpreter[F[_]] extends UserRepositoryAlg[F[Either[Error, *]]] 之类的内容,但没有帮助。
编辑:
我发现了如何使用 Applicative[F] 转换 A => F[A] 来返回 F[Either[Error,User]]:
class UserRepositoryInterpreter[F[_] : Applicative] extends UserRepositoryAlg[F[Either[Error, *]]] {
override def find(nick: String): F[Either[Error, User]] = for {
res <- Applicative[F].pure(users.find(user => user.nick == nick).toRight(UserError))
} yield res
override def update(user: User): F[Either[Error, User]] = for {
found <- Applicative[F].pure(users.find(u => u.nick == user.nick).toRight(UserError))
updated = Applicative[F].pure(found.map(u => u.copy(points = u.points + user.points)))
} yield updated
}
但是我的main函数还是有问题,因为我无法获取Either的Right值:
def addPoints(nick: String): EitherT[F, Error, User] = {
for {
user <- EitherT.liftF(repo.find(nick))
updated <- EitherT.rightT(repo.update(user))
} yield Right(updated)
}
这里updated <- EitherT.rightT(repo.update(user))user是Either[Error, User],但我只需要通过User。所以我尝试做类似的事情:
Right(user).map(u=>u) 并通过它,但它也无济于事。我应该如何取这个值?
【问题讨论】:
标签: scala functional-programming scala-cats tagless-final