F#でsleep sort
追記しました
元ネタは、以下あたり。
常識を覆すソートアルゴリズム!その名も"sleep sort"! - Islands in the byte stream
http://d.hatena.ne.jp/gfx/20110519/1305810786
Sleep sortの各言語での実装まとめ – Yuyak
http://www.yuyak.com/1339
ただいま流行っている sleep sort です。
既出かもしれませんが、せっかく書いたので置いておきます。
open System.Collections.Concurrent let sleepSort f s = let q = new ConcurrentQueue<'a> () seq {for x in s -> async { do! Async.Sleep((f:'a -> int) >> ( * ) 100 <| x) q.Enqueue x } } |> Async.Parallel |> Async.RunSynchronously |> ignore q :> seq<'a> ["5";"3";"6";"3";"6";"3";"1";"4";"7"] |> sleepSort int |> Seq.iter (printf "%s,") System.Console.ReadLine () |> ignore
いろんな書き方があると思うけど、一応F#らしさをプンプン匂わせてみたつもり。
追記:シグネチャ ファイルも書こう!
@igeta @kos59125 お。だいたいそうなりますね。それにしても、intだけしかソートできないとか、元仕様をシカトした実装が多すぎる気が。そこは守りましょうよ的に思ったり。
2011-05-20 22:23:19 via web to @igeta
2011-05-20 22:25:44 via web to @zecl
@kos59125 @igeta あ、いえ・・・。別にマジメにやるようなネタでもないですからねw こちらこそ、なんかすいません^^;
2011-05-20 22:27:29 via web to @kos59125
@zecl @kos59125 シグネチャ ファイルが付いてないコードはすべて手抜きです!(キリッ などと。
2011-05-20 22:42:04 via web to @zecl
あ、シグネチャ ファイルって、実はあんまし書いたことなかったですよ^^;
ということで、せっかくなので書いておきます。
SleepSort.fsi
namespace Sort [<AutoOpen>] module Sort = val sleepSort : ('a -> int) -> seq<'a> -> seq<'a>
SleepSort.fs
namespace Sort [<AutoOpen>] module Sort = open System.Collections.Concurrent let sleepSort f s = let q = new ConcurrentQueue<'a> () seq {for x in s -> async { do! Async.Sleep((f:'a -> int) >> ( * ) 100 <| x) q.Enqueue x } } |> Async.Parallel |> Async.RunSynchronously |> ignore q :> seq<'a> ["5";"3";"6";"3";"6";"3";"1";"4";"7"] |> sleepSort int |> Seq.iter (printf "%s,") System.Console.ReadLine () |> ignore
これでよいかな?
追記:よいシグネチャ ファイルは、よいドキュメントでもある
せっかくなのでシグネチャ ファイル追記しておいた。これで勝つる。
2011-05-20 23:03:39 via web
@zecl 引数名の指定も .fsi 側でぜひ。あとコメント。
2011-05-20 23:05:50 via web to @zecl
val sleepSort : projection:('T -> int) -> source:seq<'T> -> seq<'T> とかしておくとすばらしいと思うです。
2011-05-20 23:18:23 via web
よいシグネチャ ファイルは、よいドキュメントでもある、とか OCaml のエロイ人が言ってた気がする。ただし僕はいまホッピーを飲んでいて酔っているのでよくわかりません。
2011-05-20 23:21:04 via web
記憶力の乏しさなら自信があります!
2011-05-20 23:24:02 via web
その気になれば、.fs ファイルでは気ままに f とか x とか短い引数名を付けておいて .fsi ファイル側で意味のある名前を付ける、ということも可能だろう、ということ。
2011-05-20 23:28:11 via web
@igeta ありがとうございます!コメントというのは、.fsの関数に「///」でコメントが欲しいということです?
2011-05-20 23:31:27 via web to @igeta
@zecl .fsi 側で各 val なり module なりの上っちょに /// でも // でもいいのでコメントがあるといいなあと。まあ簡単に言うと F# Compiler Source の書き方に準拠してる的な感じになってるといいなっていう。
2011-05-20 23:35:14 via web to @zecl
ぜんぜん勝ててなかったorz... なるほど。勉強になります。
ホッピーうまいですよね!ということで、コメントと引数名をさらに追記しました。
SleepSort.fsi
namespace Sort [<AutoOpen>] module Sort = /// 定義であり、ドキュメントにもなる。ここで、関数に対する熱き思いをぶつけるといい。 /// 常識を覆すソートアルゴリズム!その名も"sleep sort"!のシグネチャです。 val sleepSort : projection:('T -> int) -> source:seq<'T> -> seq<'T>
SleepSort.fs
namespace Sort [<AutoOpen>] module Sort = open System.Collections.Concurrent /// 常識を覆すソートアルゴリズム!その名も"sleep sort"!をしちゃいます。 let sleepSort f s = let q = new ConcurrentQueue<'a> () seq {for x in s -> async { do! Async.Sleep(f >> ( * ) 100 <| x) q.Enqueue x } } |> Async.Parallel |> Async.RunSynchronously |> ignore q :> seq<'a> ["5";"3";"6";"3";"6";"3";"1";"4";"7"] |> sleepSort int |> Seq.iter (printf "%s,") System.Console.ReadLine () |> ignore
という具合に、引数名を変えてもOKだし、ジェネリックの型名を'Tから'aに変えても問題ない、と。
そして、f の型についてはシグネチャファイルに定義してあるので省略可能になる、と。
こんどこそ、これで勝つる!
@igeta なるほど。.fsiが定義 and ドキュメントになるようにですね。手抜きをしないってのは結構大変っすね; この程度の規模ならよいですが、頻繁にリファクタリングしているようなときは、.fsiなんて書いている場合じゃない!ような気もしまする(単に能力不足か・・・
2011-05-20 23:42:29 via web to @igeta
追記:シグネチャ ファイルを自動生成しよう
@zecl fsc SleepSort.fs --sig:SleepSort.fsi
2011-05-20 23:58:06 via web to @zecl
@zecl ってすると fsc さんがよしなに fsi を作ってくれますよ。
2011-05-21 00:03:13 via web to @zecl
シグネチャファイル(.fsi)をよしなに自動生成したあとに、自分でいろいろ追記すればよい、と。
でも、大幅にコードの構成を変えた場合はやり直し。それはちょっとツライね。