2012-01-13 23 views
5

Estoy interesado en usar/sobrecargar el operador "range step" (...), pero no puedo saber cómo usarlo eso.F # (.. ..) operador uso/sobrecarga

En la documentación que dice

// Usage: 
start .. step .. finish 

pero tratando de que en el # cáscara F da errores:

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

Sin embargo, calificó de "explícitamente" es posible:

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

val x : seq<int> 

¿Es solo posible usar este operador para la construcción de lista/secuencia como [1..2..7] y??

Respuesta

1

El spec § 6.3.12 no es explícito al respecto, pero los únicos ejemplos dados se encuentran dentro de las expresiones de secuencia. Eso, junto con el hecho de que nada más funciona, parece confirmar su conclusión.

FYI - Aquí están los documentos relevantes para los operadores de la gama.

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

Section 3.8.2 también menciona un manejo especial de (.. ..), por lo que es seguro asumir que es sujeto a limitaciones/comportamiento, aparte de los de funciones/operadores típicos.

+0

Marcado esto como la respuesta aceptada ya que fue el más rápido y todos los demás no agregaron información más relevante. Parece que '(.. ..)' solo puede vivir dentro de 'seq {...}'. - Gracias por leer las especificaciones para mí ;-) – uhrm

2

Los usos de este operador están cubiertos por section 6.3.12 of the spec (Expresiones de rango). El built-in (.. ..) operador trabaja en cualquier tipo con (+) apropiadas y Zero miembros, pero se puede redefinirlo a hacer otra cosa (tenga en cuenta que este ejemplo no tiene sentido):

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

Anulación (... .) operador

Si redefine el operador (.. ..) como en la respuesta de @kvb, anulará ese operador de cualquier tipo. Dado que probablemente desee que el operador (.. ..) trabaje para un tipo de datos personalizado, anular los miembros estáticos (+) y One es suficiente. Por ejemplo, aquí hay un tipo numérico personalizado para la aritmética modular tomado de @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) 

Mientras que la construcción de una partida van desde la cota inferior, (+) y One se utilizan para encontrar el siguiente elemento. La construcción termina cuando el siguiente elemento es igual o superior al límite superior del rango. Ahora se puede emplear en cualquier expresión IntegerZ5 rango:

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] 

Utilizando (.. ..) operador de

Otro uso de la expresión de rango está en for bucles.Me resulta muy útil en muchos casos:

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

porque es más flexible que for...to..do que se limita a solamente int e implica una serie con un paso de 1:

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

Es un buen uso, sobre todo porque, de acuerdo con la especificación, en muchos casos se traduce en un bucle simple. – Daniel

+0

... y funciona para expresiones de rango con paso explícito no igual a 1 también, como en 'for i in 1I..2I..100I printf"% A "i' –

+0

Claro que sí. Es por eso que dije que es más flexible. – pad

Cuestiones relacionadas