scalaのmap関数とforのyield

4521 ワード

まずscalaの関数から始めます.
コマンド後に、(x:Int)=>x*2と入力します.
この奇妙なフォーマットはよく知られていませんが、javascriptの関数をよく知っている場合は、次のようにします.
function myfunc(param){
   alert("hello"+ param);
}
これはポップアップウィンドウhelloの関数で、hellp+入力パラメータが表示されます.このparamは値を入力できるだけでなく、別の関数を入力することもできます.別の関数をパラメータとして入力できるように、入力された関数は書き方を変えます.例えば、次のようにします.
var myfunc2 = function (param){
   alert("hello"+ param);
}
関数名を左に移動すると、右にfunctionと()と{}の3つの記号が残り、myfuncに入力できます.
myfunc(myfunc2);
JSにおける関数伝達を理解したが,Scalaにおいても同様であり,上の(x:Int)=>x*2は実際にはJSの(x:Int){x*2}と見なすことができ,右矢印=>の代わりに括弧を用い,両者の意味差は多くない(function付は1つ少ない).jsと同等:
var myfunc3 = function (x) {
  return   x * 2  ;
}
scalaのx:IntはJavaのInt xに似ていて、Intはxのタイプで、jsは動的言語なので、タイプ定義は必要ありません.Scalaの書き方は次のとおりです.
var myfunc = (x:Int) => x * 2
私たち自身が(x:Int)=>x*2と略して書いてもいいし、myfuncと同じようにあちこちで引用して使っていて、名前がないだけで、つまり匿名関数で、別の関数の入力パラメータとして使うことができます.次のようになります.
myfunc2( (x:Int) => x * 2);
myfuncという関数自体も直接使用できます.
myfunc(2)
結果は4です.
ではmyfunc(myfunc(2))はどれくらいでしょうか.ここはmyfunc 2ではなく、myfunc自身です.
myfunc(2)
結果は8です.自分を2回呼び出したことに相当する.
関数プログラミング向けの一般的なイメージは、集積回路の入出力のように例えられます.
入力-->関数演算->出力
したがって、ここ(x:Int)=>x*2にもこの3つの構造があります.
x------>関数演算x*2------>出力x*2の結果を入力します.
出力x*2の結果とx*2の演算は実際には結合されており、一体であるため、一般的にjsのようにreturn x*2を明示的に宣言しない.Scalaの"=>"記号の右側は細部を表し、関数体を表し、ReturnValue isの"右側"を表すと考えられる.
 
ステップ2
前のウォーミングアップがあれば、私たちは関数が第一等公民であることに初歩的な印象を持っています.次に、関数がどのように値として伝達されているかを見てみましょう.
val myList = List(1,2,3,4,5)
for(x:Int <- myList) yield myfunc (x)
yieldはforループに特化し、新しい結果を結果シーケンスに書き込む.ここでmyfunc(x)結果を新しいリストに戻す.結果は、List[Int]=List(2,4,6,8,10)
次に、関数プログラミングに最も一般的な関数mapを導入します.
myList.map((x: Int) => x * 2)
結果もList[Int]=List(2,4,6,8,10);また,集合myListの各要素を(x:Int)=>x*2演算して結果を得ることにも相当する.
入出力という観点からこの関数mapを理解し、mapの入力は(x:Int)=>x*2の出力であり、(x:Int)=>x*2の入力は何でしょうか.xです.では、xはどこから来ましたか.推測はmyListの各要素から来ている可能性があります.
ここでは、フリーフリーフリーフリーフリーフリーフリーフリーフリー変数を持たない関数である関数コンボ(Functional Combinators)定義を導入します.自由変数とは?孤立した変数はありません.例えば、上記の変数はxがmyListの要素から来る孤立変数ではありません.
ここでmapは、リストmyListの各要素にx*2関数を適用し、新しいリストList(2,4,6)を返す.この操作をmapアセンブリと呼び,同様にfilter操作もある.
for(x <- c; if cond) yield {...}
同等:
c.filter(x => cond).map(x => {...})

または
c.withFilter(x => cond).map(x => {...})

  
ここでforにはif文判定が1つ追加されていることに注意してください.すなわち、リストセットの要素をif判定します.これはfilter関数を使用し、filterが入力関数の計算結果をfalseのすべて削除することに相当します.ブール値を返す関数は、通常、述語関数[または判定関数]と呼ばれます.
forの別の形式を見てみましょう.集合はネストされています.
for(x <- c1; y <- c2; z <-c3) {...}

同等:
c1.foreach(x => c2.foreach(y => c3.foreach(z => {...})))

コンビネーションforeachを使用する利点ここでも,forを用いてネストサイクルを行うと,しばしばぼんやりしてしまう可能性があり,コンビネーションを用いると簡単明瞭であることがわかる.foreachというコンポジットはMapに似ていますが、結果は返されません.
val doubled = myList.foreach((x: Int) => x * 2)  
doubled: Unit = ()

ここでforeachは結果がタイプUnitであり、voidのように空である.
flatMapは別の組合せであり、flatは折り畳みまたはネストの意味と理解できる.
for(x <- c1; y <- c2; z <- c3) yield {...}

に等しい
c1.flatMap(x => c2.flatMap(y => c3.map(z => {...})))

ここのforサイクルは上と区別して1つのyieldが多くなって、yieldの第1反応を見て私たちはmapを考えていますが、ここの集合は1つではなく、3つのネストで、flat+mapを使います.なお、zはmapの入力としてネストされたセットの最後の出力である.
もう1つの例を見て、ネストされた集合が次のように仮定します.
 val nestedNumbers = List(List(1, 2), List(3, 4))
nestedNumbers.flatMap(x => x.map(_ * 2)

結果は
List[Int] = List(2, 4, 6, 8)

2つの集合を1つの集合出力に折り畳み,x*2関数計算を適用した.ここで_*2(x:Int)=>x*2と同等、下線_共通コンテキストを表す変数または関数.簡単な書き方です.
ステップ3
入力と出力のある関数を表す(x:Int)=>x*2の周りに展開し続けましょう.別の関数でこの関数を入力パラメータとして使用する必要がある場合、別の関数のメソッドパラメータをどのように定義しますか.myfunc 2(*2)はhardコードの書き方です.
def myfunc2(fn: Int => Int): Int = {
  fn(10)
}
ここでのfn:Int=>Intマッチング(x:Int)=>x*2という抽象は、もちろん(x:Int)=>x+2などであってもよく、入力と出力の戻りが整数であればよい.実行する場合:
myfunc2((x: Int) => x * 2)
結果は20で、実行:
myfunc2((x: Int) => x + 2)
結果は12です.
ここで、fn(10)の10はfn入力パラメータで、fn出力結果はmyfunc 2の入力によって決まるので、アクセス者モードに少し似ていますよ.
次に、独自の関数の組合せを書いてみましょう.
var myfunc = (x: Int) => x * 2
val numbers = List(1, 2, 3, 4)
def ourMap(numbers: List[Int], fn: Int => Int): List[Int] = {  numbers.map((x: Int) => x * 2)}
ourMap(numbers, myfunc(_))
結果はList[Int]=List(2,4,6,8)