F#(.. ..)运算符使用/重载

时间:2012-01-13 15:18:49

标签: f# operator-overloading

我有兴趣使用/重载“范围步骤”操作符(.. ..),但我不能为我的生活找到如何使用它。

在文档中说

// Usage:
start .. step .. finish

但是在F#shell中尝试它会产生错误:

> 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..2..7}

3 个答案:

答案 0 :(得分: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'

答案 1 :(得分: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的{​​{1}}更灵活,并且暗示步长为int的范围:

1

答案 2 :(得分:1)

spec § 6.3.12没有明确说明,但给出的唯一例子是在序列表达式中。这一点,以及没有其他工作的事实,似乎证实了你的结论。

仅供参考 - 以下是范围运营商的相关文档。

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

Section 3.8.2还提到(.. ..)的特殊处理,因此可以安全地假设它受限于典型函数/运算符之外的限制/行为。