Scalaスキルマップ
windymelt.icon: Scalaをやりすぎて初心者の気持ちがわからない
Pythonはいつもよくわからない状態なので、Pythonを学ぶつもりでScalaを勉強するとよいのでは(??)
重要: ガチ初心者には我々が言うところの「副作用」しか見えていない
ロボットの腕が動く、画面上のカービィが動く
コンピュータとは「する」ものだという理解
副作用に注目し、次に作用に注目してもらう
直感が生えかけているときに、「それでいい」と言って安心させる
既存の我々の良く知る世界を分解していって、プリミティブな要素に還元する。そしてそれを組み上げる方法論へ進めていく
運動会にもプログラムある
還元していく過程で、適切に初心者が持っている世界に対して記号接地させる
ことあるごとに叩き込む™シリーズ
イミュータビリティ
全ては式である
段階
超最初は「半角と全角を区別する」みたいな話をする
最初は「定義する」という概念に触れない
REPLで「使う」のみにとどめる
最初はREPLもいらない。Scastieを使わせる
完全無料ですという話もする
Scastieが多言語対応していない……
Scastieの使い方を練習しましょう、とする
1+1してもらう
REPLに移行したらscala -explainさせる
詳細なエラーメッセージが出るようになる(英語だが……)
たかだか、importするくらい
「読み書き」というくらいだからな
同様に、まずは出力し、入力は後でやる
「出入口」というくらいだからな
Python講座では、全ての基礎は整数から始めている
人々にとって、整数は馴染みがある
小学校で習うはずである
プログラマにとって、文字列は空気であるが、一般的な人々にとって文字列は馴染みがない
我が国が誇る学習指導要領にタダ乗りするべきである
税金で勝手にやってくれてる™
整数に定義されている操作をいくつか紹介する
加減乗除
Floatに入る
「式」の概念に触れられそう
定数
ついに「定義」する
valを使うと、計算されて束縛される
「代入」という概念が出現する
数学のイコールとは違う
が、Scalaでは上書きすることはないので「定義」でいい気もする
valキーワードを利用することで、式の結果に名前を付けることができます。
これが全てである
コメント
関数
定義はしない
呼ぶだけ
が、Predefになっていてそこそこ使えそうな関数がほぼない!!
identityがあるけど何もうれしさが分からない
自明な例は何も嬉しくない™
printlnかなぁ
戻り値(返り値)の概念に触れられない
scala.math.absを呼ぶ
scala.mathのことをパッケージと呼びます、まで一気に走っていいかも
scala.math.absくらいが丁度良いだろう
絶対値は中一の単元
パッケージ(のimport)
pythonとかとは毛色が違う
import mathができない
mathは最初から呼べるから
Pythonでは、パッケージはデフォルトでは「呼べない」
importして初めて名前空間に出現する
(同時にロードが行われるからそうなるのだろう)
Scalaでは、あらゆるパッケージが最初から呼べる
修飾さえすればよいという世界観
importとは、パッケージのシンボルを現在のスコープに導入する行為
コンパイルする言語なので、モジュールのロードとスコープへの導入が切り離されている
import scala.math.absしてもらうか
既に定義された関数や定数を、簡単に呼べるようになる以上のものはない
packageは名前空間を切るにすぎない
文字列
Scalaには"string"しかないので楽
文字列を結合するには"red" ++ "blue"する
"red" + "blue"でもいいのだが、一貫性への直感が芽生えてほしいので++に揃えたい
文字列と整数同士は「操作」ができないよ!
違う種類のデータだ
「文字列」や「整数」といった、データの分け方のことを「型」といいます。
Scalaは、この「型」があるおかげで、バグが発生しにくい仕組みになっています。
文字列と数値の行き来
42.toString
"42".toInt
"42.195".toDouble
一貫性があって良い
基礎的なI/O
println
io.StdIn.readLine
メソッド
データには操作が結び付いています
ほぼ全ての「操作」とは単なるメソッドであることをネタばらしする必要がある
(イミュータビリティ)
Pythonだと、ここから条件式と分岐に発展していくが……
Scalaだとmatchすることが多いのだよな、と思いつつifもやっておく
if cond then 形式にするか、if (cond) {}形式にするか……
ここでブレるのがScalaの微妙なところ
(ほぼ)全てが式であることを叩き込みたいので、以下のような恣意的な例を使いたい:
code:scala
val a = 10
val b = 20
val c = if a < b then "small" else "big"
println(c)
Python入門によれば:
コンピュータのプログラムは、どんなに複雑そうにみえるプログラムでも、細かく分解すれば次の3つの単純な構造の組み合わせで構成されています。
わかる
その一方、FPの枠組みでは「コンピュータのプログラムは、写像と副作用」という世界観もある
三種の神器イデオロギーから逃れたい気持ちがある
というのも、これを内面化しきるとFP不可能になるため
他方、初学者にとって最も身近な(プログラムに近い)パラダイムは何か?ということを考える必要がある
レシピ
道案内
口述
人間は時系列という実在から逃れられない。他方、式は普遍の存在である
お茶女ではどうやってるんだ?
文脈: お茶女ではOCamlを教えていて、関数型女子大生を輩出している
大学二年生ならまぁ分かるだろうが……
であっても、普通にifを教えている
しかし、そのままタプルとパターンマッチに即座に突入している
そしてなめらかに再帰構造をやっている
嬉しいけど、嬉しくはない™
数学的帰納法を履修していないと実践不可能
高校一年
whileみたいなやつは、実は一切無視できたりしないか?
無視しているが最終的にやりたいことは全て理解できる、みたいな意味
whileのずるいところ3選~
累積もやっている
写像も行っている
任意のタイミングで脱出できる
無制限の暴力が君を待っている!!!
whileなんか使っているとろくな大人にならない
そもそも、Scalaはimmutable wayを指向しており、ことあるごとに叩き込む™べきなので、やるべきではない
初心者向けのコースでwhileを教えているから、この世からwhileがなくならない
Pythonのコースでは、しばらくすると、リストのループをはじめる
Scalaユーザからすると、forか.mapでいいじゃん、ということになる
forはflatMapなので、もうすこし我慢したい気もする
Seq(1,2,3).map(_ * 2)じゃん、って先にやったほうが分かりやすくないか?
_はまあいいとして、n => n * 2は先に関数を教えておけばなんとかならない?
無名関数の説明が必要になるので、先にdef double(n: Int): Int = n * 2を教える
結果いらないなら.foreachでいい
関数定義についに入る
valかdefかのおなじみの面倒な側面が登場するが……
defでいい
「関数」としてはdef foo = println(42)としたときの直感のほうが勝るのではないか
「呼び出されると実行され、その結果が帰る」
valの場合は定義した段階で実行され、その結果が束縛される
absを自分で実装してもらうか
ここでそろそろブロックについても知ってもらう
code:scala
def abs(n: Int): Int =
if n > 0 then n else -n
end abs
慣れてきたら、{}を使ってみましょう。という方向性にできないか
う~ん
Pythonではブロックにする必然性があるかもしれないが、Scalaにおいてブロックは「複数の式を束ねて最後の値を返す式」でしかないので、複雑な式でないとブロックの直感が生えない
defも、左辺のシグネチャに対して右辺の定義を与えます、以上のことはない
まず素朴なabsを実装してもらい、次に複数の定数を使った複雑な関数を作ってもらおうか
def abs(n: Int): Int = if n > 0 then n else -n
returnも教えなくていい。これは脱出ハッチ
ローカル定数とグローバルな定数について触れられるようになる
厳密にはグローバルはない
関数の呼び方
namedで呼ぶかどうか、デフォルトはあるか、くらい
Pythonコースではリストに入っている
Scalaにおいて真のListを使うことはたいしてない(なくはない程度)。再帰の例題に丁度いいときに使うくらい
42 :: 43 :: 44 :: Nilみたいな構文を知ってもそんなに嬉しくない
嬉しくなくはないけどそんなに嬉しくない
同様にArrayも生では使わないがち
Scalaにおける優先搭乗はSeq
「シーケンス、つまり順序を持った列を表現します」くらいに言っておく
作成
Seq(1, 2, 3, 4, 5)
Seq.fill(10)(-4)
ウゲー カリー化されている
参照
xs(3)
挿入・置換・削除
イミュータブルなのだよな~
ガッとやれそうな操作がない
これも別に教えなくていいか?
辞書
ScalaだとMap
これもSeqのときとだいたい振る舞いや操作が同じでたすかる
Map("foo" -> 42, "bar" -> 43)
後から、->は(,)のシュガーシンガックスだったというネタばらしをする
作成するときはSomething()とする、という直感を生やしてもらう
参照するときはsth()とする、という直感を生やしてもらう
MapとSeqの相互変換についても触れておく
ここでタプルに触れることになる
unapply(分割代入)
val Seq(x, y, z) = xs
ハイまず処理系のインストールが終わりました
Scala Scriptを書きましょうね~
Hello Worldする
クラスを作る
クラスとは、関数と状態を一緒に扱える便利なものです。
(どうせすぐたいして使わなくなるけどな・・・)
座学
code:mmd
graph TD
Int
Double
Int --> expr
Double --> expr
String
実習
code:mmd
graph TD
lib --> db
lib --> di