考虑以下嵌套的平面图结构:
val isValid: F[Boolean] = userRepository.isValid(username, password)
isValid.flatMap(valid =>
if (valid) {
userRepository.getClaims(username).flatMap(claims => {
val token = JWTRefreshService.createToken(claims)
Created(token)
}
)
} else {
Unauthorized(headers.`WWW-Authenticate`(NonEmptyList.of(Challenge(scheme = "Bearer", realm =
"Access to authorize a request"))))
}
)
Run Code Online (Sandbox Code Playgroud)
哪里F是F[_] : Sync。
我怎样才能把这个结构改写成 for-comprehension。我无法弄清楚如何在不创建嵌套 for-comprehension 的情况下重写 if else 子句。
在第23章"Scala编程"一书中,作者给出了一个例子:
case class Book(title: String, authors: String*)
val books: List[Book] = // list of books, omitted here
// ?nd all authors who have published at least two books
for (b1 <- books; b2 <- books if b1 != b2;
a1 <- b1.authors; a2 <- b2.authors if a1 == a2)
yield a1
Run Code Online (Sandbox Code Playgroud)
作者说,这将转化为:
books flatMap (b1 =>
books filter (b2 => b1 != b2) flatMap (b2 =>
b1.authors flatMap (a1 =>
b2.authors filter (a2 => a1 == a2) map (a2 => …Run Code Online (Sandbox Code Playgroud) 我刚刚发现自己编写了一段代码如下:
def language(frequencies: Array[String], text: Array[String]) = {
val allText = text.mkString.replace(" ", "")
val emaps = for {
fset <- frequencies
devs = for {
i <- 'a' to 'z'
p = fset.indexOf(i) match {
case -1 => 0d
case x => fset.substring(x + 1, x + 3).toDouble / 100 * allText.size
}
a = allText.count(i ==)
dev = math.pow(p - a, 2)
} yield dev
} yield devs.sum
emaps.min
}
Run Code Online (Sandbox Code Playgroud)
如您所见,该值emaps是从一个字符串数组创建的双打数组.它工作正常.我之前没有看到像这样嵌套的for-comprehension.它可以,还是应该以某种方式重构?
我是scala和大多数函数式语言的新手,我现在正试图计算一个数字.我写了代码:
lazy val factors = for(int <- 2 until math.ceil(math.sqrt(number)).toInt if number%int == 0) yield int
Run Code Online (Sandbox Code Playgroud)
我想知道如果我宣布scala val是懒惰的,那么当我打电话时它不会评估整个理解factors.head吗?
functional-programming scala immutability lazy-evaluation for-comprehension
我有一些代码片段,我生成多个列表(通过for comprehensions),然后连接它们.有一些单元素列表,但这不起作用.在Haskell中,我会做类似的事情
[42 | i == j]
Run Code Online (Sandbox Code Playgroud)
等价的是
(do guard (i == j)
return 42) :: [Int]
Run Code Online (Sandbox Code Playgroud)
要么
(guard (i == j) >>= \_ -> return 1) :: [Int]
Run Code Online (Sandbox Code Playgroud)
在斯卡拉我试过
for (if i == j) yield 42
Run Code Online (Sandbox Code Playgroud)
但它说"非法启动简单模式".
在回答Scala的收益时,作者说"Scala"对于理解"等同于Haskell的"do"符号.
此外,在Scala网站上,它说"理解具有(枚举)产生e的形式,其中枚举是指以分号分隔的枚举器列表.枚举器是引入新变量的生成器,或者是过滤器".但很明显,事实并非如此,因为过滤器似乎只能在发电机之后才能使用.
目前我使用
if (i == j) List(42) else Nil
Run Code Online (Sandbox Code Playgroud)
对于这种特殊情况,我可能不会更喜欢for comprehension语法,而只是使用if-then-else代替.在Haskell中,由于与数学集合构造符号的相似性,它看起来相当不错.
我的问题不是关于风格,而是更多关于技术细节:为什么Haskell和Scala之间的这种特殊情况存在差异?为什么不for (if i == j) yield 42工作?
我知道在Scala中输入是一个大问题,理想情况下,你可以通过使用模式匹配等方式来进行类型转换或任何混乱的解决方案.但是,如果我在一个列表或一系列项目中迭代这些公共超类型的子类型,并且只想在该子类型的序列中使用特定子类型的那些项目,我无法理解如何去做.我不认为我可以在模式匹配中for-comprehension实现这一点.
所以,比方说我有这些类:
sealed abstract class SuperType
case class SubtypeA extends SuperType
case class SubtypeB extends SuperType
Run Code Online (Sandbox Code Playgroud)
我有一个Seq[SuperType],我想得到一个Seq只是SubtypeA实例,所以一个Seq[SubTypeA],所以我可以循环它并执行由SubTypeA所有元素提供的方法.
我不知道为什么这不起作用:
import scala.concurrent.future
import scala.concurrent.Future
import scala.concurrent.ExecutionContext
import scala.concurrent.ExecutionContext.Implicits.global
object FutureTest {
def main(args: Array[String]) {
val result1 = future("a")
val result2 = future("b")
val result3 = future("c")
val res = for {
r1 <- result1
r2 <- result2
r3 <- result3
} yield (r1 + r2 + r3)
for { r <- res} yield(println(r))
}
}
Run Code Online (Sandbox Code Playgroud)
我期待这个打印"abc",但没有真正发生.
我有一个使用ReactiveMongo和MongoDB的Play Framework应用程序,我有以下代码:
def categories(id: String): Future[Vector[Category]] = {...}
....
val categoriesFuture = categories(id)
for {
categories: Vector[Category] <- categoriesFuture
categoryIdsWithoutPerson: Vector[BSONObjectID] <- findCategoryIdsWithoutPerson(categories.map(_.id), personId) //Returns Future[Vector[BSONObjectID]]
categoriesWithoutPerson: Vector[Category] <- categories.filter(category => categoryIdsWithoutPerson.contains(category.id)) //Play cites the error here
} yield categoryIdsWithoutPerson
Run Code Online (Sandbox Code Playgroud)
为了解释这个代码,我去取Vector的Categories包裹在Future,因为这是ReactiveMongo如何汇总.在for理解中,我使用它Vector来从数据库中获取id列表.最后,我使用一个filter调用来保留那些id可以在id列表中找到的类别.
这一切看起来都相当简单.问题是Play在for理解的最后一行给出了以下编译错误:
pattern type is incompatible with expected type;
found : Vector[com.myapp.Category]
required: com.myapp.Category
Run Code Online (Sandbox Code Playgroud)
我不确定为什么所需类型是单个实例Category.
我可以使用一些洞察我做错了什么和/或是否有更简单或更惯用的方法来实现这一点.
我有一个调用api并返回未来的Scala未来,如果结果不正确,那么另一个api调用将提交第一个future的结果并在将来返回.
这就是我到目前为止所拥有的.
val fut1 = Future(queryFirst)
val fut2 = fut1 map {
case y if y.isInstanceOf[NoResult] => Future(queryAgainWithFut1Result)
case x => x
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我访问fut2结果,它会给出这样的结果:
scala.concurrent.Await.result(fut2, 5 seconds)
warning: there was one feature warning; re-run with -feature for details
fut2: Any = scala.concurrent.impl.Promise$DefaultPromise@61ab71c2
Run Code Online (Sandbox Code Playgroud)
如果fut1结果不准确,有没有办法可以选择返回fut2?
编辑: 第二个未来必须使用第一个未来继续api调用.这就是我到目前为止所拥有的.
val fut1 = Future("queryFirst")
val fut2 = fut1 flatMap {
case y if y.isInstanceOf[Int] => Future("queryAgainWithResult(y)")
case x => Future(x)
}
Run Code Online (Sandbox Code Playgroud) 我正在尝试使用for -reherehension以下内容:
val s: Seq[Option[Int]] = //...
val t: Option[Int] = //...
s.map(sv => t.flatMap(tv => sv.map(_ == tv)))
Run Code Online (Sandbox Code Playgroud)
我试过这个:
val r: Seq[Option[Boolean]] = for(
sv <- s;
tv <- t;
svv <- sv
) yield svv == tv //Seq[Boolean] does not conform to Seq[Option[Boolean]]
Run Code Online (Sandbox Code Playgroud)
有没有办法简明扼要地写for-comprehension?