スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#入門初級編第4回(units of measure(2))

今回のお題は「units of measure(2)」です。
 
最初にいくつか値の型と値を定義しておきます。
 
[<Measure>]
type m //メートル
 
[<Measure>]
type cm //センチメートル
 
[<Measure>]
type s //秒
 
let m3,m2,m1 = 3.0<m>,2.0<m>,1.0<m>;;
let cm3,cm2,cm1 = 300.0<cm>,200.0<cm>,100.0<cm>
let sec3,sec2,sec1 =3.0<s>,2.0<s>,1.0<s> 
 
それでは、単位の変換を説明したいと思います。
 
まずは単位を取り除く変換です。(例えばfloat<m> -> floatという変換です。)
これは普通に
 
> let a = float m3;;
val a : float = 3.0
 
とでもしてやればよいです。
 
次にfloat型の値に単位を付ける変換です。
例えば2.0を2.0<m>にするには次のようにします。
 
> let k = 2.0 * 1.0<m>;;
val k : float<m> = 2.0
 
関数化したいなら、次のようになります。
 
> let toMesM (x:float) =
    1.0<m> * x;;
 
val toMesM : float -> float<m>
 
> toMesM 8.2;;
val it : float<m> = 8.2
 
 
次は単位付きの値同士の変換です。たとえばメートルをセンチに直すとかいう場合です。。
例えば、センチメートルとメートルを相互変換したいのであれば
 
> let R_MtoCM = 100.0<cm/m>;; 
val R_MtoCM : float<cm/m> = 100.0 
 
とでも定義しておいて、 
 
> let a = R_MtoCM * 1.0<m>;; 
val a : float<cm> = 100.0
 
のように使えばできます。
 
逆も
 
> let b = 1.0<cm> / R_MtoCM ;;
val b : float<m> = 0.01
 
のようにできます。
 
次は単位付きの値を引数にする関数です。
まず次の関数を見てください。
 
let sqr (x:float) = x * x
 
これで、sqr 2.0<m>とするとどうなるでしょうか。
 
じつはこれはエラーになります。単位付きの値を関数に渡すには、関数側もその単位まで含めた型注釈が必要となります。
 
> let sqr (x:float<cm>) = x * x;;
val sqr : float<cm> -> float<cm ^ 2>
 
> sqr 2.0<cm>;;
val it : float<cm ^ 2> = 4.0
 
しかし、単位にかかわらず上のようなよく使う関数については、ジェネリックを利用して次のように定義しておいけば適用範囲が広がります。
 
let sqr2 (x:float<'u>) = x * x 
 
> sqr2 2.0<cm>;;
val it : float<cm ^ 2> = 4.0
 
> sqr2 2.0<m>;;
val it : float<m ^ 2> = 4.0
 
(注)let sqr2 (x:'a<'u>) = x * x とは定義できないみたいです。
 
ちなみに、単位部分にワイルドカードをつかうと、この部分も推論してくれます。
 
> let sqr2 (x:float<_>) = x * x;;
val sqr2 : float<'u> -> float<'u ^ 2>
 
 
最後にジェネリックな単位付き型の定義について説明します。
 
以前次のようなクラスを定義しました。
 
type Vec2D (x : float,y:float) = 
 
    member this.ShowContents 
                = printfn "x = %f y = %f" x y 
    member this.X = x 
    member this.Y = y 
    member this.Length = 
            let sqr r = r * r 
            sqrt <| sqr x + sqr y 
 
これを単位付きの値に対して定義しなおしてみます。
 
type Vec2D< [<Measure>] 'u> (x : float<'u>,y:float<'u>) = 
 
    member this.ShowContents ()
                = printfn "x = %A y = %A" x y 
    member this.X = x 
    member this.Y = y 
    member this.Length = 
            let sqr r = r * r 
            sqrt <| sqr x + sqr y 
 
変更点は一行目のVec2Dのあとの< [<Measure>] 'u>と、floatの後の<'u>と、printfnの後の%fが%Aに変わった点です。
 
まずは単位をmとして使ってみます。
 
> let t = new Vec2D<m> (3.0<m> ,4.0<m>);;
val t : Vec2D<m>
 
> t.ShowContents();;
x = 3.0 y = 4.0
val it : unit = ()
 
> t.X;;
val it : float<m> = 3.0
 
> t.Length;;
val it : float<m> = 5.0
 
次は単位をcmとして使ってみます。
 
> let s = new Vec2D<cm> (3.0<cm> ,4.0<cm>);;
val s : Vec2D<cm>
 
> s.ShowContents();;
x = 3.0 y = 4.0
val it : unit = ()
 
> s.X;;
val it : float<cm> = 3.0
 
> s.Length;;
val it : float<cm> = 5.0
 
最後に注意ですが、他の.NET言語(C#等)と相互運用するときは、単位付きの値はF#以外では単位を抜いた値(例えば3.0<m>は単なる3.0として取り扱われますので、注意が必要です。
 
参考サイト Andrew Kennedy's Blog http://blogs.msdn.com/andrewkennedy/default.aspx
 
ちなみに上のサイトでは単位推論?のすごい例が載ってました。以下のようなものです。
 
> let silly (x:float<_>) (y:float<_>) (z:float<_>)= x*x + y*y*y + z*z*z*z*z;;
 
val silly :
  float<'u ^ 15> -> float<'u ^ 10> -> float<'u ^ 6> -> float<'u ^ 30>

 

スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

No title

単位を付ける変換:
意味のないことですが、
例えば、
let intTointM (x:int) = ((x :> obj) :?>int<m>)
のようにキャストできるようです。
これでいうと、int<m> が1つの型だとわかります。
それで、
>(注)let sqr2 (x:'a<'u>) = x * x とは定義できない
で、
let sqr2 (x:'a) = x * x
とかして、、、とか思っても、
これ自体ができません。
いわゆる四則演算(op 関数)は、コンパイル時に型が決まってないといけないです。
Gushwell さんのところでもそういう話になりました。
http://techbank.jp/Community/blogs/gushwell/archive/2009/10/12/19448.aspx#19572
まあ、'a<'u> という書き方自体できないみたいですけど・

No title

へーint<m>も型なのですね。知らなかったです。
あと四則演算がらみもふくめて、静的型付け言語には、動的言語にはない面が悩ましい部分がありますね。

int<m>も型?

>へーint<m>も型なのですね。知らなかったです。
まあ、素人の言うことなんで、話半分で・
でもまあ、
例えば
typeof<m>
とすると、「想定している型ではない、unit-of-measure は、だめだ」(意訳)と言われますね。
typeof<int<m>>
は、できます。
この結果をみると、型としては、単なるSystem.Int32 だとわかりますね。
プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。