Pixel Pedals of Tomakomai

北海道苫小牧市出身の初老の日常

今日は安全なシステムプログラミング言語Rustへの招待の日です

IIJさんでのセミナー を聴講に来ましたので、自分用のメモを残しておきます。

安全なシステムプログラミング言語Rustへの招待 / keenさん

  • 2015 年に 1.0.0 がリリース
    • ここからは安定している
  • 6週間ごとのリリース
  • 言語仕様は2つ
    • Rust2015 と Rust2018
    • 移行ツールはある。両方をコンパイルしてリンクすることも可能
  • 実例
    • firecracker AWS Lambda の内側
    • Magick Pocket: DropBoxのストレージマネージャ
    • Servo: レンダリングエンジン
    • Redox : OS。 大学のプロジェクト
    • TiKV: KVS
  • システムプログラミングは?
    • ランタイムがない (GCがない)
    • メモリは自動管理
    • Cと相互連携
    • 生パケット、組み込み系など
  • メモリ配置
    • Cと違い、詰めようとする
    • #[repr(C)] をつけると、 12 となる
  • イテレータ
    • (2..).filter(...).take(...).for_each(...)
    • 最適化により、速いコードになる
  • トレイト
    • Haskellでいう型クラス
    • C++ の concept らしい
    • 静的ディスパッチ、動的ディスパッチ
    • derive : DebugShow 相当
    • 自分を self で受け取る Python 的なスタイル
    • {:?} で Debug プリントができる
  • 型検査
    • 制約を書いてなければ、メソッドを呼べない
    • C++のテンプレートと違ってコンパイル時に落ちる
  • enum
    • generics, 構造体のように引数も取れる
    • 代数的データ型。木構造をきれいに書ける
  • Ordering
    • 値として定義
    • reverse やメソッドチェーンで簡単に定義できたり
  • 例外はない
    • Result 型を利用する
    • ? で早期 return が可能
    • ? がググりようがないのが初心者には辛い
  • fork
    • nix::unistd::fork の戻り値が、型を見るとわかりやすい
  • forkのデモ
    • alacritty : rust 製のターミナルエミュレータ
    • Cargo.toml に依存を書く
    • cargo run で実行まで一度にやってくれる
  • 安全
    • セキュリティ面。余計なデバグが減る
    • gdbを使わなくてもいい
  • 生産性が高い
    • Cは低級言語。便利な機能があり、低レイヤが扱える、両立
    • async / await は OS がなくても動く
      • システムコールが要らない、という意味。ユーザスレッド。
      • アロケートがなくても動く
      • ステートマシンのコードに変更してくれる
      • 言語仕様としては依存しない
  • 活発なコミュニティ
  • ネットワークドライバを書く実験。Rustが若干遅い
    • 5~6%遅い
    • IPC は Rust の方が断然良い → CPUを使い切れているとも言える
    • 低級な言語でCPUを使い切れないより、高級な言語で使い切りたい
  • 安全
    • NULL Pointer, use after free, 範囲外アクセス, data race は起きない
    • race condition は防げない(デッドロック
      • プログラムのロジックのバグなので
  • 範囲外アクセス
    • vec![1, 2, 3] コンパイル時にチェックしない
    • 実行時例外
    • 固定長配列 [1, 2, 3] に定数でアクセスする場合はコンパイルエラー
  • 所有権
    • 値のライフタイムがある
    • 所有権は移動する。移動後にアクセスするとコンパイルエラー ( move セマンティクス)
    • 関数呼び出しによる所有権の移動
    • 2回データが使えないのは不便
  • 借用
    • &data でデータを貸す。
    • & にはポインタを取るという意味もある
    • 所有するポインタ Box もある
  • 借用は元のデータより長生きできない
  • Rustのデータはイミュータブル
  • C言語では *a = 0; *b = 1; return *a をしても 0 が返るとは限らない
    • a == b のとき
    • Rustでは可変参照は複数作れないので、大丈夫
  • Rust では Pointer Alias の制約が強い
    • 挙動がわかりやすく、コンパイラが最適しやすいというメリット
  • コンパイル時に Read-Write lock がかかっている
  • Nullがほしいときもある
    • find の結果がないとき、など
    • Option
      • i32 など、ポインタじゃない値も nullable にできる
      • 値なのでメソッドが生やせる
    • Option<Pointer> は最適化でポインタになる
  • Copy トレイトでマークすると、 move されない
    • i32 など
  • データには所有者がいる、ポインタは実体がある、nullポインタなどはない
  • アプリケーションの設計に関わる
    • C++のお手本のような設計をするとコンパイラは通りやすい
    • 所有者を意識する。長寿のデータ型を所有者とする
    • データ構造 HashMap などは所有者となる
    • 処理のフローを考えて無駄なコピーを廃する
      • HTTP Request 関連のものは Request に全て持たせるなど
  • get get_mut では所有権が奪えない
    • 所有権を奪うには remove
  • リソースを開放する API がない
    • open はあるが close がない
    • lock はあるが free はない
  • close のエラーは握りつぶされるので注意
    • ファイルディスクリプタに対して close がエラーを吐くと何もできないが (ディスクリプタの再利用があるかも)
    • バッファ付きで読み込み専用ファイルディスクリプタを包むと、書き込めるが、close時に落ちる、などはありうる
      • flush を先にしておくことで回避可能
  • Rustの進歩
    • 参照のライフタイムのチェックを緩めたり
  • 所有権があると書けないデータ構造
    • グラフ
    • opt out する : Rc 複数共有、 RefCell 実行時借用チェックなど
  • RcRefCell はマルチスレッドで使うと落ちてくれる
    • Arc Mutex などを使うと O.K.
    • Rust の Mutex は守る値を明示する
    • Send トレイトが実装されていると、 spawn に渡せる
    • ドキュメントを読まなくてもスレッドセーフか分かる
  • 安全性を捨てる
    • Cの関数を呼ぶ
    • 未初期化のメモリ(ハッシュテーブルなど)
    • unsafe ブロックで囲むとなんでもできる (コンパイルが通るが、セグフォ)
  • unsafe
    • nullポインタを作るのは良い。書き込みはNG
    • 基本は使わない
    • 同頑張っても無理な時 ( Vec など)
    • 高速化(境界外アクセスの無視 get_unchecked
    • C の FFI : safe な API でラップするのが普通
  • コミュニティが活発なものは成長する
    • stack overflowの人気一
    • MicroSoft
    • crates.io 30,000+ クレート ( Ruby は 15 万 )
    • コミュニティ中心でオープン / Mozillaがサポートしているだけ。AWSもサポート
  • Linuxユーザが多い(シェアは 1% のはずだが)
    • rust2020 タグを付けると、希望を吸い上げてくれる

  • UB(Undefined Behavior) が起きない
  • 日本語コミュニティもある (rust-jp slack)
    • beginer チャネルもある

  • Q). Sparkでも使える?
    • A). jarからJNIを使って呼び出さないと。厳しい。Sparkを使ったほうがいい(rustで書き直した人も。CPUバウンドを解決できるらしい)

今日は Haskell Day 2019 の日です

咳が止まらない状態で非常に厳しいですが、来ていますので、自分用のメモを残しておきます。

関数型(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) こちらは意識されにくい
  • 2変数関数 (a, b) -> c
  • セクション (+)高階関数
    • 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
    • fmapmap の一般化
  • ap :: [b -> c] -> ([b] -> [c]) も欲しい
    • 非関数を引数に適用する、拡張適用演算子
    • <*>ap の一般化
  • ($) は関数適用演算子
    • 何もしないから id と一致
    • 演算子の結合順位は重要
  • 二項演算子は拡張適用演算子
    • ◎ :: a -> b -> c について (◎) = ($) . (◎) = (◎) . ($)

