Buscar..


Observaciones

Las funciones y las subrutinas , junto con los módulos , son las herramientas para dividir un programa en unidades. Esto hace que el programa sea más legible y manejable. Cada una de estas unidades puede considerarse como parte del código que, idealmente, podría compilarse y probarse de forma aislada. Los programas principales pueden llamar (o invocar) a dichos subprogramas (funciones o subrutinas) para realizar una tarea.

Las funciones y las subrutinas son diferentes en el siguiente sentido:

  • Las funciones devuelven un solo objeto y, generalmente, no alteran los valores de sus argumentos (es decir, ¡actúan como una función matemática);
  • Las subrutinas generalmente realizan una tarea más complicada y generalmente alteran sus argumentos (si hay alguno presente), así como otras variables (por ejemplo, aquellas declaradas en el módulo que contiene la subrutina).

Las funciones y subrutinas van colectivamente bajo el nombre de procedimientos . (En lo siguiente, usaremos el verbo "call" como sinónimo de "invocar" incluso si técnicamente los procedimientos a ser call son subroutine , mientras que las function s aparecen como parte derecha de la asignación o en expresiones).

Sintaxis funcional

Las funciones se pueden escribir utilizando varios tipos de sintaxis.

function name()
  integer name
  name = 42
end function
integer function name()
  name = 42
end function
function name() result(res)
  integer res
  res = 42
end function

Las funciones devuelven valores a través de un resultado de función . A menos que la declaración de función tenga una cláusula de result el result la función tendrá el mismo nombre que la función. Con result el result la función es el dado por el result . En cada uno de los dos primeros ejemplos anteriores, el resultado de la función viene dado por name ; en el tercero por res .

El resultado de la función debe definirse durante la ejecución de la función.

Las funciones permiten utilizar algunos prefijos especiales.

Función pura significa que esta función no tiene ningún efecto secundario:

pure real function square(x)
  real, intent(in) :: x
  square = x * x
end function

La función elemental se define como operador escalar, pero se puede invocar con array como argumento real, en cuyo caso la función se aplicará de forma elemental. A menos que se especifique el prefijo impure (introducido en Fortran 2008), una función elemental también es una función pura .

elemental real function square(x)
  real, intent(in) :: x
  square = x * x
end function

Declaración de devolución

La declaración de return se puede utilizar para salir de la función y la subrutina. A diferencia de muchos otros lenguajes de programación, no se utiliza para establecer el valor de retorno.

real function f(x)
  real, intent(in) :: x
  integer :: i

  f = x

  do i = 1, 10

    f = sqrt(f) - 1.0

    if (f < 0) then
      f = -1000.
      return
    end if

  end do
end function

Esta función realiza un cálculo iterativo. Si el valor de f vuelve negativo, la función devuelve el valor -1000.

Procedimientos recursivos

En Fortran, las funciones y las subrutinas deben declararse explícitamente como recursivas , si han de llamarse a sí mismas de nuevo, directa o indirectamente. Por lo tanto, una implementación recursiva de la serie Fibonacci podría tener este aspecto:

recursive function fibonacci(term) result(fibo)
  integer, intent(in) :: term
  integer :: fibo

  if (term <= 1) then
    fibo = 1
  else
    fibo = fibonacci(term-1) + fibonacci(term-2)
  end if
  
end function fibonacci

Otro ejemplo es permitido calcular factorial:

recursive function factorial(n)  result(f)
  integer :: f
  integer, intent(in) :: n
  
  if(n == 0) then
    f = 1
  else
    f = n * f(n-1)
  end if
end function factorial

Para que una función se refiera directamente a sí misma, su definición debe usar el sufijo de result . No es posible que una función sea tanto recursive como elemental .

La intención de los argumentos ficticios

El atributo de intent de un argumento ficticio en una subrutina o función declara su uso previsto. La sintaxis es una de

intent(IN)
intent(OUT)
intent(INOUT)

Por ejemplo, considere esta función:

real function f(x)
  real, intent(IN) :: x

  f = x*x
end function

La intent(IN) especifica que el argumento ficticio (sin puntero) x nunca se puede definir o perder su definición a lo largo de la función o su inicialización. Si un argumento ficticio de puntero tiene el atributo intent(IN) , esto se aplica a su asociación.

