ScalaやHaskellのライブラリをF# に移植するときのTips?

こんなことを思っていたりすることもあるため、HaskellScalaに面白そうなライブラリがあると聞きつけるとF# に移植できないか試したくなります。

で、いくつかTipsというかこんなことがあるよ、的なことをまとめておきます。

用語はてきとーなので表現が微妙であれば順次修正していきます。

【この記事は書きかけです】

型パラメータが型パラメータをもつ

Free Monadを例にしてみると

sealed trait Free[S[+_], +A]

data Free f a = Pure a | Free (f (Free f a))

などの型パラメータが型パラメータをもってるよ的なやつです。

これが出た場合、私は白旗をあげます。

型エラーが解決できない

基本的には多相ではないのであきらめなければらなない場合か、解決できそうだけど根気負けする場合の2択です。

obj型なら通る、とかもたまにありますね。

再帰なlazyちゃんマジlazy

これはscala-machinesやHaskellのmachinesのrepeatedly関数を例にしましょう。
まずはScala

def repeatedly: Machine[K, O] = {
  lazy val r : Machine[K, O] = this >> r
  r
}

次にHaskell

repeatedly (Plan m) = r where r = m (const r) Yield Await Stop

lazyだからこそできる再帰ですね。

HaskellScalaではlazyが型に現れることはないので、これで問題なしです。

が、F#ではこう単純にはいきません。この例の場合だと、

let rec repeatedly p : Machine<'k, 'o> =
  let inline (>>.) p (next : Lazy<Plan<'k, 'o, 'a>>) = p >>= (fun _ -> next.Value)
  let rec r = lazy (p >>. r)
  r.Value

こうなります。

まずevaluationが発生して欲しい場所を探します。今回の場合は(>>.)演算子でした。
これを、えいやっとシャドウィングしてLazy版を書きます。
あとは何事もなかったように、自己再帰の警告を #nowarn "40" などで消すなり放置しながら残りの部分を実装します。
こうすることで、他の関数には迷惑をかけずにScalaHaskellと同様のことが行えます。

この系統はlazy evaluation(?)の良い勉強になりますね。

type class

  1. fsharp-typeclasses - Emulate Haskell's typeclasses in F# - Google Project Hosting を使う
  2. あきらめて地道な実装を行う

前者は使ったことがないのでどんな感じなのかわかりません。

後者はFSharpx内のいくつかのmoduleに方法を見れば、どんな感じなのか把握できると思います。

あ、IOモナドはあきらめてます。

Nothing型

ScalaのNothing型を表現できる気がしないので、コンパイラのご機嫌を伺いながら(型推論してもらいながら)問題のなさそうな型にします。

おわりに

「F#で理想を追求するって、そういうことよ」