Higher Kinded Datatypes / @fumieval さん

  • レコード
    • 複数の値に名前をかけ、一つの値にまとめることができる
    • 問題はあるが
  • フィールドを Maybe
    • 新しいフィールドを追加したときに過去のデータとの整合性など
  • データ型の宣言、コードが冗長
  • 多相型を使って解決する
    • data Item (h :: Type -> Type) = Item { item = h Text}
    • Item Identity, Item Maybe : Maybe の有無を共通化
    • Item (Const Text) : すべて文字列。CSVから読んだときなど
    • Item ((-> Value) : Value型からの関数をまとめる
    • カスタマイズ性が高まる
  • 構造を共通化すると、共通の操作が定義できる
  • babies パッケージ
    • instance FunctorB Item などが定義されており、 Generics で自動導出
    • bmap buniq bzipWith btraverse
  • fill :: ProductB t => t Identity -> t Maybe -> t Identity
    • Nothing 以外のフィールドを埋める関数
  • display 表示用の関数
  • HKD によるジェネリックプログラミングであれば、目的にあった型に変換できる
    • 爆アド : 爆発的なアドバンテージ
  • extensible
    • より短く書ける
    • APIがたくさん定義されている (末永くメンテしてきたので)
    • JSON のデシリアライズもできる (aeson より短く実現できる)
  • extensiblebabies の違い
    • extensible は標準の仕組みではないので自由度が高い
    • babies は標準仕様なので、言語のエコシステムから様々なサポートが得られる
    • extensibleインスタンスが予め用意されているもの
    • babies は標準なのでどんな型でも良い
    • extensible はレコードの追加削除が容易、重複も可能
  • TangleT の例
    • 体重と身長から BMI を出す例
    • 標準入力から体重、身長のフィールドの値を得て、BMIフィールドに hitch 関数で参照する例
    • 依存関係は自動で解決され、必要なフィールドだけユーザに聞かれる
  • 問題点
    • HKD は Generic1 のインスタンスにできるが、 GHC8.8 ではまだ自動導出無理
    • babies はコンパイル時間がやたら増大しがち ( extensible も )
  • これはもはやただの関数型プログラミングではない : Beyond Functional Programing
  • Q). レコードに HKD のパラメータを入れたが、なぜ Identity が必要? Functor とは関係ある? type エリアスではだめ?
    • A). Functor ではない。 type エリアスでは引数をすべて指定しなければならないので NG
  • Q). このスライドの h のカインドが Type -> Type 。複数の Type パラメータを受けるようにできる
    • A). できる。 Arrow を受けて name :: h String Int みたいな
  • Q). プロダクションで使っている?
    • A). 最近使い始めている。 Tangle はかなり前から
  • Q). GHC の Trees that Grow との違いは?
    • A). 独立した概念。両方を組み合わせることも
  • Q). HKD を使うと制約を使って fold する場合に constraint を必要なときに型ハックが必要で辛い
    • A). type application @Show など必要。面倒になるのは否めない。 extensible では成約と成約の組み合わせを扱うために And class などを用意して回避しようとしている
  • Q). And は何でも使える?
    • A). はい
  • おまけ: OpenGL のライブラリでも HKD を使っている
    • シェーダーに渡す型を、自動導出してコードを省略できる

「しんさんきぼう」GHCのderivingテクノロジー

  • 神算鬼謀 : GHC の deriving 機能がすごくなっている
  • deriving に三種類ある
  • Haskellの標準では、特定の型クラスについて、自動で関数適語を生やしてくれる
    • 特定の型クラスのみ
  • GHC拡張の deriving は3つ
    • GeneralizedNewtypeDeriving
    • DeriveAnyClass
    • DeriveVia
  • GeneralizedNewtypeDeriving (GND)
    • newtype 元の型クラスを newtype 先でも使う
    • newtype の元のインスタンスと同じ挙動をする
    • 自作モナドを作るときに便利
  • 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 、オーバーライドなら newtypevia
  • 「これが newtype の力だ、見たか!」
  • Q). どういう型を使うときに使える?
    • A). 使ったことはないです!
    • A). 「DerivingVia をお使いの方は?」「JSONインスタンスを作るときに、プレフィクスを消せる」

Haskell メタプログラミングによるEgisonのパターンマッチの実装

  • MiniEgison : 2010 年から使っている Egison の機能を GHC へ移植
    • いくつかのGHC拡張を使っている
  • MiniEgisonとは
    • matchAll すべてのパターンマッチの結果を返す
    • matcher パターンの解釈の方法を定義
      • List リストとしてマッチ 、 Multiset 順不同としてマッチ
  • non-linear pattern matching : $x で束縛した値を #(x + 1) で利用
    • バックトラックで効率良く動く
  • infinitely many pattern-matching
  • matchmatchAllhead
  • Egisonのパターンマッチを利用して map concat uniq を実装できる
    • intersect difference も実装できる
    • Davis-Putnam Algorithm を実装する例
    • 数学的なアルゴリズムを簡単に記述できる表現力がある
  • ループは二種類ある
    • 探索範囲を狭めるループと、バックトラックを含む再帰
    • 後者をEgison pattern matchingへ隠せる
    • パターンマッチ指向プログラミング
  • 実装のため型システムを考える必要がある
    • この型システムをGHCに落とし込む
  • class Matcher m a ma のマッチャーという関係
  • 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 は二重数のこと
  • xy偏微分していくときに diffD は問題がある
    • dx と dy の区別のために適切に lift をする必要がある
  • 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 aAD s a みたいなもの
    • Tape Wengert List。式の組み立てを記録する
    • reverse mode は stateful となるため、 unsafePerformIO を使うことになる
  • Reverse mode を圏論から考える論文もある。まだ研究中の分野
  • Q). forward のほうが効率がいい問題は?
    • A). ぱっと思いつかない。 forward mode はきれいなので説明に使われる
  • Q). State モナドじゃなくて unsafe なのは?
    • A). 演算子のオーバロードで実際したいので。複雑な式は使いまわしたいが、 List で作ると表現しにくい
  • Q). ST モナドと同じ使い方なのに、なぜ unsafeIO
    • A). 外側に ST が出てきてしまう。内部では ST で評価している
  • Q). 二重数のうんちくは?
    • A). なぜ微分と対応するのか。テイラー展開の2乗以降を無視するということに対応している
  • Q). 整数 1 を渡せるのは Num Float 型クラスを受け取れるから?
    • A). はい

GHCJS + Miso で作る Web フロントエンド / チェシャ猫さん

  • フロントエンド書いている人 → 多い → Haskell に比べるとメジャーですから
  • サンプル htps://hakelda219.wb.a*p (公開禁止)
  • Miso はサーバサイドレンダリングができるが、その話はしない
  • GHCJS
    • GHC のフォーク
    • Haskellのライブラリが(ほぼ)そのまま使える
  • Miso (ロゴは味噌ラーメン)
    • GHCJS で Elm Architecture を実装したもの
    • 類似品は Reflex など
  • putStrLenconsole.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
  • 問題例「 users4.csv が push できない。 push せよ」
  • 旧構成
    • webhook -> Ruby/Sinatra -> Jenkins -> TypeScript (on Heroku) -> Slackにメッセージ
  • なぜ書き換えたか
    • メンテナンスがきつくなってきた
    • Jenkins plugin が古すぎ
    • スコアボードを作った人は退職
    • 8割が趣味
  • 作り直すならHaskell
  • Jenkins が嫌だった。 DroneCIに (go製)
  • GitHub Webhook -> Haskell / Servant -> DroneCI -> Haskell + Elm
    • DroneCIはリポジトリにテストファイルを置くが、参加者に見せたくないのでリポジトリを2つ用意
    • git-plantation
      • OSS にした(OSSにすれば、俺がやめても俺がやる)
  • アプリ
    • app, store, tool, slack の 4 アプリ
  • 依存パッケージ
    • rio, extensible, mix.hs, shelly(スレッドセーフ。 servantのため), servant, elmap.hs, github, drone, req, wreq, lenz
  • 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 インテグレーションは残っている
  • 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
    • Sanity: 境界条件の処理がまだなら Yet 、済んでいれば Done
    • 処理済ではないもの Yet だけ Num インスンタンスに
    • 幽霊型で共通化することで、一回の実装で済む
  • GHC(k + 1) - 1 = k であることがわからない
    • ghc-typelits-natnormalise 型チェッカーの差替
    • 人にとって自明な制約をGHCがわからないので型検査機のプラグインで使う
    • シングルトンパッケージは使わないように頑張っている
  • モナドで仕事を分けている」というツイートがあったが、本当か
  • Tagless-Final Style
    • 細かい情報はモナド m にすべて押し付ける
    • 興味のあるオペレーションを取り出して結果をモナディックにしたもの
  • Reader, ReaderT env IO
    • RIO pattern は有用である
    • DerivingVia で実装の詳細を共有する
  • =<< などは Lisper のかっこと同じだが、普通の人には難しい
    • GADT でスマートコンストラクタを実装
    • freeモナドで書いたもの
  • 部屋の温度を扱う場合に 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 を使うのがいい
    • カスタムライブラリを使いたい
  • カスタムライブラリを作った理由
    • 高速アクセス、依存性が少ない、ラベルが多態(ラベルを型にしたい)、 HKD 的なオペレーション
    • GHC プラグインを作った。型レベルプラグインの簡素化や記法の単純化
  • 「人間は忘れるので型に覚えてもらって下さい」
    • ゆくゆくはリリースしたい

Cadenza: Building fast functional languages (on the JVM) / Edward Kmett さん

  • 速い関数型言語が欲しい
  • いろんな言語が GraalVM で動かせる
  • ライブコーディング
    • ラムダ計算の実装
    • ValueClosuure のみ
    • 完成版があった
    • uneval の実装
    • 完成版その2
    • uneval . eval で正規化
    • Bool Nat の追加
  • 今後の展望
    • Dependent Types にするか、 GHC Core にするか
    • 後者は GHC のコードを多く再利用できる
  • Q). なぜ eval するか
    • A). eval は速いから。特に依存型について
  • Q). Kotlin は?

LT

Haskell で 3D モデルに触れる / as_capabl さん

  • 3D のファイルフォーマット
  • glTF
    • JSONとbinary / JSON が読めれば良い
    • aeson は便利だが、型が30、メンバーが200。手では多すぎる。
    • JSON Schema から自動生成すればいい
      • aeson-schema hjsonschema
      • どっちもだめ
  • CONJCT
    • CONfigurable Json sChema Translator
    • type generation に注力
  • holzgl の両方を併用
    • 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 さん

  • Nummul を考える
  • 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の型クラスには破壊的な変更が加わる
    • Monad, Applicative, Functor, MonadFail, Semigroup Monad
  • 破壊的変更はきつい
  • 抽象型クラス : メソッドが公開されていない
    • KnownNat : natSing は見えない
  • 抽象型クラスだと、実装を変えても何も起きない
    • 実際 KnownNat は Integer から Natural に変わっている
  • 例えば Monad を抽象にするには、 return などを普通の関数にする
  • 三者インスタンスを作れなくなる
    • DrivingVia などを使う必要がある
  • クラス階層を変えても、破壊的変更を避けられる
  • (そのうちブログに書くのでお楽しみに)

GHCGC / kazu_yamamotoさん

  • Servant でも Warp などは使っているので、熊本の方は東京に足を向けて寝ないで!
  • 「世代別並列コピーGC」 から 「並列コピーGC と 並行マーク&スイープGC 」に変わる
  • コピーGC は生きているオブジェクトを他方へコピーする方式
  • マーク&スイープ方式
    • オブジェクトをすべて見て、要らないものを捨てる
    • GCが遅く領域が断片化。領域を探すのが遅い
  • 並列の実現
    • サイズごとに領域がたくさんある
  • 新世代と旧世代に分類
    • 3回生き残ると旧世代に移す
    • 世代別仮説 : 旧世代のGCは少なくていい
  • 旧世代のGCは領域が無限に大きくなる。遅い
  • GC をするときに GHC はプログラムを止める
  • (時間切れ)椅子をGCしましょう

今日は YAPC::Nagoya::Tiny 2019 の日です

来ましたので、自分用のメモを残しておきます。

開会の挨拶

  • 名古屋から来た人、東海から来た人
  • ランチはルーセントタワーB1が穴場
  • Tiny とは?
    • 新たなコミュニティの形成。
    • 小規模で開催しやすい
    • メインはトーク
  • ハッシュタグ: #yapcjapan
  • フロア貸切ではないので注意

Perlでもできる! PerlウェブサービスにDocker, ECS, CDKを導入してよかったこと、大変だったこと / Windymeltさん

  • Perlアプリケーションの環境構築は大変
    • plenv, MySQL Redice, Imagemagic, bzip2 などなど
    • デザイナーさんやプランナーさん
  • Docker-compose の導入
  • 開発環境 = ミドルウェア、ソフトウェア実行環境、ソースコード
  • ミドルウェアは Docker-compose で切り出す
  • 実行環境は Docker image として切り出し
  • ソースコードを同梱すると、頻繁な作り直しが発生
    • ホストに置く
  • ミドルウェア、実行環境はホストやブランチをまたがってもだいたい一緒
  • 開発環境の管理が容易
  • Dockerfile で CI にも持ち込めるが
    • キャッシュがなくて20-30分待たされる問題
  • AWS ECR: Elastic Container Registory
  • DockerイメージをAWSにおけて便利
    • 素朴に1つのイメージを共有するとブランチ間で競合
    • どうタグつけるか
  • 実行環境は Dockerfile と cpnafile.snapshot に依存
    • cat でつけて md5 の先頭7文字をとって tag にする
    • docker-compose のラッパを作って、 tag に該当するものがECRにあるかを見て、なければpush
  • 30秒くらいで簡単に環境構築できるようになった
    • 問題が次々発覚したのは大変だった
  • 動作検証用の環境
    • マージ前に見れる環境が欲しい(ステージングではなく)
    • 環境を作るのはSREの力が必要で大変
  • AWS ECS
    • king of docker-compose
    • だいたい死なない
  • ソースコードなしの Docker イメージでは動かせない
    • AWS Code build を利用
    • Makeみたいなやつ
    • 特定のブランチ名についてhookを動かしてビルド
  • ECSで検証時にブランチごとにサブドメインを切りたい
    • 共用ALBを立てて、ブランチの数だけリスナルールを生成
  • 本番っぽいDBが欲しい
    • RDSを立てて本番DBのスナップショットを入れた
  • SREの助けを借りずに環境構築ができるようになった
  • タスク定義、サービス定義、ALBリスナールール → 目でrsyncが必要
    • CDKの導入
    • TypeScript でAWS リソースを記述
  • スタックの作製
    • 基盤部分とブランチ部分を分ける
    • スタック同士の依存関係を表現 → 壊れない
    • ブランチごとに別スタック → CDKのコンテキスト機能
      • ブランチ名がわかればイメージ名が分かる。
  • 自動化されたが、CDKに慣れる必要があった
    • まだない機能があったり
    • issue を作ると作ってもらえるかも
    1. CDK使うと暗黙的にリソースが?
      1. アウトバウンドが開放されたり、勝手に権限を与えてしまったりが、デプロイ時に聞かれる
    1. IAM の設定が煩雑になりがち。工夫は?
      1. クラスタやコンテナを作るときはTyeScriptのスタイル。型レベルで作るべきものはわかる。一つのファイルに固められるので煩雑さはマシ

