(Basic Programing)
なお、Scala言語の基礎的な補足事項(プログラムの形態が2種類あることと、その扱い方)を別ページに記しておいた(読んでおいて下さい)。
Collectionクラスの階層 |
io.Source.fromFile
を使ってPCの中のファイルからデータを得る![]() |
関数定義の文法と関数の値 |
(確認)関数定義は上図のような文法で行ことを以前に学び使ってきているが、今日はそれと別の別の書き方と使い方の話。
(a)=>{a*2}
のような形で
入力と出力の関係を表現したもの(これも式の一種)を「無名関数(または匿名関数)」と呼ぶ。
![]() |
2引数の関数 |
![]() |
1引数の関数 |
記号 =>
(ダブルアローと呼ばれる)
の、左側が、無名関数に渡される仮引数の並び、右側が関数の本体(値を得るための式)。
階乗の計算(=>例)
![]() |
再帰での階乗 |
![]() |
Collectionのメソッド |
数値(Intなど)からなるCollectionに対するメソッドとして、
sum | (すべて加算) |
product | (すべて乗算) |
max | (最大値) |
min | (最小値) |
などが用意されているので、 階乗の値も簡単に求められる。
(for(i<-1 to 10)yield i).product
// または
(1 to 10).product
![]() |
リレーの流れ |
productを使わない階乗計算(=>例)
(1 to 10).reduce((a,b)=>a*b)
![]() |
2引数の無名関数のイメージ |
個々の要素ごとに、右図のような操作を行うための関数が 起動される。
![]() |
factでの無名関数 |
![]() |
foldのイメージ |
reduce
を使わず、
代わりに(ほぼ似た機能の)fold
を使い、![]() |
高階関数のイメージ |
乱数列の生成(=>例)
for(i<-1 to 100)yield math.random
![]() |
乱数列の生成 |
また、変数にセットしておいてこのあとの実習に使う (板書したが以下のリストにも提示しておいた)
val ns=for(i<-1 to 100)yield
(math.random*1000).toInt
// あるいは mapを使ってもいい
val ns=(1 to 100).map{_=>(math.random*1000).toInt}
//
![]() |
mapの流れ |
平均値は、以下のように除算すればいい。
ns.sum.toDouble/ns.size
// または
(0.0+ns.sum)/ns.size
単純に ns.sum/ns.size
だと、
整数を整数で除算し、
剰余を切り捨てた整数の答えが出てしまい、平均値にならない。
![]() |
reduceでmax |
(a,b)=>if(a>b)a else b
を reduceに渡すといい
(min を求めるなら不等号を逆にする)。
(=>例)選別:
![]() |
filterに使う無名関数 |
たとえば、整数の並び ns の中から、偶数だけを選び出す (新しいCollectionを作る)式は、
ns.filter((n)=>n%2==0)
// または
ns.filter(_%2==0)
プログラミング入門の段階では、
![]() |
sortWithの構成 |
無名関数について:
無名関数は、以下のようなルールで省略した書き方ができる。(=>例)
![]() |
無名関数の略記 |
![]() |
メソッド呼出 |
メソッド呼出について:
![]() |
メソッドチェーン |
1
に対する1引数メソッド to
は、
1.to(10)
、
1 to 10
の両方の書き方が可能。![]() |
メソッド呼出の2つの記法 |
+
、*
など演算子として使われる特種な文字を除いて)。( )
で囲む必要がある。
![]() |
forとmap |
(文法に関する補足のページも参照)
for の後ろの 括弧内の 矢印(<-)の右辺に、
![]() |
toメソッド |
繰り返しが可能なオブジェクトやデータ構造 (「Iterableインタフェースを実装したクラスのインスタンス」) が置かれる。
1 to 10
が、
Iterableなオブジェクトの一種 Range を生成している。1 to 10
に対してメソッドを呼ぶときは、
括弧で囲む必要がある。1 内包表記: map に変換される
for(i<-1 to 20) yield s.circle(...)
// ↑ と ↓ は 同じ意味
(1 to 20).map{(i)=>s.circle(...)}
(1 to 20).map((i)=>s.circle(...))
(1 to 20).map(i=>s.circle(...))
1.to(20).map(i=>s.circle(...))
// ちなみに 以下の2つも同じ意味
1 to 20
1.to(20)
// だが、
1 to 20.map(...) // これは使えない(括弧がないと意味が変わるため)
![]() |
mapの構成 |
2 繰り返し実行: foreach に変換される
for(c<-cs) { ... }
// ↑ と ↓ は 同じ意味
cs.foreach(c=>{...})
foreachの意味
ここまで解説した内容をREPL上で実演した記録(復習に活用下さい)
ようなプログラムを作ってみる。
(解説ページに沿って考えてみよう)
![]() |
発展問題の例 |
ようなプログラムを作ってみる。 (ここは自力で考えてみよう)