![](/img/trans.png)
[英]Scala macros: How can I get a list of the objects within a given package that inherit some trait?
[英]How can you recursively construct a list inside of a singular Some trait in Scala?
我现在正在阅读红皮书《 Scala中的功能编程》,因此同时我正在学习Scala。 如果我理解正确,特质并不意味着对象。 如果我错了,请纠正我。
我的问题是我不知道如何将A类型的列表包装在Some
特质内。 我会向正确的方向暗示。
在我正在做的练习中,要求我定义一个函数,该函数用于转换列表中的每个元素,然后将整个列表包含在Some
特质内。
这是我的代码:
def traverse[A, B](a: List[A])(f: A => Option[B]): Option[List[B]] = a match {
case Nil => Nil: B
case h :: t => f(h) flatMap ( hh => hh :: traverse(t)(f))
}
我觉得我在这里的路正确,但是scala解释器抱怨::
对Option[List[B]]
不可用。 我认为这是因为函数的类型签名不返回列表,而是返回包装在Some中的List。
但是我对flatMap的直觉也可能是错误的吗? f(h)
返回一个Option[B]
。 调用flatmap实际上看起来在Option内部,所以B
类型正确吗? 我的逻辑是,通过这种方式,我可以使用函数hh :: traverse(t)(f)
构造类型B的列表。 但是我不确定是否会在这里。
如果有什么不同,我将scala解释器与:paste命令一起使用。 我不确定这是否会使事情变得不合时宜。
如果我理解正确,特质并不意味着对象。
特性是特质,对象是对象。 特性有点像Java中的“接口”,而object
是单例对象。 这些单例对象可以从特征扩展。
Some
特质
它返回包装在Some中的列表。
它返回包装在Option
内的列表(即,可以为None
,根本没有任何列表)。 为了在可选列表值上调用::
,您需要另一个map
:
def traverse[A, B](a: List[A])(f: A => Option[B])
: Option[List[B]] = a match {
case Nil => Some(Nil)
case h :: t => f(h) flatMap {
hValue => traverse(t)(f) map {
tValue => hValue :: tValue
}
}
}
您可以将其缩写为:
def traverse[A, B](a: List[A])(f: A => Option[B])
: Option[List[B]] = a match {
case Nil => Some(Nil)
case h :: t => f(h) flatMap {
hValue => traverse(t)(f) map (hValue :: _)
}
}
或立即使用for
-comprehension:
def traverse[A, B](a: List[A])(f: A => Option[B])
: Option[List[B]] = a match {
case Nil => Some(Nil)
case h :: t => for {
hValue <- f(h)
tValue <- traverse(t)(f)
} yield (hValue :: tValue)
}
有关单子运算的更多信息。 Option
是monad,但将其视为具有零或一个值的容器可能会更容易。 像没有元素的List()
或只具有一个元素的List(x)
。 要修改隐藏在容器内的元素,您需要map
:
List(1).map(_ + 1) => List(2)
Some(1).map(_ + 1) => Some(2)
但是map
不能更改列表中元素的数量。 因此,您需要的是另一个操作,称为flatMap
,该操作带有一个函数,该函数又带一个元素并返回List
:
List(1).flatMap { x => List() } => List()
Some(1).flatMap { x => None } => None
List(1).flatMap { x => List(x + 1) } => List(2)
Some(1).flatMap { x => Some(x + 1) } => Some(2)
这将传播“失败”,这是一个空列表,因为List().flatMap { ...whatever...}
将始终返回一个空列表。
traverse
就是这样做的,如果任何元素的函数f
返回None
(即我的解释中的List()
,则传播“失败”,并将非失败结果合并到容器内的新列表中。 由于从traverse
获得的是内部包含列表的容器,因此需要应用map
。 并且由于应该传播“故障”(如果发生),因此需要flatMap
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.