Compartir a través de


Instrucciones de formato de código (F#)

En este tema se resumen las instrucciones de sangría del código para F#. Debido a que el lenguaje F# es sensible a los saltos de línea y a las sangrías, dar formato al código correctamente no es una simple cuestión de legibilidad o de estandarización. El formato del código debe ser correcto para que se compile correctamente.

Reglas generales para la sangría

Cuando es necesario utilizar la sangría, se deben utilizar espacios, no tabulaciones. Se necesita como mínimo un espacio. Cada organización puede crear normas de codificación a fin de especificar el número de espacios que se utilizarán para la sangría; lo habitual son tres o cuatro espacios de sangría en cada nivel. Se puede configurar Visual Studio conforme a las normas de sangría de la organización modificando las opciones en el cuadro de diálogo Opciones al que se tiene acceso desde el menú Herramientas. En el nodo Editor de texto, expanda F# y, a continuación, haga clic en Tabulaciones. Para obtener una descripción de las opciones disponibles, vea Tabulaciones, Todos los lenguajes, Editor de texto, Opciones (Cuadro de diálogo).

En general, cuando el compilador analiza el código, mantiene una pila interna que indica el nivel de anidación actual. Cuando se aplica sangría al código, se crea (o inserta) un nuevo nivel de anidación en esta pila interna. Cuando una construcción finaliza, se saca el nivel. La sangría es una manera de indicar el final de un nivel y sacar la pila interna, pero también hay algunos tokens que hacen que se saque el nivel, como la palabra clave end, o una llave o un paréntesis de cierre.

El código de una construcción de varias líneas, como una definición de tipo, una definición de función, una construcción try...with y las construcciones en bucle, se debe aplicar la sangría con relación a la línea de apertura de la construcción. La primera línea con sangría establece una posición de columna para el código subsiguiente de la misma construcción. El nivel de sangría se denomina contexto. La posición de columna establece una columna mínima, denominada línea de contexto, para las líneas de código subsiguientes que están en el mismo contexto. Cuando se encuentra una línea de código que tiene menos sangría que esta posición de columna establecida, el compilador da por hecho que el contexto ha finalizado y que, a continuación, se está codificando en el siguiente nivel superior, en el contexto anterior. El término fuera de contexto se utiliza para describir la situación en que una línea de código desencadena el final de una construcción porque no tiene la sangría suficiente. En otras palabras, el código que se encuentra a la izquierda de la línea de contexto está fuera de contexto. En el código al que se ha aplicado sangría correctamente, se puede sacar partido de la regla de fuera de contexto para delinear el final de las construcciones. Si la sangría se utiliza incorrectamente, una situación de fuera de contexto puede hacer que el compilador emita una advertencia o que el código se interprete de forma incorrecta.

Las líneas de contexto se determinan como sigue.

  • Un token = asociado a let introduce una línea de contexto en la columna del primer token después del signo =.

  • En una expresión if...then...else, la posición de columna del primer token después de la palabra clave then o la palabra clave else introduce una línea de contexto.

  • En una expresión try...with, el primer token después de try introduce una línea de contexto.

  • En una expresión match, el primer token después de with y el primer token después de -> introducen líneas de contexto.

  • El primer token después de with en una extensión de tipo introduce una línea de contexto.

  • El primer token después de una llave o un paréntesis de apertura, o después de la palabra clave begin, introduce una línea de contexto.

  • El primer carácter de las palabras clave let, if y module introduce una línea de contexto.

En los ejemplos de código siguientes se muestran las reglas de sangría. En este caso, las instrucciones de impresión se basan en la sangría para efectuar la asociación al contexto adecuado. Cada vez que la sangría se desplaza, se saca el contexto y se regresa al contexto anterior. Por tanto, se imprime un espacio al final de cada iteración; "Done!" se imprime solo una vez, porque la sangría de fin de contexto establece que no forma parte del bucle. La impresión de la cadena "Top-level context" no forma parte de la función. Así pues, se imprime en primer lugar, durante la inicialización estática, antes de que se llame a la función.

let printList list1 =
    for elem in list1 do
        if elem > 0 then
            printf "%d" elem
        elif elem = 0 then
            printf "Zero"
        else
            printf "(Negative number)"
        printf " "
    printfn "Done!"
printfn "Top-level context."
printList [-1;0;1;2;3]

La salida es la siguiente.

Top-level context

(Negative number) Zero 1 2 3 Done!

Cuando se incluyen saltos en líneas largas, la continuación de la línea debe tener más sangría que la construcción contenedora. Por ejemplo, a los argumentos de función se les debe aplicar más sangría que el primer carácter del nombre de función, como se muestra en el código siguiente.

let myFunction1 a b = a + b
let myFunction2(a, b) = a + b
let someFunction param1 param2 =
    let result = myFunction1 param1
                     param2
    result * 100
let someOtherFunction param1 param2 =
    let result = myFunction2(param1,
                     param2)
    result * 100

Hay excepciones a estas reglas, tal y como se describe en la sección siguiente.

Sangría en los módulos

Se debe aplicar sangría al código de un módulo local con relación al módulo, pero no es necesario aplicársela al código de un módulo de nivel superior. No es preciso aplicar sangría a los elementos de espacio de nombres.

En los siguientes ejemplos de código se muestra cómo hacerlo.

// Program1.fs
// A is a top-level module.
module A

let function1 a b = a - b * b
// Program2.fs
// A1 and A2 are local modules.
module A1 =
    let function1 a b = a*a + b*b

module A2 =
    let function2 a b = a*a - b*b

Para obtener más información, vea Módulos (F#).

Excepciones a las reglas de sangría básicas

La regla general, tal y como se describe en la sección anterior, es que al código de las construcciones de varias líneas se le debe aplicar sangría con relación a la sangría de la primera línea de la construcción, y que el final de la construcción viene determinado por la aparición de la primera línea de contexto. Una excepción a la regla de finalización de contextos se refiere a que algunas construcciones, como la expresión try...with, la expresión if...then...else y el uso de la sintaxis and para declarar funciones o tipos mutuamente recursivos, tienen varias partes. Las partes posteriores, como then y else de una expresión if...then...else, tienen el mismo nivel de sangría que el token que inicia la expresión, pero esto, en lugar de indicar el final del contexto, representa la siguiente parte del mismo contexto. Por consiguiente, una expresión if...then...else se puede escribir como en el ejemplo de código siguiente.

let abs1 x =
    if (x >= 0)
    then
        x
    else
        -x

La excepción a la regla de fuera de contexto únicamente es de aplicación a las palabras clave else y then. Por consiguiente, aunque aplicar más sangría a then y else no es un error, si se deja de aplicar sangría a las líneas de código de un bloque then se genera una advertencia. Esto se muestra en las líneas de código siguientes.

// The following code does not produce a warning.
let abs2 x =
    if (x >= 0)
        then
        x
        else
        -x
// The following code is not indented properly and produces a warning.
let abs3 x =
    if (x >= 0)
    then
    x
    else
    -x

Para el código de un bloque else, se aplica una regla especial más. La advertencia del ejemplo anterior únicamente aparece para el código del bloque then, no en el código del bloque else. Esto permite escribir código que compruebe varias condiciones al principio de una función sin forzar que se aplique sangría al resto del código para la función, que podría estar en un bloque else. Así, puede escribir lo siguiente sin generar una advertencia.

let abs4 x =
    if (x >= 0) then x else
    -x

Otra excepción a la regla de que los contextos finalizan cuando una línea no tiene tanta sangría como la anterior se refiere a los operadores infijos, como + y |>. Se permite que las líneas que empiezan por operadores infijos comiencen (1 + oplength) columnas antes de la posición normal sin desencadenar un final del contexto, donde oplength es el número de caracteres que componen el operador. Esto hace que el primer token después del operador se alinee con la línea anterior.

Por ejemplo, en el código siguiente se permite que al símbolo + se le aplique una sangría de dos columnas menos que a la línea anterior.

let function1 arg1 arg2 arg3 arg4 =
    arg1 + arg2
  + arg3 + arg4

Aunque la sangría suele aumentar a medida que sube el nivel de anidación, hay varias construcciones en las que el compilador permite restablecer la sangría en una posición de columna inferior.

Las construcciones que permiten restablecer la posición de columna son:

  • Cuerpos de funciones anónimas. En el código siguiente, la expresión de impresión se inicia en una posición de columna que está más a la izquierda que la palabra clave fun. Sin embargo, la línea no debe comenzar en una columna situada a la izquierda del principio del nivel de sangría anterior (es decir, a la izquierda de L en List).

    let printListWithOffset a list1 =
        List.iter (fun elem ->
            printfn "%d" (a + elem)) list1
    
  • Las construcciones que van entre paréntesis o entre begin y end en un bloque then o else de una expresión if...then...else, siempre que la sangría no sea inferior a la posición de columna de la palabra clave if. Esta excepción permite un estilo de codificación en el que se utiliza un paréntesis de apertura o begin al final de una línea después de then o else.

  • Cuerpos de módulos, clases, interfaces y estructuras delimitados por begin...end, {...}, class...end o interface...end. Esto permite un estilo en el que la palabra clave de apertura de una definición de tipo puede estar en la misma línea que el nombre de tipo, sin forzar que se aplique al cuerpo completo más sangría que a la palabra clave de apertura.

    type IMyInterface = interface
       abstract Function1: int -> int
    end
    

Vea también

Otros recursos

Referencia del lenguaje F#