咳が止まらない状態で非常に厳しいですが、来ていますので、自分用のメモを残しておきます。
関数型(function type)を見つめるプログラミング / 山下さん
- 関数の型、 Haskell では第一級
- リスト型
a
が型なら[a]
も型 - タプル
a
b
が型なら(a, b)
も型 - タプル
a
b
が型なら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` xs
fmap
はmap
の一般化
ap :: [b -> c] -> ([b] -> [c])
も欲しい- 非関数を引数に適用する、拡張適用演算子
<*>
はap
の一般化
($)
は関数適用演算子- 何もしないから
id
と一致 - 演算子の結合順位は重要
- 何もしないから
- 二項演算子は拡張適用演算子
◎ :: a -> b -> c
について(◎) = ($) . (◎) = (◎) . ($)
Higher Kinded Datatypes / @fumieval さん
- レコード
- 複数の値に名前をかけ、一つの値にまとめることができる
- 問題はあるが
- フィールドを
Maybe
に- 新しいフィールドを追加したときに過去のデータとの整合性など
- データ型の宣言、コードが冗長
- 多相型を使って解決する
- 構造を共通化すると、共通の操作が定義できる
babies
パッケージinstance FunctorB Item
などが定義されており、 Generics で自動導出bmap
buniq
bzipWith
btraverse
fill :: ProductB t => t Identity -> t Maybe -> t Identity
Nothing
以外のフィールドを埋める関数
display
表示用の関数- HKD によるジェネリックプログラミングであれば、目的にあった型に変換できる
- 爆アド : 爆発的なアドバンテージ
extensible
extensible
と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
では成約と成約の組み合わせを扱うためにAnd
class などを用意して回避しようとしている
- A). type application
- Q).
And
は何でも使える?- A). はい
- おまけ: OpenGL のライブラリでも HKD を使っている
- シェーダーに渡す型を、自動導出してコードを省略できる
「しんさんきぼう」GHCのderivingテクノロジー
- 神算鬼謀 : GHC の deriving 機能がすごくなっている
- deriving に三種類ある
- Haskellの標準では、特定の型クラスについて、自動で関数適語を生やしてくれる
- 特定の型クラスのみ
- GHC拡張の deriving は3つ
GeneralizedNewtypeDeriving
DeriveAnyClass
DeriveVia
- GeneralizedNewtypeDeriving (GND)
- DeriveAnyClass
- minimal implementation が空集合であるクラスを deriving 指定できるように
- デフォルト実装があれば、 deriving 可能になる (
instance Xxx
宣言の代わり)
- DerivingVia
- GNDをもっと一般化したもの
deriving (Numeric) via Nat
via
は、newtype
を複数経由している場合に、どの実装を使うか選べる- 経由していなくても representation が同じであれば
via
で指定できる newtype
だけでなくdata
でも使える
DeriveAnyClass
GeneralizedNewtypedDeriving
がかぶると、警告が出てDeriveAnyClass
が使われてしまうDerivingStrategies
:deriving stock
deriving anyclass
deriving 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のパターンマッチを利用して
map
concat
uniq
を実装できるintersect
difference
も実装できるDavis-Putnam Algorithm
を実装する例- 数学的なアルゴリズムを簡単に記述できる表現力がある
- ループは二種類ある
- 探索範囲を狭めるループと、バックトラックを含む再帰
- 後者をEgison pattern matchingへ隠せる
- パターンマッチ指向プログラミング
- 実装のため型システムを考える必要がある
- この型システムをGHCに落とし込む
class Matcher m a
m
はa
のマッチャーという関係MatchClause
: マッチ式の表現- マッチする関数と、マッチする変数の組
- マッチ式と対象をスタックに積んで評価しながらマッチする
- 色々うまく使ってやっている
nil
cons
は多層化されているので複数の挙動で使える- 実行時間は2~4倍程度。頑張っている
- 「パターンマッチでこんなに色々できてすごい」
- Q). Lean に Egison を入れると網羅性は?
- A). 研究課題。かなり考える必要がある
- Q). ViewPattern 拡張とできることの違いは?
- A). Non-Linear パターンがサポートできない
- Q). 出力順は?
- A). 幅選択なので、固定。探索木が変われば変わる
関数と型で理解する自動微分 / lotz さん
- 導関数が欲しいときありますよね?
- 微分計算はやりたくない → 自動微分
\x -> x^2 + sin x
から\x -> 2 * x + cos x
ad
パッケージを利用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
は幽霊型diffAD
forall s. AD s (D a) -> AD s (D a)
を引数にとるlift
する箇所が違うとs
が固定されず、型エラーとなるforall s. AD s (..)
はこのために必要な型
- reverse mode
- 誤差逆伝搬法はこれに該当する
Reverse s a
はAD s a
みたいなものTape
Wengert 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
を渡せるのはNum
Float
型クラスを受け取れるから?- 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を規定にして一方向にしか回らない
update
view
は純粋な関数 (状態がない)- 再現性がある。管理しやすい
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 はモナディックな値を想定している
unfoldrM
indexM'
stream'
unstream'
の 4 つのプリミティブを借りる
- 破壊的な実行で高速に
PrimMonad
:IO
ST
の抽象化- 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
で正規化Bool
Nat
の追加
- 今後の展望
- 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
を考えるmulInt
mulFloat
をまとめられる機能- 同じ名前に別の実装を与える。片付けによってDispatch
- adhoc polymorphism
Num :: * -> Constraint
mul
に@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しましょう