咳が止まらない状態で非常に厳しいですが、来ていますので、自分用のメモを残しておきます。
関数型(function type)を見つめるプログラミング / 山下さん
- 関数の型、 Haskell では第一級
- リスト型
aが型なら[a]も型 - タプル
abが型なら(a, b)も型 - タプル
abが型ならa -> bも型- a が domain 、 b が codomain
- 高階関数型
- domain が関数
(a -> b) -> c - codomain が関数
a -> (b -> c)こちらは意識されにくい
- domain が関数
- 2変数関数
(a, b) -> c- Haskell 以外でもよく使う
- セクション
(+)は高階関数aが domain、bが codomain
- 逆に、 codomain が関数の高階関数は 2 項演算子
f: a -> a -> a`f`
curry :: ((a, b) -> c) -> a -> b -> cは高階化関数- 部分適用演算子、でもある
f `curry` x
- 部分適用演算子、でもある
map :: (a -> b) -> [a] -> [b]は関数拡張関数mapは拡張適用演算子とも読めるf `map` xsfmapはmapの一般化
ap :: [b -> c] -> ([b] -> [c])も欲しい- 非関数を引数に適用する、拡張適用演算子
<*>はapの一般化
($)は関数適用演算子- 何もしないから
idと一致 - 演算子の結合順位は重要
- 何もしないから
- 二項演算子は拡張適用演算子
◎ :: a -> b -> cについて(◎) = ($) . (◎) = (◎) . ($)
Higher Kinded Datatypes / @fumieval さん
- レコード
- 複数の値に名前をかけ、一つの値にまとめることができる
- 問題はあるが
- フィールドを
Maybeに- 新しいフィールドを追加したときに過去のデータとの整合性など
- データ型の宣言、コードが冗長
- 多相型を使って解決する
- 構造を共通化すると、共通の操作が定義できる
babiesパッケージinstance FunctorB Itemなどが定義されており、 Generics で自動導出bmapbuniqbzipWithbtraverse
fill :: ProductB t => t Identity -> t Maybe -> t IdentityNothing以外のフィールドを埋める関数
display表示用の関数- HKD によるジェネリックプログラミングであれば、目的にあった型に変換できる
- 爆アド : 爆発的なアドバンテージ
extensibleextensibleとbabiesの違いextensibleは標準の仕組みではないので自由度が高いbabiesは標準仕様なので、言語のエコシステムから様々なサポートが得られるextensibleはインスタンスが予め用意されているものbabiesは標準なのでどんな型でも良いextensibleはレコードの追加削除が容易、重複も可能
TangleTの例- 問題点
- これはもはやただの関数型プログラミングではない : Beyond Functional Programing
- Q). レコードに HKD のパラメータを入れたが、なぜ Identity が必要? Functor とは関係ある? type エリアスではだめ?
- A). Functor ではない。 type エリアスでは引数をすべて指定しなければならないので NG
- Q). このスライドの h のカインドが
Type -> Type。複数のTypeパラメータを受けるようにできる- A). できる。
Arrowを受けてname :: h String Intみたいな
- A). できる。
- Q). プロダクションで使っている?
- A). 最近使い始めている。 Tangle はかなり前から
- Q). GHC の Trees that Grow との違いは?
- A). 独立した概念。両方を組み合わせることも
- Q). HKD を使うと制約を使って fold する場合に constraint を必要なときに型ハックが必要で辛い
- A). type application
@Showなど必要。面倒になるのは否めない。extensibleでは成約と成約の組み合わせを扱うためにAndclass などを用意して回避しようとしている
- A). type application
- Q).
Andは何でも使える?- A). はい
- おまけ: OpenGL のライブラリでも HKD を使っている
- シェーダーに渡す型を、自動導出してコードを省略できる
「しんさんきぼう」GHCのderivingテクノロジー
- 神算鬼謀 : GHC の deriving 機能がすごくなっている
- deriving に三種類ある
- Haskellの標準では、特定の型クラスについて、自動で関数適語を生やしてくれる
- 特定の型クラスのみ
- GHC拡張の deriving は3つ
GeneralizedNewtypeDerivingDeriveAnyClassDeriveVia
- GeneralizedNewtypeDeriving (GND)
- DeriveAnyClass
- minimal implementation が空集合であるクラスを deriving 指定できるように
- デフォルト実装があれば、 deriving 可能になる (
instance Xxx宣言の代わり)
- DerivingVia
- GNDをもっと一般化したもの
deriving (Numeric) via Natviaは、newtypeを複数経由している場合に、どの実装を使うか選べる- 経由していなくても representation が同じであれば
viaで指定できる newtypeだけでなくdataでも使える
DeriveAnyClassGeneralizedNewtypedDerivingがかぶると、警告が出てDeriveAnyClassが使われてしまうDerivingStrategies:deriving stockderiving anyclassderiving newtypeが選べる- デフォルト実装を使うなら
anyclass、オーバーライドならnewtypeかvia
- 「これが newtype の力だ、見たか!」
- Q). どういう型を使うときに使える?
Haskell メタプログラミングによるEgisonのパターンマッチの実装
- MiniEgison : 2010 年から使っている Egison の機能を GHC へ移植
- いくつかのGHC拡張を使っている
- MiniEgisonとは
- matchAll すべてのパターンマッチの結果を返す
- matcher パターンの解釈の方法を定義
Listリストとしてマッチ 、Multiset順不同としてマッチ
- non-linear pattern matching :
$xで束縛した値を#(x + 1)で利用- バックトラックで効率良く動く
- infinitely many pattern-matching
- 幅優先探索により、可算無限個マッチさせられる
matchはmatchAllのhead- Egisonのパターンマッチを利用して
mapconcatuniqを実装できるintersectdifferenceも実装できるDavis-Putnam Algorithmを実装する例- 数学的なアルゴリズムを簡単に記述できる表現力がある
- ループは二種類ある
- 探索範囲を狭めるループと、バックトラックを含む再帰
- 後者をEgison pattern matchingへ隠せる
- パターンマッチ指向プログラミング
- 実装のため型システムを考える必要がある
- この型システムをGHCに落とし込む
class Matcher m amはaのマッチャーという関係MatchClause: マッチ式の表現- マッチする関数と、マッチする変数の組
- マッチ式と対象をスタックに積んで評価しながらマッチする
- 色々うまく使ってやっている
nilconsは多層化されているので複数の挙動で使える- 実行時間は2~4倍程度。頑張っている
- 「パターンマッチでこんなに色々できてすごい」
- Q). Lean に Egison を入れると網羅性は?
- A). 研究課題。かなり考える必要がある
- Q). ViewPattern 拡張とできることの違いは?
- A). Non-Linear パターンがサポートできない
- Q). 出力順は?
- A). 幅選択なので、固定。探索木が変われば変わる
関数と型で理解する自動微分 / lotz さん
- 導関数が欲しいときありますよね?
- 微分計算はやりたくない → 自動微分
\x -> x^2 + sin xから\x -> 2 * x + cos xadパッケージを利用var "x"を関数に渡すと、式を表示できるx + x + cos x
- 合成関数の微分法
- 入力関数から計算 forward mode
- 反対から計算 reverse mode
- 他入力、他出力だと効率が変わる
- n < m フォワードモードの効率が良い
- n > m リバースモードの効率が良い
- 機械次元では n > m が多い(特徴量が圧倒的に多い)。 reverse mode が重宝される
- 実装方法
- 二重数 : 二乗すると 0 になる数 ε
data D a = D a a実部を撮るreal、虚部をとるtangent- (a + bε)(c + dε) = ac + (ad + bc)ε ライプニッツルールに対応しているのがミソ。
lift 1実数,infinitesimalεdiffD f x = tangent $ f (x + infinitesimal)これだけで O.K.adパッケージのForwardは二重数のこと
xとyを偏微分していくときにdiffDは問題がある- dx と dy の区別のために適切に
liftをする必要がある
- dx と dy の区別のために適切に
newtype AD s a = AD {unAD :: a}sは幽霊型diffADforall s. AD s (D a) -> AD s (D a)を引数にとるliftする箇所が違うとsが固定されず、型エラーとなるforall s. AD s (..)はこのために必要な型
- reverse mode
- 誤差逆伝搬法はこれに該当する
Reverse s aはAD s aみたいなものTapeWengert List。式の組み立てを記録する- reverse mode は stateful となるため、
unsafePerformIOを使うことになる
- Reverse mode を圏論から考える論文もある。まだ研究中の分野
- Q). forward のほうが効率がいい問題は?
- A). ぱっと思いつかない。 forward mode はきれいなので説明に使われる
- Q). State モナドじゃなくて
unsafeなのは?- A). 演算子のオーバロードで実際したいので。複雑な式は使いまわしたいが、
Listで作ると表現しにくい
- A). 演算子のオーバロードで実際したいので。複雑な式は使いまわしたいが、
- Q).
STモナドと同じ使い方なのに、なぜunsafeIO?- A). 外側に
STが出てきてしまう。内部では ST で評価している
- A). 外側に
- Q). 二重数のうんちくは?
- Q). 整数
1を渡せるのはNumFloat型クラスを受け取れるから?- A). はい
GHCJS + Miso で作る Web フロントエンド / チェシャ猫さん
- フロントエンド書いている人 → 多い → Haskell に比べるとメジャーですから
- サンプル htps://hakelda219.wb.a*p (公開禁止)
- Miso はサーバサイドレンダリングができるが、その話はしない
- GHCJS
- Miso (ロゴは味噌ラーメン)
- GHCJS で Elm Architecture を実装したもの
- 類似品は Reflex など
putStrLenはconsole.logに出る- Elm アーキテクチャとは (TEA: The Elm Architecture)
- Action - updateModel -> Model - (viewModel) -> View -> HTML -> Action -> ...
- Actionを規定にして一方向にしか回らない
updateviewは純粋な関数 (状態がない)- 再現性がある。管理しやすい
Viewから値を取るわけではなく、Modelがあるのが重要
- 他の仕組み
Effect:IO相当の副作用Subscription: 外部から発生したアクションを Model へ反映- 例) マウスが動いたイベントを拾うなど
- チャットのサンプルプログラムを消して、再実装するデモ
- カッコの対応が合わなくてビルドが通らない
- 成功
- Q). nixosを使うのにメンバーがwindowsの場合は?
- A). 知らないOSですね。VM使いましょう
- Q). GHCJS テンプレートハスケルが使えなかった
- A). 使えると称している。「ほぼすべて」というのは依存によっては動かない。 Lens は使える
- Q). 実行時のパフォーマンスは?
- A). Miso のサイトに張ってある。JSがElmと比較して大きい。
- Q). lazy load する仕組みを考えているという噂を聞いた
- A). わかりません
- Q). JSとのつなぎ込みは?
- A). ライブラリを使っている。 lenz っぽい記法でアクセサにアクセスする
- Q). EffectとSubscriptionについて Extensible Efect と関係は?
- A). 特にない
Haskell で作る競技型イベントの裏側 / matsubara0507 さん
- mixi git challenge
- 某社でやっている、 git に絞った競技プログラミング
- 正しいコミットを作ると得点
- 4年目
- 問題例「 users4.csv が push できない。 push せよ」
- 旧構成
- なぜ書き換えたか
- メンテナンスがきつくなってきた
- Jenkins plugin が古すぎ
- スコアボードを作った人は退職
- 8割が趣味
- 作り直すならHaskell
- Jenkins が嫌だった。 DroneCIに (go製)
- GitHub Webhook -> Haskell / Servant -> DroneCI -> Haskell + Elm
- アプリ
- app, store, tool, slack の 4 アプリ
- 依存パッケージ
- Drone の API クライアントがなかった → 作った
- Go 製クライアントを移植
- Servant の定義を Elm の API クライアントを定義
- servant-elm 。elm-bridge (自動生成)
- extensible 対応したのが elmap.hs
- Elm のコードが吐き出される (
:が一つしかない)- elm-bridge が Elm の JSON 定義も吐き出してくれる
- スコアボードを見る機能が重すぎた → cache を実装
- Servant と STM
- Docker
- Stack v1 は Docker 対応していたが、 v2 は
stack imageがなくなった - マルチステージビルドを使えばいいやん、らしい
dockerインテグレーションは残っている
- Stack v1 は Docker 対応していたが、 v2 は
- Docker 化するときは
.stack-workを無視する rio: でボイラーテンプレートを書くのめんどい → mix.hs を作った- 設定をすべて Dhall にした
- DrivingVia は
typeエリアスと宣言が悪い - mixi git challenge は Haskell 製
- Q). 保守はどうするの?
- A). 社内に書ける人はいた。きっと大丈夫でしょう
- Q). Elmの型の自動生成はJSONのprefixと相性が悪い。取り除く際の苦労は?
- A). Extensible は prefix は要らないので困らない。 Extensible を使うのは
- Q). 予約語とぶつからない?
- A). ぶつかりません
大規模数値計算を支える Haskell ── Pragmatic Haskell in Large-Scale Numerical Computation / 石井大海さん
- 写真は一枚目だけ
- Ekemmet さんにメンテーをしてもらって博士号を取った
- 汎用ソルバを書く仕事。微分方程式さえ書けば
- 4000億自由度
- 使っている拡張: TypeApplications, FlexibleContexts, MPTC, DataKinds, TypeFamilies などなど
- Dependent Haskell (依存型)
- 物理量 : 速度、温度、電化
- 表現は同じだが意味が違う
- 境界の計算が大事。同じ量でも種類によって違う
- 人間は不変条件を忘れるので、型に覚えてもらう
- K-form
- GHC は
(k + 1) - 1 = kであることがわからない - 「モナドで仕事を分けている」というツイートがあったが、本当か
- Tagless-Final Style
- 細かい情報はモナド
mにすべて押し付ける - 興味のあるオペレーションを取り出して結果をモナディックにしたもの
- 細かい情報はモナド
Reader,ReaderT env IO- RIO pattern は有用である
DerivingViaで実装の詳細を共有する
=<<などは Lisper のかっこと同じだが、普通の人には難しい- 部屋の温度を扱う場合に
Sequenceとして何を使うかListわかりやすいが、ランダムアクセス不可Vectorを使う。 O(1) で検索可能
- Stream Fusion で効率化できる
foldr f z . map g == foldr (f . g) z変形すれば一回なめるだけで良い- loop を one-pass にする
- Vector の種類
- Boxed, Unboxed, Storable
- 統一的に扱いたい。効率性は損ないたくない
- Stream/Bundle はモナディックな値を想定している
unfoldrMindexM'stream'unstream'の 4 つのプリミティブを借りる
- 破壊的な実行で高速に
PrimMonad:IOSTの抽象化- rio でも安価な破壊的変更
- Stream/Bundle を積極的に使い、 PrimMonad の演算を使うと良い
- 2 ~ 3 倍速くなった
- 破壊的変更は友達、宣言的なコンビネータに包めば怖くない
- ソルバが4種類あるときに、新しい機能を追加すると組合せ爆発
- Plugin で追加できるといい
class Plugin pで定義しておく
Solver '[A, B]: A, B が入ったソルバ- A, B の状態を保持するのに、 extensible record を使うのがいい
- カスタムライブラリを使いたい
- カスタムライブラリを作った理由
- 「人間は忘れるので型に覚えてもらって下さい」
- ゆくゆくはリリースしたい
Cadenza: Building fast functional languages (on the JVM) / Edward Kmett さん
- 速い関数型言語が欲しい
- いろんな言語が GraalVM で動かせる
- ライブコーディング
- ラムダ計算の実装
ValueはClosuureのみ- 完成版があった
unevalの実装- 完成版その2
uneval . evalで正規化BoolNatの追加
- 今後の展望
- Q). なぜ eval するか
- A). eval は速いから。特に依存型について
- Q). Kotlin は?
- A). Scala なら
LT
Haskell で 3D モデルに触れる / as_capabl さん
- 3D のファイルフォーマット
- glTF : 新しい。統一したい。まだだが
- VRM : DWANGOさん
- PMX, FBX : MikuMikuDance, Unity など
- glTF
- CONJCT
- CONfigurable Json sChema Translator
- type generation に注力
holzとglの両方を併用- Haskellは手続き敵言語なのでただ書くだけ
- 回転するデモ
- ライブラリにしたい
holz-gltf
HaskellでIoTやってます / CycloneT さん
- B2C開発でPHPで痛い目にあった
- B2B開発の技術選定で Haskell を知った
- Haskell + Elm が多い
- WebAPI : Servant, Persistent/Esqueleto, Elm-export, Xlsx
- IoT は Webアプリとあまり違わない
- ユーザは何が欲しいかわからないので掘り出す
- 定常的に開発するしかない
- メリット
- 開発速度と品質が両立、規模が大きくてもしんどくない、楽しい
QuoraでHaskellへの愛を語る / かわのさん
- Quora は Yahoo 知恵袋のようなもの
- 若気の至りといっても 44 歳
- どのプログラミングに Haskell と回答を書いた
- 高評価。愛は伝わる
- SIer では C#, Cobol もあるような現場
- 値が変更不可である
- グローバル変数がない
- 変更不可 (Java では final ばかりつける)
- ループがない
- 書いた順に動かない
- 順次処理、分岐、繰り返し・・・のどれもない!
- 学術的なライブラリが多く、プログラミングの世界が深遠だと知れる
- Yasod
- 一晩かけてビルド通らない
- Stackのお陰で一発でビルドできるようになった
- 他の人にHaskellを進められるようになった
- 管理されてる人に足を向けて寝れない : 東京には向けて寝れるな
- 今日東京に来て刺激的だった
Haskellで作ってわかる型クラス / coord_e さん
Numのmulを考えるmulIntmulFloatをまとめられる機能- 同じ名前に別の実装を与える。片付けによってDispatch
- adhoc polymorphism
Num :: * -> Constraintmulに@Intをアプリケーションすると制約が消えるinstanceがなければ消えずにエラーとなる
- 型がついたときにどうやって適切な実装にするのか?
- Dictionary-passing
- 実際の実装を渡している -> 型検査時に決まる
- 「一番話したいところに行く前に終わっちゃうな」
- 「30秒じゃ話せない」
- 終了
ABSTRACT TYPE CLASSES - HOW TO DESGIN A FUTURE PROOF TYPECLAS / mod_poppo さん
- Haskellの型クラスには破壊的な変更が加わる
- 破壊的変更はきつい
- 抽象型クラス : メソッドが公開されていない
- KnownNat : natSing は見えない
- 抽象型クラスだと、実装を変えても何も起きない
- 実際 KnownNat は Integer から Natural に変わっている
- 例えば Monad を抽象にするには、
returnなどを普通の関数にする - 第三者がインスタンスを作れなくなる
- DrivingVia などを使う必要がある
- クラス階層を変えても、破壊的変更を避けられる
- (そのうちブログに書くのでお楽しみに)
GHCのGC / kazu_yamamotoさん
- Servant でも Warp などは使っているので、熊本の方は東京に足を向けて寝ないで!
- 「世代別並列コピーGC」 から 「並列コピーGC と 並行マーク&スイープGC 」に変わる
- コピーGC は生きているオブジェクトを他方へコピーする方式
- 割当が速いが、領域の半分しか使えない
- 関数型プログラミングと相性がいい
- マーク&スイープ方式
- オブジェクトをすべて見て、要らないものを捨てる
- GCが遅く領域が断片化。領域を探すのが遅い
- 並列の実現
- サイズごとに領域がたくさんある
- 新世代と旧世代に分類
- 3回生き残ると旧世代に移す
- 世代別仮説 : 旧世代のGCは少なくていい
- 旧世代のGCは領域が無限に大きくなる。遅い
- GC をするときに GHC はプログラムを止める
- スループットは高いが応答性は低い
- 応答性がいいGoに乗り換え
- (時間切れ)椅子をGCしましょう