ラベル Monad の投稿を表示しています。 すべての投稿を表示
ラベル Monad の投稿を表示しています。 すべての投稿を表示

2017/10/30

Mercurial Repository を Git Repository に変換する

Findy という転職サイトが GitHub の public repository からスキル偏差値なるものを算出してくれます。
一度登録してみると、スキル偏差値はプレミアム本会員になるギリギリの60でした。
実際どのくらいなのだろう60。定量的な値になってると良いのだけれど。

さて、 GitHub には大学とは関係ない個人のプロダクトとかを載せていました。
大学での課題やプロダクトは大学の Mercurial Repository に残しています。
ですが、この際 GitHub にも載せることにしました。
単にスキル偏差値を上げたいだけとも言う。
単に bitbucket に上げても良いのだけれどそれだと Findy に拾って貰えないので。


環境構築

Mercurial から Git への変換は fast-export を使います。
  • $ git clone https://github.com/frej/fast-export
こいつは python を内部で使ってるのでその調整も必要です。
  • $ easy_install mercurial
とかかな。
私は python2 を brew で明示的に入れてるので
  • $ vim fast-export/hg-fast-export.sh
    • python -> python2
  • $ pip2 install mercurial
とか。実行時にエラーが出なければOKだと思います。


自分だけが Author の Mercurial Repository の変換

fast-export のセットアップが終わったら、変換します。
  • $ mkdir git_repo
  • $ cd git_repo
  • $ git init
  • $ ../fast-export/hg-fast-export.sh -r /path/to/hg_repo
これで Mercurial の Repository を元に git に commit しまくってくれます。
きちんと時刻とかも残るので便利。


Author Information が気に入らない場合

私は大学時代の時は大学のメールアドレスで commit していたので、GitHub にはアイコンが無い。
これはちょっ悲しいので Author の情報を変更する。
具体的には username と email ですね。変更するには
とかすると良い。長いけれど1コマンドです。
これは他人の commit も変更できちゃうので完全に悪用厳禁ですね。


他の人も commit している repository の変換

最初にやることは変わらずに変換。
  • $ ../fast-export/hg-fast-export.sh -r /path/to/hg_repo
んで、 Author を変更する時に発行するコマンドを変えます。
if 文で自分の変えたい username+email を指定してあげています。

これで指定したものだけが変更されます。便利。
こっちも長いけれど1コマンドですね。
これで他人の成果をきちんと残したまま、自分の気に入らないメールアドレスを書き換えられます。
やっぱり悪用厳禁なコマンドなので注意。


fast-export で変換した Repository List

どうせなので公開できる成果物のリストを残しておきます。
この成果物が誰かの参考になれば幸いです。


オチ

この後 Findy で GitHub 再連携をしたところ、算出方法が変わったようで51に下がりました。かなしい。


環境

  • OS: macOS 10.12.6
  • fast-export (cc8fefe0083bc38c781341a86a1779dc5941f6e2)
  • python: 2.7.10
    • pip: 9.0.1
    • mercurial: 4.3.3
  • Mercurial: 4.3.3
  • Git: 2.14.3


参考

2013/08/18

Monad のようで Monad じゃないものを書いてみた

最近は すごいH本読んだり とか Haskell ってたのですが Monad が謎だったので試しに書いてみました。

結論から言えば Monad 則を満たしていないので、「Monad の instance にできてしまった何か」なのですが。
ってな訳で HookMonad なるものを作ってみた話。

HookMonad

a -> a な関数と a な値を持つデータ構造を定義。
>>= で関数を適用する際に a -> a の関数を適用してから関数を適用する、ってものにしてみました。

適用してみる想定として座標を考える。名前は nonMinusPoint とかにしてみました。
座標用のデータ構造で、値が 0 以下になったら 0 にしてくれる、って代物。
「プログラマブルセミコロン」のたとえを聞いて最初に思いついたものがコレ。
毎回 「0 以下なら……」 的なロジックが必要無さそうなので良いのかなー、と。
ソースはこんな感じ。

どう処理してるのか

Hook に a -> a な f として「0 以下なら 0 にする」lambdaを渡してます。
そうして >>= で関数を適用したい時はその lambda を適用してから関数を適用させる、と。
それを単純に使うために nonMinusPoint とかって名前を付けておく。
値を操作する関数 add とか multi には 「値が 0 かどうか」的なロジックはいらない。はず。
(とは言っても nonMinusPoint を結局使うので、毎回 lambda 書いてるのとあまり変わらない気もするけれど)
そうすると、 >>= で関数を適用する分には値が 0 以上になることが保証されそう。
あと、 Maybe の「失敗するかもしれない演算」みたいに「マイナスになるかもしれない演算」があったとしても確実に 0 以上であることが保証される。
だから add とかじゃなくて「0 以上でないと使えない関数」を定義した方が良いのかも。

 

ちなみにこれはMonadじゃない

ただし前述したけれどこれは Monad 則を満たしてません。
ちなみにMonad 則は以下。
return a >>= f ≡ f a
m >>= return ≡ m
(m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
1はどうにか満たしてるはず。
2は無理。return の型を合わせるために id を使ってるので、 m >>= return すると a -> a な関数が id に変わっちゃう。
3はどうだろ。たぶん満たしてそうだけれど反例が思いつかないだけかもしれない。

さらに問題点

もともとは「数値演算をしたら non zero にする」みたいなものを作りたかったので
Hook f n >>= g = fmap f $ g n
とかにしたかった。
だけれど >>= の型は
(>>=) :: Monad m => m a -> (a -> m b) -> m b
なので、 埋め込んでる a -> a な関数を m b に fmap しようとしてダメ、って言われる。
あと HookMonad が Functor じゃないと f を数値演算後に適用できないのだけれど、 fmap の型も
fmap :: Functor f => (a -> b) -> f a -> f b
ってなってるので、 Hook (a -> a) b になっちゃってダメ。
さらに、 return に id を使ってるので、汎用性を高めるために return を使ってるようなコードだとかえって a -> a な f が id になっちゃって埋め込んでたのが消えちゃう。
完全に Monad則 の 2 がダメになっています。
ってな訳でいろいろ問題点は多し。
ただ、「演算のたんびに何かする」ことはできたので良いのかなー、とか思っています。
まー、>>= に与える関数の中でも nonMinusPoint とか書いてるから「毎回何かする」部分を毎回書いちゃってる説もありますが。
(いやでも nonMinusPoint にすることで型が Hook になるので Hook なコードを書いてたら 型チェックされる ==  非ゼロ保証 だし良いのか? うーん)

なんか良いこと

あと書いててすごいなー、と思ったこと。
この Hook ですが deriving Show してません。
どうしてかと言えば関数を持ってるから deriving だと無理。
だから getValue を定義して、値だけを取り出すようにしないと ghci で値を見られませんでした。
その getValue の中でも f を適用するようにしたので、最後の最後だけ処理後に 0 以下かどうかのチェックができてます。
あと、コメントアウトしてるのは ghci で実行してみた例なのですが、 foldl でガンガン処理していけるっぽいです。
あと途中結果を見るために scanl を使ってみたのだけれどそのままだと見られない。
scanl は計算途中の内容を List にして返すので、その List に対して fmap で getValue かけたらきちんと見られました。
ちゃんとした Functor すごいなー、とか。
あと scanl で計算結果の途中を見ると、 0 以下になるところで 0 になってるっぽい。

ってなわけで Monad のようで Monad じゃない何かを書いてみました。