intent(OUT) para un argumento ficticio no puntero significa que el argumento ficticio se convierte en indefinido en la invocación del subprograma (a excepción de cualquier componente de un tipo derivado con inicialización predeterminada) y se debe establecer durante la ejecución. El argumento real pasado como argumento ficticio debe ser definible: no se permite pasar una constante con nombre o literal, o una expresión.

De forma similar a antes, si un argumento ficticio de puntero es intent(OUT) el estado de asociación del puntero se vuelve indefinido. El argumento real aquí debe ser una variable de puntero.

intent(INOUT) especifica que el argumento real es definible y es adecuado para pasar y devolver datos del procedimiento.

Finalmente, un argumento ficticio puede estar sin el atributo de intent . Tal argumento ficticio tiene su uso limitado por el argumento real pasado.

Por ejemplo, considere

integer :: i = 0
call sub(i, .TRUE.)
call sub(1, .FALSE.)

end

subroutine sub(i, update)
  integer i
  logical, intent(in) :: update
  if (update) i = i+1
end subroutine

El argumento i puede tener ningún atributo de intent que permita las dos llamadas de subrutina del programa principal.

Haciendo referencia a un procedimiento

Para que una función o subrutina sea útil debe ser referenciada. Se hace referencia a una subrutina en una instrucción de call

call sub(...)

y una función dentro de una expresión. A diferencia de muchos otros idiomas, una expresión no forma una declaración completa, por lo que una referencia de función se ve a menudo en una instrucción de asignación o se usa de alguna otra manera:

x = func(...)
y = 1 + 2*func(...)

Hay tres formas de designar un procedimiento al que se hace referencia:

  • como el nombre de un procedimiento o puntero de procedimiento
  • un componente de procedimiento de un objeto de tipo derivado
  • un nombre de enlace de procedimiento vinculado

El primero puede verse como

procedure(), pointer :: sub_ptr=>sub
call sub()   ! With no argument list the parentheses are optional
call sub_ptr()
end

subroutine sub()
end subroutine

y los dos últimos como

module mod
  type t
    procedure(sub), pointer, nopass :: sub_ptr=>sub
  contains
    procedure, nopass :: sub
  end type

contains

  subroutine sub()
  end subroutine

end module

use mod
type(t) x
call x%sub_ptr()   ! Procedure component
call x%sub()       ! Binding name

end

Para un procedimiento con argumentos ficticios, la referencia requiere argumentos reales correspondientes, aunque es posible que no se proporcionen argumentos ficticios opcionales.

Considere la subrutina

subroutine sub(a, b, c)
  integer a, b
  integer, optional :: c
end subroutine

Esto puede ser referenciado de las siguientes dos maneras

call sub(1, 2, 3)   ! Passing to the optional dummy c
call sub(1, 2)      ! Not passing to the optional dummy c

Esto se denomina referencia de posición : los argumentos reales se asocian según la posición en las listas de argumentos. Aquí, el dummy a está asociado con 1 , b con 2 y c (cuando se especifica) con 3 .

Alternativamente, la referencia de palabras clave se puede usar cuando el procedimiento tiene una interfaz explícita disponible

call sub(a=1, b=2, c=3)
call sub(a=1, b=2)

que es lo mismo que el anterior.

Sin embargo, con palabras clave los argumentos reales se pueden ofrecer en cualquier orden

call sub(b=2, c=3, a=1)
call sub(b=2, a=1)

Se pueden usar referencias posicionales y de palabras clave.

call sub(1, c=3, b=2)

siempre que se proporcione una palabra clave para cada argumento después de la primera aparición de una palabra clave

call sub(b=2, 1, 3)  ! Not valid: all keywords must be specified

El valor de la referencia de palabras clave es particularmente pronunciado cuando hay múltiples argumentos ficticios opcionales, como se ve a continuación si en la definición de subrutina anterior b también eran opcionales

call sub(1, c=3)  ! Optional b is not passed

Las listas de argumentos para procedimientos vinculados a tipo o punteros de procedimiento de componente con un argumento pasado se consideran por separado.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow