haskell-jp / random #104 at 2023-10-01 12:34:35 +0900

Hiromi ISHII / mr_konn
手前味噌ですが、さいきん Haskell で線型型,を使えるようにする GHC の LinearTypes 言語拡張をがっつり使ってみたので、Haskell の線型型を使おうとすると現在はこんな感じだよ、将来はこうなって Rust のリソース管理により近くなっていくよ、というような記事を書きました。Linear Haskell のライブラリを使う側の話が主ですが、ライブラリを作る時の話についても需要があればそのうち書くかもしれません(書かないかもしれません)。
https://zenn.dev/konn/articles/2023-10-01-linear-haskell-in-2023
大変興味深いblogだと思っているのですが、
rustとの違いや線型、非線型のところがわかりずらく、
setとgetのところがよくわからないです。
結局rustのように書けるのか書けないのか。
どうなってしまうのか対比が欲しいです。
Consumableでdropがあるのは興味深いのですが、
NUMとか既存の型クラスのものに対してもうまく扱えるのかどうか知りたいです。
haskellはrustになれるのでしょうか?
ーー
tweagの記事はあまり踏み込んだところを書いてなくて、
今回の記事は色々な話題に具体的に触れていて素晴らしいです。
Hiromi ISHII / mr_konn
感想ありがとうございます!たしかにRustの例との対比があったほうがわかりやすかったかもしれないですね……。
Hiromi ISHII / mr_konn
Consumableでdropがあるのは興味深いのですが、
NUMとか既存の型クラスのものに対してもうまく扱えるのかどうか知りたいです。
Consumableは型に対する型クラスなので、個別の型ごとにインスタンスを与えることになります。だいたいめぼしいプリミティブな型については与えられていて、どれがインスタンスになっているのかは詳しくはlinear-baseのドキュメントを参照してください。
Hiromi ISHII / mr_konn
Numの演算の線型版はあるか?という質問であれば、これはPrelude.LinearでPreludeと同様の型クラス名である程度線型版が提供されています。Integralはありませんが、同じようにして類似物を定式化可能ですね
Hiromi ISHII / mr_konn
haskellはrustになれるのでしょうか?
はっきり( 1, 2)と

RustのようになるにはLinear Constraintsに期待。
という訳で結論。2023年のHaskellはまだ Rust ではないが、近い将来 Rust になれる可能性が大きいということでひとつ。
とかいたつもりだったのですか、これでは不足でしょうか……?
Hiromi ISHII / mr_konn
Rustとの対比がないので脳内で補完しない限り結論が具体的な説得力に欠ける、というのであれば確かにそうで、そこは完全にサボってましたね……
ありがとうございます。
Hiromi ISHII / mr_konn
いえ、こちらこそ感想ありがとうございます……!とても励みになります。
斜め読みしかできてないけど、素晴らしいです。
SPJの講演も聞きました。
Hiromi ISHII / mr_konn
ありがとうございます……!SPJの講演はいつもきいていて楽しく、わかりやすいのですごいですよね。
素人質問で申し訳ないのですが、PSQみたいな木構造も線形型にして、GCの対象ではなくすことはできますか?
ネットワークサーバを作っていると、GCで止まる時間が問題で、大きなデータはGCの対象外としたいのです。
このPSQを変更するのは、1つのスレッドのみです。
Hiromi ISHII / mr_konn
理論上はできるはずです。ただ、記事の冒頭でも書いたように、

> これは、「Linear Haskell を使うとGCで管理されていないデータ型をアロケートする仕組みを創れる」ということであって、*Linear Haskell を使うと値が GC の管理外に必ず置かれるという訳ではない*
という事情があります。なので、単純に Linear Haskell を使うだけでなく、linear-base の Pool のインタフェースにあうようにデータ型や操作を定義してやる必要があるかと思います。これは精しくいえば、Storable をつかってポインタベースで PSQ を定式化する必要が現時点ではある、ということです。一つのスレッドしか使わないということで、スレッド安全性が問題にならないのであれば、 を使ってアロケーションを行う方針で問題ないと思います(スレッドセーフではないですが、今回は問題なさそうなため)。

Pool を使ってデータ構造を実装例は、linear-base の examples 以下にありまして、単方向リストや単純なペアリングヒープの例があります:




この辺りが参考になるかなと思います。Pool を使う場合、 Representable 型クラス(本質的にはStorable な表現と相互変換できる型のクラス) を使ってアロケートする必要があるので、PSQに仕舞うデータ型も何らかの意味で Storable と相互変換出来る形式にする(だから、生の高階関数などは仕舞えない)という点に注意する必要があるかと思います。PSQの中身までは別に消さなくても良い、ということであれば StablePtr に包むなどの手も使えるとは思います。
Hiromi ISHII / mr_konn
あと、値を変更したりする場合は現状で Pool はアロケートとディアロケート一回ずつしか対応していない(初期化と最終化しかない: alloc :: a %1-> Pool %1-> Box adealloc :: Box a %1-> a のみ)ので、値を適宜変更して保存しなおすプリミティヴを Internal モジュールを読み込んで実装する必要等はあると思います。シングルスレッドであれば、これは NOINLINE などを適切に書けばそんなに難しくないです
Hiromi ISHII / mr_konn
じゃっかん違う方向性ですが、メモリにシリアライズされたデータを直接(ADTのように)扱うインタフェースを Linear Type を使って定式化する話も Tweag のブログ記事にはあり、目指しているところはやや違いますが、これも多少参考にはなるのかなと思います
https://www.tweag.io/blog/2017-08-24-linear-types-packed-data/
ありがとうござます。
Storableにする必要があるのであれば、redisに投げるというが、僕にとっては現実的かもしれません。。。
Hiromi ISHII / mr_konn
そうなっちゃいますよねえ……。derive-storableパッケージやderive-storable-pluginを使えばある程度Storableの導出を自動化してくれるとはいえ、もう少し手軽にoff-heapアロケーションできるようになるといいのになあという気持ちがあります