id:n7shi:20100701で開発した逆アセンブラ・インタプリタをF#に移植しました。Visual Studio 2008 ShellでF# Integrationを使用しています。
SilverlightではなくWindows Formsを使用しています。Silverlight ToolsでF#がサポートされたようですが、Visual Studio 2008 Shellからxapを出力する方法が分からなかったためです。以下のように手動で作成するしかなさそうです。
この方法だとUIデザインやデバッグが大変そうなので断念しました。
【追記】Visual Web Developer 2010 Express EditionでF#のライブラリをビルドする方法が判明しました。 ⇒ id:n7shi:20100710
テーブルの初期化
C#よりもF#の方が自然に書けると感じたのはテーブルの初期化です。
C#ではstaticコンストラクタでテーブルの初期化を行っていました。
public class Alpha { private static string[] regname = new string[32]; private static ulong[] mask = new ulong[256]; static Alpha() { for (int i = 0; i < regname.Length; i++) regname[i] = ((Regs)i).ToString().ToLower(); for (int i = 0; i < 256; i++) { ulong m = 0xff; for (int j = 1; j < 256; j <<= 1, m <<= 8) if ((i & j) != 0) mask[i] |= m; } } }
F#では定義と同時に初期化コードが書けるため、コードが分断されずに自然だと思いました。以下はC#を直訳したコードです。
let regname = let regname = Array.zeroCreate<string> 32 for i in 0..31 do regname.[i] <- enum<Regs>(i).ToString().ToLower() regname let mask = let mask = Array.zeroCreate<uint64> 256 for i in 0..255 do let mutable m = 0xffUL let mutable j = 1 while j < 256 do if (i &&& j) <> 0 then mask.[i] <- mask.[i] ||| m j <- j <<< 1 m <- m <<< 8 mask
maskでのjとmに対する破壊的代入をやめてみます。
let mask = let mask = Array.zeroCreate<uint64> 256 for i in 0..255 do for j in 0..7 do if (i &&& (1 <<< j)) <> 0 then mask.[i] <- mask.[i] ||| (0xffUL <<< (8 * j)) mask
配列の要素に対する破壊的代入をやめるため内包表記に書き換えます。
let regname = [| for i in 0..31 -> enum<Regs>(i).ToString().ToLower() |] let mask = let bittest i j = if (i &&& (1 <<< j)) = 0 then 0UL else 0xffUL <<< (8 * j) [| for i in 0..255 -> Seq.sum(seq { for j in 0..7 -> bittest i j }) |]
配列に対するnewが言語機能として用意されていないのに不満を感じていましたが、こういうことだったのかと思いました。
内包表記への書き換えはパズルのように感じました。C#の知識だけでは読み方が分からないので、慣れが必要だと思います。C#でもクエリ式を使えば同じようなことができます。
private static string[] regname = (from i in Enumerable.Range(0, 32) select ((Regs)i).ToString().ToLower()).ToArray(); private static ulong[] mask = (from i in Enumerable.Range(0, 256) select (ulong)Enumerable.Range(0, 8).Sum( j => (i & (1 << j)) == 0 ? 0L : 0xffL << (8 * j))).ToArray();
C#でも積極的にこういう書き方をするべきかは悩みます。私は常用するまでには至りませんでした。