Rust に入門したくて!libperl を bindgen して Perl の ASTを舐め始めた話 / hkobaさん

  • FFIでRustを学ぶ
  • 今日話さないこと: Rust
  • おっさんPerlプログラマーの悩み
    • 作ったライブラリが言語ごと流行から外れて負債呼ばわり
    • 既存の資産の総書き直し?
  • Perlの限界
    • 静的な型検査
    • fields で静的に見てもらうこともできる
    • 定義時点や関数渡しの部分のチェックが甘い
    • 内部APIPerlのASTを読むことは可能
    • だが、Perlは弱いママ
  • 近代的な言語でやればいい
    • Rust: GCを押し付けないため、GCの競合がない
  • 実践Rust入門という日本語の本が出た
    • 仕様が安定したのでは
  • チュートリアル: The bookのGetting Started と Programming a Guessing Game
    • perl_parse() を呼ぶのが目標
    • 書籍の FFI の章
  • perl_parse() スクリプトコンパイルを済ませる
    • perl_construct, perl_parse, perl_run の順で呼ぶ
    • perl -c と同じ効果
  • PerlInterpreter には Opaque と からの列挙型を利用
  • std::ffi::CString C文字列
  • 呼べた → segv
    • gdb を使って普通にデバグできそう
    • 普通のC言語と同じ!
    • lifetime のミスでdangling pointer
    • unsafe ばかりだが動く
  • bindgen とは
  • EXTERN.hperl.h から生成
    • 1.5MB
  • エラーが出るが、 redefined
    • 定数定義が本当に二回されていたので、手で削るとビルドは通る
    • unsafe の嵐だが動く
  • perl crate がすでにあったが、 Perl から Rust を呼ぶもの
    • 被らないので、 libperl-sys libperl-rs にした
  • ビルド: Config.pm から libperl のビルドオプションを取得して rust 用にする
  • まとめ
    • FFIからRust入門するのはあり(よく知っているライブラリがあれば)
    • bindgen は期待できそう
    • gdb使えるのはよい
    1. RustでPerlを書いて下さい
      1. もしかしたらそういう未来はあるかも。そのための足がかりの仕事

(my$name="Perl 6")~~s/Perl\s*6/Raku/; / Dan Kogaiさん

  • 司会「なんて読むんでしょうかね」
    • 読めないけど実行できるタイトルで
    • Raku が必要 (Perl5ではだめ)
  • YAPCではなくYARC(やらしー)になるのでは
  • @TimToady 「Perl 6 と呼ぶのをやめよう」
    • 別の言語なのに同じ名前なのでお互いに足を引っ張っている
    • 今後は Raku となる
  • URLもraku.orgになっている
  • Perl5 は perl と読んでいい
  • Raku の道は楽なのか?
  • やぷしぃとやらしぃは分かれる?
    • お互いにPerl仲間というのは続いているようだ
    • やらしぃはこの規模なら成立するかも
  • ラクダは楽だがRakuは落下?
    • 昔より、URLを変えるのは大変である
    • 例: itojun さん。本名は変えられたがネットの名前は変えられない
    • 例: JavaScriptJavaとの確執でEcmaScriptと呼ぶべきだが
  • Perl6は -Ofun 、 Python3は -Ofuture
    • BFDLはリタイヤしたが、Python2はリタイヤしていない
    • Perl4からPerl5 -Omodern はうまく移行した
    • jcode.pl Jcode.pm Encode.pm もうまく移行した
  • Perl4 と Perl5 よりも、当時の Perl5 と今の Perl5 のほうが中身が違う
    • 名前が一致するのに相応しいほどの後方互換性があったからうまくいった
  • Swift -Ocurrent
    • メジャー番号が変わると互換性がない
    • 稀有な成功例。Appleがリソースを突っ込んだから
    • 互換性を気にしなくていい程度の使われ具合だった
  • 人間個人の名前も変えにくくなった
    • 名前は自分だけのものではなく社会的なものに。ポインタ化。
    • s/Autrijus/Audrey/ Pugs を実装した頃に名前を変えていた
  • Perl 6 は Perl における一番の失敗ではないか
    • Perl 5 もいつまで経っても未来が来ない、と思われてしまう
  • Raku はできて19年。新しい・・・?
    • Perlへのコミュニティに、貢献してきたはず
    • 古いものと見なされるのは残念
  • Rakuになるのはラクじゃない
    1. CPAN の P は変わるの?
      1. 今は github から引っ張ってくる時代。別の機会に考察したい。
      1. (PAUSEでアップデートすることになっているが、どうなるのか)

Makefile生活 / azumakuniyukiさん

  • Makefile とは
    • make コマンド実行時に読まれる
    • BSDでは gmake を使って
    • GNUmakefile makefile Makefile の順で探しに来る
    • 処理をターゲットでグループ化
    • 行志向のシェルスクリプト、古来からある
  • make make all make install make clean make test make world とかよく使う
  • コマンド履歴の20% make
  • 実行すると画面いっぱいに大量の何かが流れていく
  • perl-5.30.0 の GNUmakefile は 14,153 行
    • automake の結果
  • 深入りすると危ない。沼。極めないほうがいい。浅瀬について話す
  • CPANM = http://cpanmin.us マクロ
  • cpanm: ターゲット名
  • コマンドは TAB から始める
  • install: cpanm 疑似ターゲット: 依存名
  • Makefile をタスクランナーとして使う
    • リポジトリ、設定ファイル置き場、Ansible Playbook置き場、に置く
    • 複雑なことには向いてない。単一のコマンド、実行順が決まっている
  • make fix-commit-message make push make cancel-the-latest-commit make remove-added-file などを用意して使っている
    • zsh の補完が効くので、覚えなくて良い
  • make restart
    • postfix の restart 。文法がおかしいとエラーで止まるようにする
  • make test-conn-with-starttls
    • smtpのテストをするための
  • エリアスとして使っている
  • make deploy-public-key SSHREMOTEHOST=... ... に鍵を設置
  • make check-wordy
    • Perl Hackers Hub で決まっている禁則文字の処理
  • make すると git status するようになっている
  • test check clean などは共通のターゲット名とする
    • 共通の名前にしておくと戸惑うことがない
  • ホームディレクトリで make clean すると古いスクリーンショットが消える
  • Omake (おまけ)
  • -n ドライラン、 -f ファイル名、 マクロの上書き、 @ コマンド非表示、 - エラー無視

