2012-01-13 12 views
5

「レンジステップ」演算子(.. ..)をオーバーロードすることに興味がありますが、私の人生では使用方法を見つけることができませんそれ。ドキュメントでF#(.. ..)演算子の使用/オーバーロード

それは

// Usage: 
start .. step .. finish 

が、F#のシェルでエラーが発生しますことをしようと言う:

> let x = 1 .. 2 .. 7;; 

    let x = 1 .. 2 .. 7;; 
    ----------^^ 

stdin(54,11): error FS0010: Unexpected symbol '..' in binding. Expected incomplete structured construct at or before this point or other token. 

はしかし、 "明示的" それを呼び出すことは可能です:

> let x = (.. ..) 1 2 7;; 

val x : seq<int> 

[1..2..7]とのようなリスト/ seqの構築にのみこの演算子を使うことは可能ですか??

答えて

1

spec § 6.3.12は明示的ではありませんが、唯一の例はシーケンス式の中にあります。それは他に何も働かないという事実と共に、あなたの結論を確認するようです。

FYI - 範囲演算子に関する関連ドキュメントです。

Operators.(..)<^T>
Operators.(.. ..)<^T,^Step>

Section 3.8.2(.. ..)の特別な処理を言及し、それはそれは離れて、典型的な機能/事業者のものと限界/行動の対象だと仮定しても安全です。

+0

それは最速であり、他のすべてのものはより関連性の高い情報を追加しなかったからです。 '(.. ..)'は 'seq {...} '内にしか存在しないようです。 - スペックを読んでくれてありがとうございます;-) – uhrm

2

この演算子の使用方法は、section 6.3.12 of the spec(範囲式)でカバーされています。 (.. ..)オペレータが適切な(+)Zeroメンバーとどのようなタイプで動作しますが、あなたがそれが何かを行うために再定義することができますに内蔵され(この例では無意味であることに注意してください):

let (.. ..) x y z = 
    Seq.map (fun (s:string) -> s.[z] + y) x 

let result = seq { ["test"; "func"] .. (char 1) .. 2 } // contains 't' 'o' 
2

オーバーライド(..を。 。)演算子

(.. ..)演算子を@ kvbの答えのように再定義すると、その演算子はすべての型を上書きします。 (.. ..)をカスタムデータ型の演算子として使用する場合は、スタティック(+)Oneのメンバーをオーバーライドするだけで十分です。例えば、ここ@Tomas's blogから取られたモジュラー算術演算のためのカスタム数値型です:下限の範囲の開始を構築しながら

type IntegerZ5 = 
    | Z5 of int 
    member z.ToInt32() = 
    let (Z5 n) = z in n 
    override z.ToString() = 
    sprintf "%d (mod 5)" (z.ToInt32()) 

    static member Create(n) = 
    let z5 = n % 5 
    Z5(max ((z5 + 5) % 5) z5) 
    static member (+) (Z5 a, Z5 b) = IntegerZ5.Create(a + b) 
    static member (-) (Z5 a, Z5 b) = IntegerZ5.Create(a - b) 
    static member (*) (Z5 a, Z5 b) = IntegerZ5.Create(a * b) 
    static member Zero = Z5 0 
    static member One = Z5 1 

    let inline z5 a = IntegerZ5.Create(a) 

(+)Oneは、次の要素を見つけるために使用されています。次の要素が範囲の上限に等しいかそれを超えると、構築が完了します。範囲式の別の用途は、forループである(..)演算子

を使用して

let s1 = seq{z5 37..z5 3};; // seq [Z5 2; Z5 3] 
    let s2 = seq{z5 10..z5 22..z5 4};; // seq [Z5 0; Z5 2; Z5 4] 

:今、あなたは、任意の範囲式でIntegerZ5を採用することができます。私は多くの場合、それが参考:

let sum = 
    let mutable s = 0L 
    for i in 1L..1000L do (* or 1L..1L..1000L with an explicit step *) 
     s <- s + i 
    s 

それだけintに制限し、1のステップで範囲を意味しているfor...to..doよりも柔軟であるため、:受け入れ答えとしてこれをマークする

let sum = 
    let mutable s = 0L 
    for i = 1L to 1000L do (* doesn't work *) 
     s <- s + i 
    s 
+0

これはうれしいことです。特に仕様に従って、多くの場合単純なforループに変換されています。 – Daniel

+0

...明示的なステップが1にも等しくない範囲式にも有効です。例えば、1I..2I..100Iではprintf "%A" i' –

+0

と同じです。だから、私はそれがより柔軟であると言いました。 – pad

関連する問題