haskell backpack 事始め

Post on 29-Jan-2018

435 Views

Category:

Software

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Haskell Backpack 事始めひげ

注意!

Backpack は2種類ある!Backpack'14:

Scott Kilpatrick 氏が提案(POPL 2014)

MixIn を利用して弱いモジュール言語に強いモジュール性を組み込む

Backpack'17:

Edward Z. Yang 氏が提案(彼の博士論文?)

既存の GHC に組み込めるように Backpack'14をリファクタリング

GHC8.2 や Cabal2.0 に組み込まれたのはコッチ

Backpack は2種類ある!どちらも目的は

Haskell に強いモジュール性を組み込むこと

しかし,ぼくの中でふたつの差分をしっかりと飲み込めてないので,イロイロと間違ってる部分がアルかもしれない....

Backpack'14の論文には概念的な主張が多いが,'17には少ない印象...'14の主張が,どこまで'17でも尊重されてるかハッキリとはまだ分からないので,その点が怪しいです...

ちなみに以下のリポジトリに少しだけまとめてある

matsubara0507/awesome-backpack - GitHub

今後も少しずつ更新してくつもり

本題

Haskell のモジュールは弱い

弱いモジュール性モジュール A がモジュール B に依存している場合

モジュール A の実装はモジュール B に依存する

Haskell の既存のモジュールシステム

Haskell の既存のパッケージシステム

は弱いモジュール性で実装されている

(インターフェースの依存性より弱いって意味っぽい)

強いモジュール性インターフェースの実装が何に依存しているかとは独立 にモジュールを型検査することが出来る.

(インターフェースの依存性より強いモジュール性)

結果として以下のことを可能にする!!

インターフェースとなるモジュール

リンクへのモジュールの再利用

モジュールの再帰的なリンク

しかし Haskell には弱いモジュールシステムしか...

そこで Backpack'14

Backpack'14パッケージレベルでの設計

シンプルな MixIn デザインを採用

ベースは MixML

いくつか問題があたので Haskell に対応させた

ジェネリックな設計なので他の Weak Module を持つ言語でも機能する(だろう)

強いモジュール性で Haskell を改造する!(Retrofit)

Modules in Today’s Haskell以下のような Haskell の Modules を考える

-- Socket.hsmodule Socket where data SocketT = ... open = ...

-- Server.hsmodule Server where import Socket data ServerT = ... SocketT ...

Packages in Backpack'14Backpack'14 だと次のように書ける

package complete-server where Socket = [ data SocketT = ... open = ... ] Server = [ import Socket data ServerT = ... SocketT ... ]

この時点では,ただまとめただけ...

※ ココの話はGHCに採用されては無い(構文とか)

Packages in Backpack'14Signature を利用すると次のように書ける

package partial-server where Socket :: [ data SocketT open :: Int -> SocketT ] Server = [ import Socket data ServerT = ... SocketT ... ]

※ ココの話はGHCに採用されては無い(構文とか)

Packages in Backpack'14packageを別々に定義してincludeすることもできる

package socketsig where Socket :: [ data SocketT open :: Int -> SocketT ]

package complete-server where include socketsig Server = [ import Socket data ServerT = ... SocketT ... ]

※ 以降の話はGHCに採用されては無い(構文とか)

Packages in Backpack'14Signature を持つパッケージに,それを実装したパッケージを linking する

package socketimpl where Socket = [ data SocketT = ... open = ... ]

package main where include partial-server include socketimpl

Packages in Backpack'14再利用する

package server-linked-1 where include partial-server include socketimpl-1

package server-linked-2 where include partial-server include socketimpl-2

別々の実装 socketimplN を与えて

Packages in Backpack'14再利用する

package multi where A = { include server-linked-1 } B = { include server-linked-2 } Main = [ import qualified A.Server import qualified B.Server ... ]

両方とも呼び出す!

Packages in Backpack'14再帰的にも適用できちゃう!

package ab-sigs where A :: [ S_A ] B :: [ S_B ]

package b-from-a where include ab-sigs B = [ inport A ; ... ] package a-from-b where include ab-sigs A = [ inport B ; ... ]

package ab-rec-sep where include a-form-b include b-form-a

しかし...Backpack'14 では GHC での実装

できなかった...

何故かBackpack'14 の意味論は Haskell の意味論と密接に結びついている

そのため,GHC と Cabal を切り離して実装することが出来なかった

Backpack'14 はコンパイラとパッケージマネージャー間の

抽象化の障壁 (abstraction barrier)

を壊してしまうらしい(用語が良く分からないけど)

そこで Backpack'17(そこでというか,そういうモチベーションだけどね...)

Backpack'17Backpack'14 を実用的に改良

コンパイラとパッケージマネージャーの障壁(バリア)を保持(??)

GHC8.2 と Cabal 2.0 に導入された

我らがヒーロー Stack 様はまだ

Hackage も 代わりに next.hackage

基本的な概念(MixIn, Signature など)はBackpack'14 と同じだと思われる...(構文は違うけど)

GHC 8.2 で試す詳しくはこの記事を参照

1. *.bkp というファイルを作る

2. ghc --backpack xxx.bkp と打つだけ

*.bkp は *.hs に比べて unit と言う階層ができた

unit main where module Main where main = putStrLn "Hello world!"

ひとつの *.bkp ファイルに unit は複数書いて良い

例: 正規表現細かい実装は割愛...

-- regex.bkpunit str-bytestring where module Str

unit str-string where module Str

unit regex-types where module Regex.Types

unit regex-indef where dependency regex-types signature Str module Regex

例: 正規表現-- regex.bkpunit main where dependency regex-types dependency regex-indef[Str=str-string:Str] (Regex as Regex.String) dependency regex-indef[Str=str-bytestring:Str] (Regex as Regex.ByteString) module Main

ひとつのインターフェースモジュールで別々の実装(String と ByteString ) が同時に使える!

後は ghc --backpack regex.bkp と打つだけ!

Cabal 2.0 で試す詳しくはこの記事を参照

1. bkp ファイルを unit ごとに分けて( *.hs と *.hsig )

2. cabal ファイルで依存関係を定義し

再構築するイメージ(たぶん)

さっきの例がこんな感じに分かれる.

大きく分けて2つのやり方Cabalのバージョンが 1.25 以上である必要がある

1. 単一のパッケージで管理する場合

このブランチやこのブランチ

cabal build でビルド

2. 分割してパッケージを管理する場合

このブランチ

cabal new-build でビルド

なぜ?Bcakpack パッケージをインスタンス化する必要があるためコマンドが(今のところ)異なる.

(1) は Cabal でビルドした時点で完全にカプセル化される.これは ghc --backpack でも同様である.

ちなみに

(1) であれば Stack と cabal-install でもビルド可能だそうだ.

まとめ

まとめHaskell に MixIn を用いた強いモジュール性を追加

モジュールの実装の依存を後から選択可能

モジュールをインターフェースとして使える

GHC8.2 から *.bkp で利用できる

Cabal2.0 から *.hsig *.hs *.cabal より *.bkp を構成

分けてにビルドするなら cabal new-build を使う

next.hackage で既に Backpack を用いたライブラリが管理されている

結局何がうれしいのか(ちゃんと論文読んでないので,ぼくが思うところ)

本質的には関係ない実装を利用者側で選択できる

A パッケージの文字列に Text を使うか ByteStringを使うかは利用者の自由

A-text とか A-bytestring とか別に作る必要が無い

型クラスに無理やり突っ込んでたモノが解決

モジュールレベルにアドホック多相(たぶん)

面白い

おまけ

Stack の現状...なんと1年前から Issue がある

IRCで議論してロードマップはできてるみたい

1. Stack が Cabal2.0 をサポート(済)

2. Stack をコンポーネントごとのビルドプランに切り替える(see haskell/cabal#2802)

一番エキサイティングらしい(?)

3. Cabal2.0前後でビルドプランを切り替える(難題)

つまりStack Project 単位でモジュール群を持っていた

しかし Backpack はモジュール(コンポーネント)ごとに管理する必要がある

従ってモジュール群の管理方法を変える事が必要

コレ曰く,インターナルライブラリをサポートするのが一つの方法で,foreign libraries で既に採用済みとのこと

最新のアクティビティがソレについてなので,その方向でやるのかな?

おしまい

top related