Нет переноса скалярных аргументов в массивы в Fortran

#fortran #overloading #fortran90

#fortran #перегрузка #fortran90

Вопрос:

Почему Fortran передает скалярное выражение в массив в выражении, но не в качестве аргумента процедуры? В частности, почему орган по стандартизации принял это проектное решение? Это исключительно из-за двусмысленности, должна ли процедура быть перегружена? Может ли сообщение об ошибке в этой ситуации быть альтернативным подходом?

Например, в приведенном ниже коде последнее утверждение x = foo(7) выдает ошибку GFortran: Error: Rank mismatch in argument 'a' at (1) (1 and 0) .

 module m

  public :: foo

  contains

  function foo(a) result(b)
    integer, dimension(:)       :: a
    integer, dimension(size(a)) :: b
    b = a 1
  end function foo

end module m

program p

  use m

  integer, dimension(4) :: x
  integer, parameter, dimension(4) :: y = (/1,2,3,4/)

  x = 7
  x = foo(x)
  x = foo(y)
  x = foo(x   7)
  x = foo(7)

end program p
  

Этот вопрос должен был задавать вопрос о том, почему назначение массива приведет источник скалярного значения к целевому массиву; в отличие от функции массива. Я ожидаю, что это просто удобный частный случай. Любые комментарии, с благодарностью полученные в шапках ниже.

Ответ №1:

Если вы хотите, чтобы функция обрабатывала аргументы scaler и array, объявите ее как «элементарную» и с фиктивными аргументами scaler. Тогда он сможет обрабатывать как фактические аргументы scaler, так и массива, включая выражения scaler. Это удовлетворит ваши потребности?

Изменение:

   elemental function foo(a) result(b)
    integer, intent (in)      :: a
    integer :: b
    b = a 1
  end function foo
  

Возможно, они предоставили способ сделать то, что вы хотите, и одного способа было достаточно?

Комментарии:

1. Это, вероятно, не такое общее, как хочет OP, поскольку elemental накладывает множество ограничений на то, что может делать функция.

2. Да, конечно. Большинство встроенных функций являются элементарными, не так ли. И элементарной функции требуется arity > 1, чтобы таким образом продвинуть скаляр в массив. Мой вопрос был бы лучше сфокусирован на операторе присваивания, который будет продвигать скаляр. Но это имеет больше смысла: оператор присваивания является специальным. В последнее время я просматривал слишком много APL…

Ответ №2:

Вызов процедуры в Fortran с явными интерфейсами (которые вы получаете автоматически при использовании процедур модуля) требует соответствия TKR (тип, вид, ранг). Поскольку массив отличается от скалярного типа, не говоря уже о несоответствии ранга, это недопустимо.

Это из-за двусмысленности, должна ли процедура быть перегружена?

Это было бы проблемой, да.

Может ли сообщение об ошибке в этой ситуации быть альтернативным подходом?

Могут ли существовать розовые единороги? Возможно, но, насколько мне известно, они этого не делают. Итак, стандарт Fortran в настоящее время требует сопоставления TKR, и, следовательно, соответствующий стандарту компилятор должен обеспечить выполнение этого требования. Если вы хотите это изменить, я рекомендую внести предложение в комитет по стандартам.

Комментарии:

1. Спасибо janneb. Я ценю ваш ответ, но я на самом деле ищу «почему».

Ответ №3:

Я бы подумал, что ответ на это довольно ясен. Давайте немного изменим ваш пример:

 module m

  public :: foo

  contains

  function foo(a) result(b)
    integer, dimension(:)       :: a
    integer, dimension(size(a)) :: b
    b = a 1
    a(2) = -777     ! new line; modify one element
  end function foo

end module m

program p

  use m

  integer :: x
  integer, dimension(4) :: y 

  x = 7
  y = foo(x)  ! pass a scalar

end program p
  

каким должен быть x после вызова foo?

Теперь, конечно, вы могли бы изменить семантику передачи аргументов в зависимости от того, является ли это intent(in) переменной, но это не то, что прояснит ситуацию для программистов.

Если предполагается, что вызов функции каким-то образом «распределяется» по элементам массива, то, как указывает MSB, elemental — это правильный путь. В противном случае просто убедитесь, что ваши аргументы соответствуют вашим параметрам.

Комментарии:

1. Спасибо. Я думал, что аргумент будет intent(in) . Вот почему я включил parameter аргумент, y . Как вы говорите, elemental это правильный путь.