ScalaMatsuri2019いってきた
はじめに
こんにちは、びしょ〜じょです。 ScalaMatsuri2019にいってきました。 Scalaはちょっとしか書いてないうえにだいぶ前ですが、論文やコードはぼちぼち読んでるので興味は依然としてだいぶある、という感じの人間です。
頑張ってる感を出したんでスカラマツリに大学の金で行けないかな〜〜
— びしょ〜じょ (@Nymphium) March 26, 2019
ScalaMatsuriの参加費が皆さんの税金で賄われることとなりました。ありがとうございます。
— びしょ〜じょ (@Nymphium) April 26, 2019
良いですね! 東京で開催なので宿泊の必要がなかったので(とはいえ茨城から東京はめんどいので宿泊したかったが……)すんなり申請できました。 懇親会分はレギュレーションにより自費です。 ボクが研究しているalgebraic effectsに類似する機能であるextensible effectsに関する複数の発表を聞くのが主な目的でした。 他にも面白い目標があったしよく会う人とか久しぶりに会う人とか、知り合いの知り合いと知り合いになるなど、様々な実りのある会合でした。
聞いてて特に面白いなと思ったセッションについていくつか振り返っていきます。
Day1
The advantage of using 'Eff' in Scala Project
R社のスタディサプリではextensible effects, 通称Effをプロダクトで使っているようです。良いですね。 話が前後しますが、Effはまあまあ難しいのが短所です。 それでも複数のエフェクトをfor式内で扱えるのがありあまる長所となっています。
発生させたいエフェクトはなんだったのかというと、例えばFuture[A]
などです。
Future[A]
はとにかくシンプルという長所がある一方、セマフォの制御が難しかったりエラーハンドリングが大雑把になるなどの欠点がある。
ではFuture[Try[A]]
にポケモン進化! となるが、エラーハンドリングがThrowable
どまりです。
Javaのライブラリをラップするときには内部でTry
を使うようです。インターフェースはEither
にしてScala的に利用できるようにするようだ。
Future[E Either A]
にすることで、上記のようにScalaっぽく柔軟にエラーハンドリングができるが、Either
を引き回す必要がある。
EitherT[Future, E, A]
でモナトラを使うことでfor
の中がシンプルになる。
一方モナトラの問題点がそのまま出てくるわけですね。lift問題やモナドスタック、合成の順番、パフォーマンスなど。
Eff[R, A]
はモナトラ同様に複数のエフェクトをいちどきに使うことができる。
のみならず、モナトラの持つ合成順序による振る舞いの違いやパフォーマンス問題が解決されている。
欠点はやはり理解が難しい部分。
extensible effectsはモナトラとの比較がよくされますが、確かにモナトラ以前というものがあり、それらのpros/consがまとまっているのがEffのありがたみをもっと噛みしめるのに役立ちました。
Clean Architectrueと一緒にEffを使っているようですが、CAとEffの相性の良さとかは聞いておくべきだった……。
for
式といえばDSL!(短絡的発想) なのでCAの例の図の層ごとにDSLが定義され、DSLの使えるエフェクトがEffでひとまとまりになっている、などで使えそうな印象があります。
Making Logic Moand
論理プログラミングをScalaでもやろう! という話。 論理プログラミングといえばPrologですが、その本質はbacktrackingとunification。 これをScalaで実現するには……?
filter
のようなcomputationはバックトラッキングと考えられる。
つまりバックトラッキングはMonadPlusである。
backtracking | monadplus |
---|---|
\/ |
plus |
/\ |
flatMap |
成功 | pure |
失敗 | empty |
MonadPlusとしてListを使う。
unificationは変数と値を表す適当なデータ構造でうまくやる。 また変数に対応する値を保つ状態を持つ。 ところでbacktrackingとmutable dataは相性が悪い。 なので状態をimmutableに表したい、つまりStateモナドを使う。 ということで論理プログラミングをおこなうLogiモナド(List + State)を構築する。
よっしゃOKや! というわけではなく、問題点がある。 スタックセーフでない点と、データ構造がListに依存してる点。 これらを解決するために、Freerモナドを利用する。
Freerモナドの継続を持つ部分でType-aligned Sequenceを利用する。
簡単にいうとTASeq(A => B, B => C) === A => C
みたいな感じで関数合成がリストで表現される。
これによってflatMap
の継続を合成するところがスタックセーフになる。
トランポリンなどを使わなくてもスタックセーフになるのが良いですね。
そしてFreerからalgebraic effectsを作る。
各プリミティブをエフェクトとして追加していく。
そしてalgebraic effectsによりLogicモナドを構成して、Listへの依存がなくなる。
Freerのrun
を書くことで、Vector
の戻り値にして有限個の解を得たり、Stream
にして無限の解をいっぱいとってきたり、などなど。
また各プリミティブが個別に定義されているので探索アルゴリズムをカスタマイズしたり追加できる。
例えばカットを定義するなど。
なかなか聴きごたえのある内容でした。 パフォーマンスに関する質問はやはり(やはり?)でてきて、どうすればパフォーマンス良くなるんでしょうね。 静的になんとかなる部分をなんとかするとだいぶパフォーマンスがよくなるので、今はとりあえずcompilationしておきましょう。 『Efficient Compilation of Algebraic Effects and Handlers』を読んでください。
CPS or DI
コンポーネントの分割と合成の方法として、DIを使う方法とCPSを使う方法の比較でした。 複数の関連する処理内容を渡したいときにはDI、そうでなければCPS、アドホックに処理を合成する場合はCPS、という使い分けをすると良いということでした。 CPSはcontinuation monadでサラッと書けるのが良い。 FPとOOPができるScalaならではの使い分けですねえ。
CPSといえばコントロールフローが使えるのが利点ですが、そこに関してあまり活きてないのと、DIとその点の比較がないのがちょっと残念でした。 みなさんご存知ですがCPSは強力なので、なんでもできてしまうからなんでもしたくなってしまうのでいけない。
他
かぶっていけなかったけど興味あるやつとか
Day 2
2日目は主にアンカンファレンスでした。 1日目からアイデアボードに発表案を貼っていって、シールとかで聞きたい意思を表明すると、人気な案が2日目におこなわれる、というシステム。
Bengal: Dotty Cats
(スライドみつからね〜〜涙)
Scala3向けのCatsライクなライブラリとして開発されているBengal。 結局あんまりわかんなかった。 Bengalを作るにあたってキーになるScala3の新機能なんだろうか。 とはいえ知らない新機能が多くて面白かった。
extension methods
コレはKokaのdot記法みたいなやつか。
case class Circle(x: Double, y: Double, radius: Double)
def (c: Circle) circumference: Double = c.radius * math.Pi * 2
Scala的には、オブジェクトにメソッドを新しく生やすという感覚だろうか。 またextension methodsの定義の構文のおかげで二項演算子が直感的に書ける。
def (x : A) + (y : A) : A = x combine y
delegate-given
implicit parameterがいい感じに書ける
delegate imports
importがいい感じに書ける
importe delegate bengal.delegates._
importe delegate bengal.delegates.{for Monad[_]}
export clauses
OCamlのopen
的なやつ。
例ではクラスかなんかのスコープにopenしていたが、OCamlのlet open
よろしく式としても書けるのだろうか?
type lambdas
とうとう言語標準に入った!
opaque type alias
type aliasを作るが、完全なaliasではなく、特定のメソッドを生やすことができるようになる。 余計なオブジェクトを作らないのでランタイムのコストを下げることが期待できるんじゃないでしょうか。
typeclass derivation
はい神
local coherence
delegationでメソッドが衝突したときに手動で解決するやつっぽい。
Haskellかよ〜〜という感じでますますアツくなるな。
fujitask meets extensible effects
トランザクションを型でうまく表現するfujitaskはsubtypingを利用したテクを利用している。 subtyping関係は半順序集合であり、特にScalaの場合は束を作る。 そしてトランザクションは束を作る! なのでこれをScalaのsubtypingで表現できる。 つまりトランザクションがScalaの型でエンコードできる。
そしてFujitaskはモナドだワーイワーイということでfor式でトランザクションをスッキリ書ける。 型クラスとsubtypingのあるScalaだからこそでき、型クラスのないJavaやsubtypingのないHaskellでは実現できない。
ところで様々なforで効果を使いたいわけですが、(中略)extensible effectsを使う。
extensible effectsはsubtypingを持たないHaskellを起源に持ち、antos-effもsubtypingが考慮されていない。
しかし
fujitaskひいてはトランザクションとsubtypingの話がおもしろかった(小並感)。
他
どっかスライドまとまってないかな……
おわりに
Scalaおもろいしもっと面白くなる! という気持ちをゲインしたのですごく良かった。 ぼくのかんがえたさいきょうのプログラム言語へのモチベーションも高まってしまった〜〜研究やってる場合じゃねえ!!