10年でどう変わった? はてなブックマークでのPerlの使い方 / 伊奈 林太郎さん ( @oarat さん)

  • はてなブックマーク
    • 2005 年リリース
    • 2008 年リライト
    • 2013 年デザインリニューアル
    • 2015 年フルリライト
    • 2019 年完了
    • Scala で書き直したが、Perlも使っている
  • 旧システム構成では、他のサービスも一緒に1つのコードベースに
    • .pm 400,000行, .t 270,000, html 70,000, gitmodules 30+
    • パフォーマンス上の問題(影響範囲が大きすぎて直せない)
    • サーバコストの増大
    • 書き直しコストは(うまくいって3年→書き直せるね)
  • 新システム構成ではマイクロサービス化
  • 250ms で返せた割合 4割から9割に改善
    • サーバ台数は半減
    • リリースサイクルは週から日へ
    • 仕様の整理
  • 困ってたところをどう解決したか100連発(無理なので一部)
  • 巨大なモノリス。単一言語
  • マイクロサービス化
    • HTTPでJSONをやり取り
    • 境界づけられたコンテキストで分ける、再利用性、言語の違い、リリースサイクル
  • 言語選択 Scala, Perl, Go, Python
  • バックエンドは Perl
    • ドメインモデルの表現
    • 更新頻度が低い部分
  • Perl
    • ビュー、デザイナも触る
  • Go
    • 非同期処理。小さく作る
  • Python
  • ジョブキュー
    • TheShwartz + WorkerManager だった
    • 重いジョブにリソースを専有される → キューが詰まる
    • Scala で使えない
    • 環境が壊れがち、動作確認が大変
  • Fireworq (Go) を開発
    • キューに専念する。複数キューを定義(思いジョブの隔離)
    • 同時接続のワーカ数を動的に変更可
    • ワーカはHTTPバックエンドとした
    • 2014年に作ったもの - ブックマークの作り直しのために先んじて作った
  • トランザクション
  • DDD
    • ファットモデル、ファットコントローラ(?)
    • アプリケーション層の役割がちぐはぐだった
    • アプリケーション層について議論、指針をドキュメント化
    • Perlはビューモデルの層なので大雑把
  • ファットモデル
    • 5,000行弱のエンティティ。副作用があらゆるところで起こる
    • 不変というルールにした
    • Perlでは Class::Accessor::Lite 。 Class::Mix で動的継承
  • Class::Mix
    • DOに動的にフィールドを追加する
    • clone_with で多重継承させる
  • 文化を継承する
  • 厚いフレームワークからの脱却
    • Ridge, DBIx::MoCo (RoRリスペクトの重いもの)
    • ブックマークチームしか使っていない
    • フレームワークから逸脱した利用が増加
  • Ridgeの辛いところ
    • 暗黙のディスパッチルール
    • URIとメソッドの対応が不明
    • ルールも複雑
    • before_filter after_filter 変なところにロジックが書かれて追えない
    • ほとんどが Ridge を継承
    • Plack + Router::Simple で書き換え
  • DBIx::MoCo
    • 変更操作を最後に書き出すものだが、 ->save で即時書き出し
    • キャッシュがあるのに、キャッシュを回避しがち
    • トリガで色々やり過ぎ
    • N+1 クエリ
    • 生クエリを書きがち
    • DBIx::Handler + Scope::Container
    • has-a 関係は複数件一度に引くメソッドだけを作る
  • Perlのバージョン
    • 5.8 だった。 CentOS 5 、 mod_perlyum (CPANモジュール)
    • Plack化、cpanfile化、Docker化は失敗していた
    • 5.2x に書き換えた・・・すべてが輝いて見える
  • モジュールの動的ロードはしない
  • デッドコードは今すぐ消す
  • Elasticsearch のバージョンを上げられない(フィールド名が変わる)
    • 壊れてもわかりにくい。Scalaだと型付きなので安心
  • Twitterの文字数制限
    • Perlで再現するのは難しい
    • Scala なので Javaの公式パッケージならO.K.
  • プロジェクトの進め方
    • PoC、社内リリース、本番リリース、プロジェクト収束
  • PoC レビュー
    • CTO、チーフエンジニア、インフラ部長、旧システム識者
    • 捨てる仮実装 (捨てなかったけど)
  • 社内リリース
    • 社内URLをブックマークして利用
  • 本番リリース
    • 面の単位で新システムに切り替え(参照系から)
    • 面ごとに必要なデータをオンライン同期(5~10回)
  • プロジェクトの収束
    • 残っていた API、非同期処理、更新系
    • 使っているリソースに依存しているサービスを全回収
    • 2~3ヶ月かけてすべてのコードを読んで洗い出し
    • やることの総量は決まっていたので、ウォーターフォール的に進んだ
  • レガシーコードの考古学は気合い
    1. Class::Mixでtrait。 *::Role はどうして使わない?
      1. Class::Accessor::Lite しか使ってないので。 is_a とくっつけないと呼べない、の最小階
    1. canonical URLには対応している? Twitterは? 一番うざい点なんだけど
      1. Twitterが悪い。ガツンと言いたい。検討します
    1. DDDの学習コストは高いが、最初はどうした
      1. プロダクトコードに苦しめられたおっさんには教えやすい。新卒には厳しい。

他言語ユーザから見たPerlのおもしろさ / うたがわききさん

  • Python3 を書いてた
    • Python2 を無視することで乗り越えてきた
  • プログラミング言語、それを構成するものには色々ある
  • 単一の言語ではなく、比べることで見えてくるもの
  • my $x Pythonにはなく、Perlでは静的解析されてるのすごい
  • コンテキストは Perl 特有のもの
    • $x = @arr ($x) = @arr wantarray
  • %hash@arr が互換なのが不思議
  • 関数の引数 shift $_[0] @_ args とかあってむずい
    • Smart::Args 使うしか」
  • ( (1, 2), (3, 4) ) と書けない
    • [ [1, 2], [3, 4] ] ならいい
    • これは Python でも
  • package がクラス名
  • CPAN名前空間
    • 名前空間の文化は良い
    • Acme はよい(ジョークであることがわかりやすい)
  • Try::Tiny
    • try catch って関数があるだけ。モダンな言語機能も手作り
  • Scope::Guard
    • Go でいう defer
    • $guard っていう変数は何・・・? → デストラク
    • GC のついでによしなにモダン機能ができる
  • VSCodePerl
  • package 宣言を自動にしてほしい
    • Perl insert package を書いた
    • package 名と use の補完

40分で学ぶPerl入門 / 木本裕紀さん

  • 右キーが効かないトラブル
  • 正規表現の使い所
  • find * | grep -P '(\.pm|\.pl)'
  • perl -pi -e 's/shimeji/enoki/'
    • すきやきでしめじと間違えてえのきを買ってきたとき
    • git reset --hard があれば戻れるので
    • .bak を用意して、 .bak を戻す。 git 使っている方が現代人ぽい?怖くない?」
    • remote には全部残っている
    • いろいろあります
  • HTMLの aタグ の href を置換するライブコーディング
    • danさん、間違っていたら教えて下さい
    • やっつけ仕事には正規表現はいい
    • 「すべてが UTF-8 で完結していれば、 Encode は使わなくていいはず」
  • オブジェクト指向
    • スクリプトをベタ書きするときは使わない
    • 機能を分割して提供したい場合 (CPANモジュールとして使ってもらいたい)
    • OOPのほうがユーザには使ってもらいやすい
    • オプションの指定をコンストラクタでできる
  • Perlオブジェクト指向
    • 他の言語と違って構文がない
    • データと名前空間を結びつけたもの
    • リファレンスと bless だけあればいい
  • ライブコーディング
    • bless を使う例
    • 今度は一回で出ました
    • new
    • でたー!!(発表終了)

Perlにおける動的なモジュールロードのメリットとデメリットについて / ybrliiu さん

  • TMTOWTDI が好き
    • OOPの実現方法がいろいろある
    • Perl のコアにOOPが入ったりするのは楽しみ
  • 動的なモジュールロードが辛い理由を明文化したい
  • アイテム効果クラス
    • 静的はめんどくさいから動的にロードさせるようにした
    • grep してもアイテム効果クラスの場所が見つからない
  • 動的なモジュールロードは柔軟性がありすぎる。保守性が下がる
    • 動的なモジュールロードが必要なときは保守性が下がらないよう
  • 静的なモジュールロード
  • 動的なモジュール
    • Module::Loadなどを使う
    • import は自動的に呼ばれない
    • CHECK INIT はスキップされる
  • 動的なモジュールロードのメリット
    • クラス名をまとめてコードを短くしたり
    • Module::Find
    • Catalyst 風 → use しなくても使える、パッケージ名が短くなる
    • プラガブルなモジュールを作れる
    • 動的ディスパッチ
    • 起動にかかる時間の短縮 (利用時までロードを遅らせる)
    • 相互依存の解決
  • デメリット
    • モジュール名を組み立てると greppability が低下
      • 静的ツール解析にも厳しい
    • ロードタイミングがわからないため、混沌とした依存関係が生まれる
    • 依存関係がわかりにくい、循環依存が見つけにくい
    • 依存しているモジュールが壊れていてもわからない
      • all_uase_ok とかで全モジュールをロードはできる
  • なるべく静的にモジュールをロードしたい
  • パッケージ名が長すぎる問題
  • use 忘れを防ぐ方法の代替案は不明
    • IDEが先頭に入れてほしい
  • まとめてロードするのは動的にロードするしかない
    • 設計が間違えている可能性がある
    • 動的ロードするなら all_uses_ok は必要
  • プラグイン機構
    • 外部で use したプラガブルなオブジェクトを投げ込むとか
  • 動的ディスパッチ
    • 事前ロードして対応表を作る
  • 起動時間の改善は動的ロードするしかない
    • 保守性と犠牲になるのでよく考える
  • 依存関係を動的に解決
    • if プラグマで選択的にロードできる
    • 循環参照は治す
    1. 動的ロードのまま直せなかったことは?
      1. 現在やり始めたのでまだ不明。いずれ話せるかも

