はじめに

こんにちは、びしょ〜じょです。 ScalaMatsuri2019にいってきました。 Scalaはちょっとしか書いてないうえにだいぶ前ですが、論文やコードはぼちぼち読んでるので興味は依然としてだいぶある、という感じの人間です。

良いですね! 東京で開催なので宿泊の必要がなかったので(とはいえ茨城から東京はめんどいので宿泊したかったが……)すんなり申請できました。 懇親会分はレギュレーションにより自費です。 ボクが研究している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

This document introduces the concept of logic monads in Scala by explaining logic programming with Prolog and how it can be implemented using monads and unification. It covers logic programming concepts like backtracking and unification, and how they can be modeled in Scala using monads. It then explains how to implement a logic monad in Scala using the State monad and List monad. Finally, it shows an example implementation of the Prolog predicate my_append in the logic monad. - Download as a PDF, PPTX or view online for free

論理プログラミングを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は強力なので、なんでもできてしまうからなんでもしたくなってしまうのでいけない。

かぶっていけなかったけど興味あるやつとか

Presented at ScalaMatsuri2019 https://2019.scalamatsuri.org
実践 Clean Architecturehttp://2019.scalamatsuri.org/

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が考慮されていない。 しかし1をしたねこはるさん作の、subtypingを考慮したkits-effを利用すればイケる!

fujitaskひいてはトランザクションとsubtypingの話がおもしろかった(小並感)。

ScalaMatsuri 2019http://2019.scalamatsuri.org/index_en.html

どっかスライドまとまってないかな……


おわりに

Scalaおもろいしもっと面白くなる! という気持ちをゲインしたのですごく良かった。 ぼくのかんがえたさいきょうのプログラム言語へのモチベーションも高まってしまった〜〜研究やってる場合じゃねえ!!