F#でSomaを使うメリット その2 : 単位の利用

F#には単位という非常にクールな機能があります。F#でSomaを使えばこの機能が利用でき、わかりやすいプログラムを安全に(コンパイル時にチェックされるので)記述できます。

サンプルを見てみましょう。まず、センチメートル、メートル、キログラム、そしてそれらを利用したBMIの計算処理を行う関数を記述します。

// センチメートル[<Measure>]
type cm =
static member ConvertToMeter(x:decimal<cm>) =
x / 100M<cm> * 1M<m>

// メートルand [<Measure>] m =
static member ConvertToCentiMeter(x:decimal<m>) =
(decimal x) * 100M<cm>

// キログラム[<Measure>]
type kg

// BMIの計算処理let calculateBMI (height:decimal<cm>) (weight:decimal<kg>) =
let height = cm.ConvertToMeter height
weight / (height * height)

ここまでは純粋にF#の機能です。これらの単位や関数をSomaをからめて利用するとこうなります。
  // DBのEMPテーブルとマッピングしたレコード
type Emp =
{ [<Id>]
EmpId : int
EmpName : string
Height : decimal<cm>
Weight : decimal<kg> }

[<Test>]
let ``test measure``() =
// DBへ追加
MsSql.insert<Emp> { EmpId = 1; EmpName = "Smith"; Height = 178.34M<cm>; Weight = 61.89M<kg> }|> ignore
// DBから取得
let emp = MsSql.find<Emp> [1]
let bmi = calculateBMI emp.Height emp.Weight
printfn "BMI : %.2f" (decimal bmi) // BMI : 19.46

Empレコード型にはHeightやWeightというフィールドがありますが、ここにcmとkgの単位があることに注目してください。単位を記述できると、意図がとても明確になりますね。


タイトルにはSomaのメリットと書きましたが、正確にはF#でデータ構造を定義することのメリットです。つまり、データ構造をC#VB.NETで生成するLINQ to SQL や Entity Frameworkのデザイナでクラスを作っているかぎりではこのメリットは得られないということになります。SomaではF#で記述されたレコードをテーブルとマッピングできるためこのメリットをおしみなく享受できるわけです。

というわけで、Somaを使うとF#の「単位」を活かしてDBアクセスできます、という話でした。