我似乎真的不了解Map和FlatMap.我无法理解的是for-comprehension是如何嵌套调用map和flatMap的.以下示例来自Scala中的Functional Programming
def bothMatch(pat:String,pat2:String,s:String):Option[Boolean] = for {
f <- mkMatcher(pat)
g <- mkMatcher(pat2)
} yield f(s) && g(s)
Run Code Online (Sandbox Code Playgroud)
翻译成
def bothMatch(pat:String,pat2:String,s:String):Option[Boolean] =
mkMatcher(pat) flatMap (f =>
mkMatcher(pat2) map (g => f(s) && g(s)))
Run Code Online (Sandbox Code Playgroud)
mkMatcher方法定义如下:
def mkMatcher(pat:String):Option[String => Boolean] =
pattern(pat) map (p => (s:String) => p.matcher(s).matches)
Run Code Online (Sandbox Code Playgroud)
模式方法如下:
import java.util.regex._
def pattern(s:String):Option[Pattern] =
try {
Some(Pattern.compile(s))
}catch{
case e: PatternSyntaxException => None
}
Run Code Online (Sandbox Code Playgroud)
如果有人能够阐明在这里使用map和flatMap背后的理由,那将会很棒.
在使用map,flatmap等函数后,使用withFilter而不是过滤器总是更高效吗?
为什么只支持map,flatmap和foreach?(预期的功能如forall/exists)
为什么这种结构会导致Scala中出现类型不匹配错误?
for (first <- Some(1); second <- List(1,2,3)) yield (first,second)
<console>:6: error: type mismatch;
found : List[(Int, Int)]
required: Option[?]
for (first <- Some(1); second <- List(1,2,3)) yield (first,second)
Run Code Online (Sandbox Code Playgroud)
如果我用List切换Some,它编译得很好:
for (first <- List(1,2,3); second <- Some(1)) yield (first,second)
res41: List[(Int, Int)] = List((1,1), (2,1), (3,1))
Run Code Online (Sandbox Code Playgroud)
这也很好:
for (first <- Some(1); second <- Some(2)) yield (first,second)
Run Code Online (Sandbox Code Playgroud) 据我了解,Scala"for"语法与Haskell的monadic"do"语法非常相似.在Scala中,"for"语法通常用于Lists和Options.我想将它与Eithers 一起使用,但默认导入中不存在必要的方法.
for {
foo <- Right(1)
bar <- Left("nope")
} yield (foo + bar)
// expected result: Left("nope")
// instead I get "error: value flatMap is not a member..."
Run Code Online (Sandbox Code Playgroud)
这个功能是通过一些导入提供的吗?
有一个轻微的障碍:
for {
foo <- Right(1)
if foo > 3
} yield foo
// expected result: Left(???)
Run Code Online (Sandbox Code Playgroud)
对于列表,它将是List().因为Option,它会None.Scala标准库是否为此提供了解决方案?(或许scalaz?)怎么样?假设我想为Either提供我自己的"monad实例",我怎么能这样做?
我有两个返回期货的功能.我试图使用for-yield理解将第一个函数的修改结果输入到另一个函数中.
这种方法有效:
val schoolFuture = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- schoolStore.getSchool(sid.get) if sid.isDefined
} yield s
Run Code Online (Sandbox Code Playgroud)
但是我对那里的"if"感到不满意,似乎我应该可以使用地图了.
但是当我尝试使用地图时:
val schoolFuture: Future[Option[School]] = for {
ud <- userStore.getUserDetails(user.userId)
sid = ud.right.toOption.flatMap(_.schoolId)
s <- sid.map(schoolStore.getSchool(_))
} yield s
Run Code Online (Sandbox Code Playgroud)
我收到编译错误:
[error] found : Option[scala.concurrent.Future[Option[School]]]
[error] required: scala.concurrent.Future[Option[School]]
[error] s <- sid.map(schoolStore.getSchool(_))
Run Code Online (Sandbox Code Playgroud)
我玩了几个变种,但没有找到任何有吸引力的工作.任何人都可以提出更好的理解和/或解释我的第二个例子有什么问题吗?
这是Scala 2.10的一个最小但完整的可运行示例:
import concurrent.{Future, Promise}
case class User(userId: Int)
case class UserDetails(userId: Int, schoolId: Option[Int])
case class School(schoolId: Int, name: String)
trait Error
class UserStore { …Run Code Online (Sandbox Code Playgroud) 我正在尝试验证无效方法的参数,但我找不到解决方案......
谁能告诉我该怎么办?
我正在尝试这样的事情:
def buildNormalCategory(user: User, parent: Category, name: String, description: String): Either[Error,Category] = {
val errors: Option[String] = for {
_ <- Option(user).toRight("User is mandatory for a normal category").right
_ <- Option(parent).toRight("Parent category is mandatory for a normal category").right
_ <- Option(name).toRight("Name is mandatory for a normal category").right
errors : Option[String] <- Option(description).toRight("Description is mandatory for a normal category").left.toOption
} yield errors
errors match {
case Some(errorString) => Left( Error(Error.FORBIDDEN,errorString) )
case None => Right( buildTrashCategory(user) )
}
}
Run Code Online (Sandbox Code Playgroud) 为了理解,我不能只是提出一个印刷声明:
def prod (m: Int) = {
for (a <- 2 to m/(2*3);
print (a + " ");
b <- (a+1) to m/a;
c = (a*b)
if (c < m)) yield c
}
Run Code Online (Sandbox Code Playgroud)
但我可以通过虚拟任务轻松绕过它:
def prod (m: Int) = {
for (a <- 2 to m/(2*3);
dummy = print (a + " ");
b <- (a+1) to m/a;
c = (a*b)
if (c < m)) yield c
}
Run Code Online (Sandbox Code Playgroud)
作为副作用,并且仅在开发中的代码中使用(到目前为止),是否有更好的临时解决方案?
是否有一个严重的问题为什么我不应该使用它,除了副作用?
从与Rex Kerr的讨论来看,必要性已经上升到显示原始代码,这有点复杂,但似乎与问题无关(2x .filter,最后调用方法),但是当我试图将Rex'模式应用到它我失败了,所以我在这里发布:
def prod (p: Array[Boolean], max: Int) …Run Code Online (Sandbox Code Playgroud) 我有一些代码嵌套调用flatMap,如下所示:
foo.flatMap(implicit f => bar(123).flatMap(b =>
/* and so on... implicit f is still in scope here.*/
))
Run Code Online (Sandbox Code Playgroud)
通常,人们会将其写为理解,这使得代码更具可读性:
for {
f <- foo
b <- bar(123)
/* yet more method calls that need f as an implicit parameter*/
}
Run Code Online (Sandbox Code Playgroud)
但我需要f暗示,我不认为有办法用于理解.在那儿?当然我可以明确地传递f,但这意味着再见DSL.我对Scala 2.9和2.10的答案感兴趣.
为了清楚起见,我想做这样的事情,但它不会编译:
for {
implicit f <- foo
b <- bar(123) //bar takes implicit argument
/* yet more method calls that need f as an implicit parameter*/
}
Run Code Online (Sandbox Code Playgroud)
编辑:也许一个功能请求是一个好主意?
EDIT2:这应该适用于所有可以用于理解的类型,因此不仅仅是通常的集合类型,如List或Seq,还有Future …
有没有人知道在实际尝试在REPL(或编译器)中编译之前如何获取(仅Scala部分)desgoared for for/comprehension表达式?
到目前为止,我唯一发现的是编译器"-print"标志,但它为您提供了完整的Scala转换...
假设我有这个monadic类:
case class Foo[A](xs: List[A]) {
def map[B](f: A => B) = Foo(xs map f)
def flatMap[B](f: A => Foo[B]) = Foo(xs flatMap f.andThen(_.xs))
def withFilter(p: A => Boolean) = {
println("Filtering!")
Foo(xs filter p)
}
}
Run Code Online (Sandbox Code Playgroud)
以下是2.10.0 REPL会话:
scala> for { (a, b) <- Foo(List(1 -> "x")) } yield a
res0: Foo[Int] = Foo(List(1))
Run Code Online (Sandbox Code Playgroud)
这与2.10.1中的情况相同:
scala> for { (a, b) <- Foo(List(1 -> "x")) } yield a
Filtering!
res0: Foo[Int] = Foo(List(1))
Run Code Online (Sandbox Code Playgroud)
这对我来说是完全出乎意料的,并且在过滤需要额外约束(例如Scalaz \/或EitherT)的情况下会导致特别混乱的错误.
我无法在2.10.1发行说明中 …