2

私は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[_]

誰かがそれを説明し、概念を明確にするためのより簡単な例を提供できますか?

4

1 に答える 1

16

mapflatMap

まずは高階関数ですflatMap

mapは、その のすべての要素に関数を適用することにより、Lista を newに変換する高階関数でもあります。たとえば、ListList

val l = List(1,2,3)

mapを使用して新しいリストに追加できます

val doubled = l.map(_ * 2)         // List(2,4,6)

だから何flatMapですか?flatMap関数が を取得するIntが を返す場合に便利ですList[Int]。この場合、この関数を に渡すmapと、得られるものは aになりますが、代わりList[List[Int]]に a を取得したい場合もあります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)
} 

最初は関数のように見えませんが、関数です! 実際には、いくつかのニュアンスを持つ関数と見なすことができる部分関数です!

部分関数とは

以下を使用して (ほぼ) 同じ結果を得ることができます。

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

通常の関数と部分関数の違いは、一部の特定の入力に対して部分関数が定義されていない可能性があることです。そのため、コンパイラはキーワードで始まる本体から部分関数を自動的に生成しますcase(それほど単純ではありませんが、簡単にするためにここでは詳細を省略します)。

タイプ別パターンマッチング

のようなパターンを型パターンms:List[_]と呼びます。これは、 の型がに対して実行時にチェックされることを意味します。はワイルド カードであり、任意の型を意味するため、文字通り任意の型を意味します (型消去のため、 のようなパターンは使用できません。詳細については、このスレッドを参照してください)。msList[_]_ms:List[_]Listms:List[Int]

したがって、このコード スニペットのパターン全体の一致は、次のことを意味します。

  • 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"
}

曖昧さ回避

ちなみに部分機能は、部分適用機能や部分適用とは全く違います!

Scala での部分関数の概念は、数学での部分関数と同じです。ドメインの値の一部が定義されていない可能性がある関数です。

于 2014-10-19T12:19:32.277 に答える