在展平函数中使用的模式匹配中的列表[_]的说明

时间:2014-10-19 11:17:42

标签: scala pattern-matching flatmap partial-functions

我是scala的新手,我无法理解以下功能

val L = List(List(1, 1), 2, List(3, List(5, 8)))       

def flatten(l: List[Any]): List[Any] =  l flatMap {
    case ms:List[_] => flatten(ms)
    case l => List(l)
}                                         

flatten(L)                      // res2: List[Any] = List(1, 1, 2, 3, 5, 8)

特别是我不理解flatMap和模式匹配的组合以及第一种情况的含义ms:List[_]

有人可以解释一下,也许可以提供一个更简单的例子来澄清这个概念吗?

1 个答案:

答案 0 :(得分:13)

mapflatMap

首先flatMap是一个higher-order函数。

map也是一个高阶函数,它会通过在List的所有元素上应用函数将List转换为新的List。例如,如果你有

val l = List(1,2,3)

您可以使用

map将其添加到新列表中
val doubled = l.map(_ * 2)         // List(2,4,6)

那么flatMap是什么?当您的函数获得flatMap但返回Int时,List[Int]非常有用。在这种情况下,如果您将此功能传递给map,那么您获得的内容将是List[List[Int]],但有时您希望获得List[Int]

您可以使用flatMap代替。数学上它等同于第一个map然后flatten结果,但在行动中它可能是基于flatten定义的flatMap函数,而不是相反。

除了技术细节之外,flatten表示如果您有List[List[List...[Int]]],如果您flatten,则会获得List[Int]

当我们看

def flatten(l: List[Any]): List[Any] =  l flatMap {
    case ms:List[_] => flatten(ms)
    case l => List(l)
} 

我们首先需要知道这是什么意思。我们已经知道我们必须将函数传递给flatMap。在这种情况下,我们传递的函数是

{
    case ms:List[_] => flatten(ms)
    case l => List(l)
} 

起初看起来不像是一个功能但是它!它实际上是一个partial function,您可以将其视为具有一些细微差别的函数!

什么是部分功能?

我们可以通过以下方式获得(几乎)相同的结果:

def flatten(l: List[Any]): List[Any] =  l flatMap { _ match {
        case ms:List[_] => flatten(ms)
        case l => List(l)
    }   
}

普通函数和部分函数之间的区别在于某些特定输入可能未定义部分函数。因此编译器将自动从一个以case关键字开头的正文生成部分函数(这不是那么简单,但为了简单起见,我在此处跳过详细信息)。

Type

的模式匹配

ms:List[_]这样的模式称为类型模式。这意味着将在运行时针对ms检查List[_]的类型。 _是一个外卡,表示任何类型,因此ms:List[_]字面意思是任何类型的List(由于类型擦除,您无法使用ms:List[Int]之类的模式,请参阅this主题获取更多信息)。

因此,此代码段上的整个模式匹配意味着

  • 如果ms是列表,则结果为flatten(ms),否则结果为List(l)

这样定义的flatten函数是递归函数,它解包列表并执行此操作直到没有更多列表,然后它将结果再次包装在List中!这种方式List[List[List.......[_]]]将转换为List[_]

类型模式的另一个例子:

def hello(o: Any) = o match {
    case _:Int => "Hi, I am an Int and I'm proud of it!"
    case _:List[_] => "I have many things to tell you! I am a list after all!"
    case b:Boolean => s"I'm simply a flag and my value is $b"
    case _ => "I'm everything else you can imagine :D"
}

消歧

顺便说一句部分功能partially applied function和部分申请完全不同!

Scala中的部分函数的概念与数学中的partial function相同:对于domain的某些值可能未定义的函数。