似ているけどちょっと違うものたちをモデリングする技術 / hitode909 さん

  • 似ているけどちょっと違うものとは
  • 漫画サイトが9サイト目
    • 見せ方(週毎の更新か、など)
    • ビューアー(オフライン機能、定期購読機能)
    • ほか、管理画面、漫画の取り込み機能(エピソードだけ?価格も?)など
    • 同じ要件もあるが違う要件もある
  • コードベースは共通
    • Hostヘッダで
    • Perlで開発
    • 全サイトにデプロイされる。どこかが壊れれば壊れる
  • DBも共通
    • media_id
  • redisも共通
    • キーは1つのクラスに押し込み
  • 却下したこと
    • ビューワ、マイクロサービスごと
    • 別のDB / マイグレーションのタイミングがむずい
    • Hostヘッダでmedia id をわける
  • コードベースが線形に増えないようにする
    • 10サイト増えてコードが10倍になってはいけない
  • 列挙は避けてルールベースで共通化
    • 例: メディア名をもとに、URLを機械的に決める(列挙しない)
  • 値置き場は定義ファイルに追い出す
    • YAMLファイルに追い出している
  • ネームスペースの工夫
    • 特定のメディアの場合はメディア名をクラス名に入れる
    • 共通のものはメディア名を入れない
  • 機能に着目したネームスペース
    • Media が Feature を持つ
    • Core: 共通概念、 Feature: メディアごと
    • Giga::Feature に様々な機能を置く
  • 5サイト目まで作ったところで
    • どのメディアがどのフィーチャーを持つかを知るクラスを作成
    • 宣言的に定義
    • has_feature 特定のページに物を出すか出さないか
    • before_filter で処理を共通化
    • HasFeature フィーチャーがきちんと実装されているかをチェック
    • wip_feature_toggle 1リクエストでだけフィーチャーを有効化(デバグ用途)
  • Scrapboxにドキュメントをどんどん書く
    • 設計パターンをどんどん書く
    • 書籍を参考に
  • コンテキストマップをみんなで書く
    • 認識がずれたときに利用
  • 困ったこと
    • 通化によるSQLの非効率
    • ボトルネックはどこになるのかはっきりしない
    • チームの舵取りが難しくなってきた
  • アプリケーションの要件に合わせた構造を作る。日々認識を合わせる。素朴だけでなくときには複雑なこともする
  • Google Jamboard は大きすぎるので注意
    1. メディアを取り違えたことは?
      1. ない
    1. はてブとは方針違う?
      1. コードの特性などが違うので。コードは難しいので共有している
    1. 依存が複雑になる。どう対処する?
      1. フィーチャーをパックにしてまとめて扱うと単純化されるのでは
    1. フィーチャーは Role ではないか?
      1. フィーチャーはオブジェクトではない。素朴なパッケージなので互いに鑑賞しにくくしたかった。一つのクラスにしたくはなかった
      1. Role は衝突回避なので使えるのでは
      1. 必要になったら議論していきます

らくらくPerl6入門 / 八雲アナグラさん

  • Rakuとは?
    • 僕が3歳のときに生まれた新しい(?)言語
    • rakulang

    • Perl5との互換性はない
    • 仕様と実装の区別
  • 名前の案
    • 6lang, Camelia
    • ダミアン先生が raku を提案
    • 箱根の焼き肉温泉rakuでハッカソンをすると盛り上がりそう
  • 歴史
    • Pugs
    • Parrot 初めてVM (開発停止)
    • Rakudo
  • Rakudo
    • Rakudo, NQP(Not Quite Perl。サブセット), VM
    • VM は MoarVM, JVM
  • Raku は 仕様の名前。 Rakudo が実装
  • NQP
    • Rakudo 開発者向け。プログラミングをしてはいけない
  • MoarVM
  • raku のダウンロード
    • rakudo-star
    • 6pad ブラウザで動く
    • ソースまるごと欲しい場合は perl6/z
  • Comma IDE 120ユーロ/年だが、無料も可能
  • Rakuの本
    • 海外では出ているが、昔の本では動かないかも
  • perl6 コマンドでインタプリタが起動
  • perl6 は分かれる
  • 拡張子 .pl を使うなら use v6 すること
    • 拡張子 .raku .rakumod .rakudoc .rakutest
    • Perl6 Modules からモジュールの検索が可能
  • raku のドキュメントは?
    • 公式ドキュメントを利用
    • 書籍はフローチャートを利用
    • ブログは妄想が書いてあることもあるから注意
    • Roast (テストシート)
    • IRCで問い合わせるのも良い (Alexander さんにツイッターで聞くのも)
    • Haskell To Raku とかもある
  • Rakuの遅さ
    • 速くはなってきている
    • Ruby Perl5 Python より早いケースも有る
    • 起動は遅い
  • シジルを使う
    • $ @ %
    • 変数のコンテナの種類を示す指示詞
      • コンテナを経由するので
    • @array_test[0] %hoge{"foo"} シジルは変わらない
  • . を使える
    • Mu (無) を継承している
  • デフォルト値
    • Nil を代入した途端にデフォルト値に戻る
  • %% 割り切れるか
  • ジャンクション 4 & 6
    • リストの中身をjunction にすると一度に処理可能
    • ? bool をとる、 ! 反対にする
  • 日本語に対応している 「」 が利用可能
  • sub でサブルーチンを定義
    • サブルーチンシグネチャがデフォルト sub add ($left, $right)
    • デフォルト値 sub add ($left $right = 1)
    • 名前付き引数 sub bmi(:$height, :$weight)
    • 書き換え可能な変数 sub setZero($n is raw) (ただしリテラルはだめ)
  • 引数の型指定 Int コンパイルタイム
  • @_ は厳しい
    • @_.shift と書かないと
  • class でクラス定義
    • === eqv
  • Twigil : public な API. 、プライベート !
  • NativeCall
    • 共有ライブラリを実行時に呼び出す
    • C の randfalk を呼び出す例
    • ライブラリなら呼び出せるので Go も呼べる
  • RakuのWAF
    • Crust, Bailador, Hematite, Cro
    • Cro がおすすめ。EDUMENTが商用サポート
    • CroでLDAPの実装
  • cro コマンド
    • cro stub http hello hello http で hello というモジュールを hello ディレクトリへ
    • Cro::HTTP::Router ルーチン具
    • Dockerfile の自動生成
  • Red
    1. Raku のセールスポイントは
    2. grammer や regex
    1. is_raw のエラーは静的?
      1. 試します。・・・実行時です。perl6 -c だと syntax ok
    1. Raku は末尾に 1; は?
      1. いりません

LT

LTに出ていたので、メモはなしです。

クロージング

  • YAPCは現地の人の協力が多大に必要
    • 開催地が限られる
    • 小さく開催
  • 参加者 48 , トーク 10 スポンサー 5,
  • 次回は京都 2020-03-27, 28
  • お疲れさまでした!

A Regular Expression Matcher in Rust

ということで、ソースコードが書かれている記事を見つけた。

https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html

Rust で書き直したものを文末に貼っておく。 rstfmtif 文を改行してくれるせいで行数が膨らんでCの実装より数行長いが、ほぼ同じ感覚で書ける。 do while はないので、 for と添字を使って書き直した 1 。こういうときには配列スライスの使い勝手がとてもよい。

