2012-01-13 63 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> 

是否只能使用此運算符進行list/seq構造,如[1..2..7]seq {1..2..7}

回答

1

spec § 6.3.12對此沒有明確說明,但僅給出的例子在序列表達式中。這一點,除了沒有別的作用,似乎證實了你的結論。

僅供參考 - 以下是範圍運算符的相關文檔。

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

Section 3.8.2也提到了(.. ..)特殊處理,因此它是安全的假設它是受到限制/行爲除了那些典型的功能/運營商。

+0

標記此作爲公認的答案因爲這是最快的,所有其他人都沒有添加更多相關信息。似乎'(.. ..)'只能存在於'seq {...}'中。 - 感謝您閱讀我的規範;-) – uhrm 2012-01-14 14:10:55

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用於尋找下一個元素的範圍開始。當下一個元素等於或超過範圍的上限時,結構結束。現在,您可以使用IntegerZ5在任何範圍表達式:

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] 

使用(..)運算符

範圍內表達的另一個用途是在for循環。我發現它在很多情況下有用:

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

,因爲它是更靈活的比for...to..do這僅限於int並意味着一個範圍內的1步:

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

這是一個很好的用法,尤其是因爲根據規範,它在許多情況下被轉換爲一個簡單的for循環。 – Daniel 2012-01-13 16:00:04

+0

...它適用於顯式步長不等於1的範圍表達式,就像在1i..2I..100I中執行printf「%A」i''一樣。 – 2012-01-13 17:02:05

+0

確實如此。這就是爲什麼我說它更靈活。 – pad 2012-01-13 17:39:33