gpt4 book ai didi

scala - 如何处理 `Reader` monad 和 `Try` ?

转载 作者:行者123 更新时间:2023-12-03 20:56:02 25 4
gpt4 key购买 nike

我正在阅读这篇关于 dependency injection in scala with Reader monad 的精彩文章.

原始示例运行良好,但我对 UserRepository.get/find 的返回类型做了一些更改。 .它是 User ,但我把它改成了 Try[User] .

然后代码不会被编译,我尝试了很多次,但仍然没有运气。

import scala.util.Try
import scalaz.Reader

case class User(email: String, supervisorId: Int, firstName: String, lastName: String)

trait UserRepository {
def get(id: Int): Try[User]

def find(username: String): Try[User]
}

trait Users {

def getUser(id: Int) = Reader((userRepository: UserRepository) =>
userRepository.get(id)
)

def findUser(username: String) = Reader((userRepository: UserRepository) =>
userRepository.find(username)
)
}

object UserInfo extends Users {

def userEmail(id: Int) = {
getUser(id) map (ut => ut.map(_.email))
}

def userInfo(username: String) =
for {
userTry <- findUser(username)
user <- userTry // !!!!!!!! compilation error
bossTry <- getUser(user.supervisorId)
boss <- bossTry // !!!!!!!! compilation error
} yield Map(
"fullName" -> s"${user.firstName} ${user.lastName}",
"email" -> s"${user.email}",
"boss" -> s"${boss.firstName} ${boss.lastName}"
)
}

编译错误是:
Error:(34, 12) type mismatch;
found : scala.util.Try[Nothing]
required: scalaz.Kleisli[scalaz.Id.Id,?,?]
user <- userTry
^


Error:(36, 12) type mismatch;
found : scala.util.Try[scala.collection.immutable.Map[String,String]]
required: scalaz.Kleisli[scalaz.Id.Id,?,?]
boss <- bossTry
^

我看了 Kleisli.flatMap的文档( findUsergetUser 的返回类型是 Kleisli ),它要求的参数类型是:
B => Kleisli[M, A, C]

Try不会是 Kleisli ,有这样的错误。

我不知道如何处理它。我可以用 scala.util.Try这里?我怎样才能把它变成 KLeisli类型?我怎样才能使这个例子工作?

最佳答案

您可以使用 ReaderT monad 变压器组成 Reader monad 和 Try monad 变成一个 monad,你可以使用 for - 对等的理解
ReaderT只是 Kleisli 的类型别名,您可以使用 Kleisli.kleisli而不是 Reader.apply构建您的 Reader -y 计算。请注意,您需要 scalaz-contrib 对于 Try 的 monad 实例(或者你可以自己写——这很简单)。

import scala.util.Try
import scalaz._, Scalaz._
import scalaz.contrib.std.utilTry._

case class User(
email: String,
supervisorId: Int,
firstName: String,
lastName: String
)

trait UserRepository {
def get(id: Int): Try[User]

def find(username: String): Try[User]
}

trait Users {
def getUser(id: Int): ReaderT[Try, UserRepository, User] =
Kleisli.kleisli(_.get(id))

def findUser(username: String): ReaderT[Try, UserRepository, User] =
Kleisli.kleisli(_.find(username))
}

既然已经完成了, UserInfo更简单(它现在也可以编译!):
object UserInfo extends Users {
def userEmail(id: Int) = getUser(id).map(_.email)

def userInfo(
username: String
): ReaderT[Try, UserRepository, Map[String, String]] =
for {
user <- findUser(username)
boss <- getUser(user.supervisorId)
} yield Map(
"fullName" -> s"${user.firstName} ${user.lastName}",
"email" -> s"${user.email}",
"boss" -> s"${boss.firstName} ${boss.lastName}"
)
}

我们可以证明它有效:
import scala.util.{ Failure, Success }

val repo = new UserRepository {
val bar = User("bar@mcfoo.com", 0, "Bar", "McFoo")
val foo = User("foo@mcbar.com", 0, "Foo", "McBar")

def get(id: Int) = id match {
case 0 => Success(bar)
case 1 => Success(foo)
case i => Failure(new Exception(s"No user with id $i"))
}

def find(username: String) = username match {
case "bar" => Success(bar)
case "foo" => Success(foo)
case other => Failure(new Exception(s"No user with name $other"))
}
}

进而:
UserInfo.userInfo("foo").run(repo).foreach(println)
Map(fullName -> Foo McBar, email -> foo@mcbar.com, boss -> Bar McFoo)

与运行 Reader 的方式完全相同,但你会得到一个 Try在末尾。

关于scala - 如何处理 `Reader` monad 和 `Try` ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25949608/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com