後、書き直していて気がついたのだが、この実装は C 文字列の末端が "\0" となっていることをうまく使っていて、そのお陰で空文字列でも気にせず 0 要素目にアクセスできている。 Rust だとそうはいかないので、 get(0) して match したりする必要がある。逆に Rust ではパターンマッチでリテラルが使えるので、 if let を用いて Some(&b'^') に直接マッチできる。


  1. loop { ... if !condition { break; } } が等価なのだけど、行数を食うので嫌った。

今日は Regex Festa の日です

今日は Regex Festa の日です

Regex Festa に来ていますので、自分のためのメモを残しておきます。

挨拶

  • wi-fiとお手洗い、喫煙所の案内
  • Opt Technologies さんについて
  • QRコード読むとアンケートあります

いろいろな正規表現、いろいろなオートマトン / @sinya8282 さん

  • 正規表現は好きだが、難しい面も面白い面もある
    • 学部の頃は世界最速のgrepを書いてたりした
    • 院では学術よりな研究
  • Shibuya.pm#16 が正規表現オンリーなイベントだった
    • 東京素晴らしい!
    • 8年の時を経て復活
  • 正規言語の魅力
  • 正規表現は難しい
  • /(\D+|<\d+>)*[!?]/ pcrepattern のマニュアルに出ている
    • VM型の正規表現と相性が悪い( * の中に + があるから)
    • pcregrep"a" x 23 をマッチさせると、失敗する
    • リソース不足になる (21世紀なのに23文字がだめなの・・・)
    • atomic group (?> ... ) を使うと解決
      • バックトラックを抑制する
      • 共通してマッチしない表現の和だと、使えるテクニック
  • (a?){22}a{22} 長さ22から44までの a の列にマッチ
    • pcregrep"a" x 23 は失敗。 21 個なら大丈夫 (令和だぜ・・・?)
    • grep -E なら DFA 型なのでマッチできる
    • a? のマッチの仕方が複数あるため
    • a?? にすればマッチングできる。 ?? は最短一致を先に施行する
  • 正規表現技術入門 の 7 章を見て下さい
  • Tagged NFA (TNFA)
    • 有限個のカウンタを持つ
    • キャプチャを可能にする
    • むずいので論文読んで教えて
  • 透過性の判定は難しい
    • 正規表現が同じ文字列の集合を受理するのか
  • (a|b)*(a|bb*a)*|a*b(b|aa*b)* は等しいのか
    • NFAにして考えると、aで終わる文字とbで終わる文字の結合だとわかる
    • オートマトンを介するしかない
  • 正規表現は難しい、オートマトンはかんたん
  • 公理を使って直接証明することはできる
  • 正規表現が重宝される理由
  • 1行で書けるからかんたんとは限らない
  • オートマトンはちょろい、かわいい
    • 様々な拡張モデルの提案
    • スタックやキューなど。後者はチューリング完全だが前者は違う
    • 受理、非受理だけでなく、受理する確率や、文字列など
      • weighted automata はかっこいい
  • オートマトンはFA
    • AFA~ZFAまで全部ある(略称が被っているものもある)
    • KFAとYFAは微妙にないと言えるかも。新しいオートマトンを作るチャンス
  • 語の組合せ論
    • 部分語の出現を数える
    • 部分語の出現回数がふさわしいような言語 $L^{=}$
  • 無限集合になるかどうかを判定できるか?
    • L^{=} \{ a, b, c \}正規表現でも文脈自由でもない
    • L^{=} \{ ba, ba, a \} \{ \epsilon, b, bb, bab, bbb, ... \} 無限集合
    • L^{=} \{ ba, ba, a, b \}\{ \epsilon \} 無限集合
  • 2018年に語混合言語の無限性は決定可能であることを示した
  • constrained automata
  • オートマトンはちょろいのではなく奥が深い

regex-applicative: 内部DSLとしての正規表現 / @igrep さん

  • 日本Haskellユーザーグループ をよろしく
  • 今日はHaskellについては話さない
  • regex-applicative
  • match :: RE s a -> [s] -> Maybe a
    • 完全一致のみ
    • マッチしたら Just しなければ Nothing
  • 連接は *>
    • sym 'a' *> sym 'b'
    • string "ab" と同じ
  • 選択は <|>
    • sym 'a' <|> sym 'b'
  • 繰り返しは、 many (0 回以上) と some (1 回以上)
  • optional オプショナル ? と同じ
  • マッチした値を Haskell の値に割り当てる
    • digit 数値
    • many digit 数値のリスト
  • 正規表現内で計算
    • sum <$> many digit
  • string "http" *> optional (sym 's') *> string "://"
    • some (psym (`elem` ['a'..'z'] ++ "."))
    • psym は関数が芯になるような文字はマッチする
  • マッチ結果を構造体にマッチできる
    • data Origin = Origin { ... } を定義
    • Origin <$> scheme <*> host <*> (prot <|> pure 80) (この例はschemeが正しく取れてないので注意)
    • <$><*> で組み立てられる
  • メリット
    • コンパイラによる型チェック
    • 文字列以外の扱いが得意
  • デメリット
    • コードが長い
    • 速度も速くない
    • String 以外にはマッチできない
  • 仕組み
    • 継続渡しで作られたNFA
    • バックトラック
  • 正規表現の分類 - DFA型とVM
  • regex-applicative
    • NFA をそのまま使っている
    • 文字を受け取って次の状態を渡すリストとして表す
    • s -> [Thread s r] の実行に失敗したらバックトラックする
    • findLongestPrefix 関数のような実装に役に立っている
  • 比較
    • パーサコンビネータは Applicative ベースなので似ている
      • バックトラックをするかしないかが違う
    • パーサコンビネータは部分一致できないが、部分一致できるようにするライブラリもある
    • regex-applicative は部分文字列へのマッチがかんたん

Emacs正規表現 / @tadsan さん

  • PHPには複数の正規表現エンジンがある
  • ereg (POSIX ERE、廃止), preg (PCRE), mb_ereg (鬼車)
  • 現状のPHPにはリテラルがない
    • バックスラッシュを一文字にマッチするには \\\\
  • preg ではデリミタを変更できる
    • '@ ... @i' など。後ろはパターン
    • 正規表現と競合しないものがいい
  • 内部的には正規表現結果はキャッシュしている
  • Emacsのエディタの検索機能
    • Emacs正規表現はNFA
    • グループなど \ の前置が必要
    • [:space:] など癖がある
  • Lispでは foo-bar は1つのシンボルだが、C言語では減算
    • syntax table で変更できる
    • 逆に言うと正規表現の結果は、バッファの syntax table の値で変わる
  • 文脈によってエスケープの違いがある
    • \\"\\\\" みたいな
  • emacsのメジャーモードを書くには、大量にエスケープを書く必要がある
    • 読みにくい
    • rx という DSL がある (group "regexp") (repeat n m pattern) など
  • re-builder で色付けができる

ヘルプシステムで正規表現を使う / @masui さん

  • Scrapbox
    • 簡単に使える wiki
    • 正規表現を展開してヘルプシステムに使う
  • ヘルプシステムは情報が見つからないので誰も使わない
    • なぜか正規表現で解決できる
    • コールセンターに電話してしまう。3年でやめる
    • 一兆三千億円規模。書籍と同じ
  • データを網羅的に生成、それからフィルタリング
    • Generate & Test
    • 網羅してから合うものを選ぶ
  • 正規表現展開ライブラリ
    • (a|b)+a, ab, b, ... と展開したり
    • ユーザの質問を正規表現で書いて、展開したものであいまい検索を実行する
    • (時計|時刻)を(1?[0-9])時に(設定|セット)する
    • 回答だけではなく、実行もしてしまう
  • あいまい検索はちょろいオートマトンで実装
  • Git Help
    • 難しい git コマンドをかんたんに実行できる
    • ある文字列が初めて出現したバージョンの出し方とか
    • gitはなんでもできるが誰もそんなことは知らない(難しすぎる)
    • IME的に実装。コマンドを打つとコマンド一覧の窓が出て、実行可能
  • Helpfeel
    • ヘルプページ向けのサービス
  • GitHelp は論文投稿したがリジェクト
    • Gitを使ってないらしくリジェクト
  • http://masui.org に資料あります

正規表現の等価性判定について / @make_now_just さん

  • 正規表現の等価性は判定可能で、そのアルゴリズムの話
  • 例えば、Base64にマッチする正規表現は複雑
    • 文字列長が4の倍数と末尾の = の扱い
    • 2つの正規表現に分けたものと、等しいかチェック
  • 正規表現DFAにでき、DFAを最小化できる。それが同型かを判定可能
    • 効率が悪い
  • 効率の良いアルゴリズム
    • DFAにはする
    • 初期状態からアルファベットのすべての文字について遷移させる
    • 受理状態がどこかで食い違ったら別
    • 割と普通の幅優先探索になる
    • 対応する状態を色付けして分類していく
    • すべての分類が一致すれば完了
  • 単純でDFAの最小化より効率的。DFAを作る時点でコストは大きい
  • NFAで判定する方法はどうか
    • NFAへの変換は楽なのでいい
    • 本当は正規表現のまま比べたいのでは
  • 正規表現微分で判定する
  • 文脈自由言語の等価性は決定不能であることは知られている
  • 論文では、NFAを使ったものが一番早いそう

ミニマルな正規表現エンジンをScalaで実装してみた / @kmizu さん

  • 正規表現エンジンを自作する方法
  • アルファベット、空列、連接、和、Kleene閉包、e? e+
  • 実装は教科書的
  • ASTとNFA、NFAState、DFAなどを定義
  • パーザはASTを作る
    • 脱糖もする e?e|e+ee*
  • 正規表現を教科書的にNFAにする
    • 変換規則に沿って変換するだけ
  • NFAをDFAにする
    • 部分集合構成法
    • NFAの状態の集合のサブセットをDFAの状態にする
  • 300行未満で書けるので、みなさんも書きましょう

その正規表現エンジン、インタプリタで満足(satisfy)してる?! / @blackenedgold さん

  • SATySFi
    • TeXを倒すためのもの
    • 日本語が扱えてPDFが出力される
  • ML風の関数定義、バックスラッシュのコマンド
  • インタプリタコンパイラ
  • (第一)二村射影
  • 多段階計算
    • ステージ0でステージ1で実行されるプログラムを生成する
    • ステージ1でプログラムを実行する
  • &42 は次のステージで 42 になる。 &int
  • SATySFi には差ショートサーキットする論理 or and がない
  • マクロっぽいが、式から式の変換しかできない
    • eval には制約が入っている
    • 生成されたコードはコンパイルエラーにならないように型がつく
  • インタプリタの実装はDFAベースよりかんたん
  • 命令列をリストで書く (εと連接が何もしなくても手に入る)
  • SATySFiは文字がないので、文字列を文字代わりにする
  • 強欲マッチ(バックトラックは実装しない)なので、かんたん
  • これをコンパイルするのは &~ を適切に入れるだけ
  • コンパイルにすると、静的(stage 0)でエラーを検出できる
    • 組版で後半のページでエラーが出ると、前のページの生成が無駄になる
  • コンパイルだと正規表現は静的に与えなければならない

l3regex: TeX で実装された正規表現エンジン / @wtsnjp さん

  • l3regexの3つのポイント
    • 将来性がある
    • 実装がすごい(TeXで実装されている)
    • 実用性がすごい
  • LaTeX3プロジェクトなので将来性がある
    • LaTeX2eの光景
    • 1990 年代から作られている
  • 実装がすごい
    • TeX名前空間がない、展開制御がない、副作用がいっぱい
    • 字句解析にチューリングマシンが必要となる言語
    • NFAベース(らしい)
    • TeXで実装するとあらゆる環境で動くので
  • 実用性 - 普通のライブラリ
    • バックスラッシュが蔵試食したりしない
    • TeX Live, MiKTeXなどでも導入される
  • 滅ぼされる言語かもしれないが、来週提出の論文には使える!

正規表現苦手なんです / @5mingame さん

正規表現のlook behindで量指定子を使いたい / @hachi8833 さん

  • (?<=...) (?=)
    • look behind に長さが違う (...|...)? {1, 2} .+ .* を書くことができない
    • 長さが変わってはいけない
  • ? {1, 2} がだめなのはなっとくいかない
    • (a|b) のように長さが変わらないのはいい
    • {3} とかも
  • .NET Framework正規表現ではフルで使える
    • 最強の正規表現エンジン
    • ドキュメントも充実
  • V8 の正規表現エンジンもいける
    • 昔のJSは look behind 自体がなかった
    • 文字クラスも使えるように?
  • PCRE と Onigmo も頑張ってほしい

とある機械の右方跳躍 / @sinya8282 さん

  • 世界で知っている人10人もいない
  • right one-way-jumping automata
    • 日本語訳は shinya さんが勝手につけたもの
    • 文字列を読むときに、1文字ずつではなく飛び越える
    • 秋田大の学生が考えたもの
  • (b|a)*DFA を右方跳躍オートマトンとして扱うと、 a と b の出現回数が同じものを受理する
  • 例えば、 baaabbba で計算が終わるはず
  • 「optさんが素晴らしい酎ハイを用意してくれたのでちょっと酔ってる」
  • 右方跳躍では、遷移可能な文字で一番近い文字に飛ぶ
    • 一番右まで行くと左から戻ってくる
  • 「与えられた右方跳躍オートマトンAがDFAのとき、Aの受理する文字列の集合が正規言語になるかどうか、のアルゴリズムが存在するか」は未解決

結局rustの標準入出力はどう書けばいいの?

現状。 StdoutLockLineWriter を噛んでるので、 BufWriter の意味があるのか謎。ベンチマーク取らねば。

use std::io::{self, BufRead, BufWriter, Write};

fn main() {
    let stdio = io::stdin();
    let mut input = stdio.lock();

    let stdout = io::stdout();
    let mut output = BufWriter::new(stdout.lock());

    let mut line = String::new();
    while input.read_line(&mut line).unwrap() > 0 {
        let _ = writeln!(output, "{}", line);
        line.clear();
    }
}

↑のコードは以下を参考に勘で書いている。

【追記】WSL上での雑なベンチ

BufWriter の意味はありそう。以下がない場合。

$ time yes | head -n 1000000 | ./target/release/bench > /dev/null

real    0m4.102s
user    0m1.250s
sys     0m2.906s

BufWriter 噛ませた場合。 42 倍くらい違う。

$ time yes | head -n 1000000 | ./target/release/bench > /dev/null

real    0m0.098s
user    0m0.063s
sys     0m0.047s

さらに、 writeln! マクロを使わずに、

        let _ = output.write(line.as_bytes());
        let _ = output.write(b"\n");

とかやると、もうちょい早い。

$ time yes | head -n 1000000 | ./target/release/bench > /dev/null

real    0m0.073s
user    0m0.031s
sys     0m0.063s

emacsで自動改行して欲しくない

特に端末へコピペとかするときに、本当に迷惑なので。

init.el をイジる。まず、 (setq indent-line-function 'insert-tab) なんて記述があったので削除(誰がなんのために入れたんだ?)。

次に、 (electric-indent-mode 0) を追加。

これでほとんどのモードで直ったのだけど、 markdown-mode だけは駄目だったので、ダメ押しの (setq markdown-indent-on-enter nil) を追加。 RET 押下時の indent-and-new-item の呼び出しを抑制できるらしい(勝手にそんなことしないで)。

メジャーモードによって挙動を上書きできるようなので、おかしなメジャーモードがあったら設定などを見直して対応していくしかなさそう。