はじめに
昨今の多くの言語には三項演算子が実装されています.残念ながらFortranにはありませんが,merge
関数を用いると三項演算子と同じ役割をしてくれます.
三項演算子とは
?: 演算子 - C# リファレンス | Microsoft Docs
condition ? consequent : alternative
?
と:
からなるこの演算子は,condition
がTrue
ならばconsequent
の値を,False
ならばalternative
の値を返します.(正確にはconsequent
あるいはalternative
の式を評価して値を返します.)以下の例の様に簡単な条件分岐をより簡潔に記述できるメリットがあります.
//statusへの代入の分岐を簡潔に書ける
status = condition ? "GOOD" : "BAD";
//上と同じ内容だが5行も必要
if(condition){
status = "GOOD";
}else{
status = "BAD";
}
merge
関数とは
GNU Fortran Compiler: merge
2つの配列を併合させて新しく同じサイズの配列を作り出す関数です.新しい配列の各要素の値には元の配列の値を使用します.2つの配列のうちどちらの値を使用するかをlogical
の配列で指定します.以下に例文とその解説図を示します.
program main
implicit none
integer :: ifT(7), ifF(7),ans(7)
logical :: mask(7), T=.true.,F=.false.
ifT = [ 1, 2, 3, 4, 5, 6, 7]
ifF = [101,102,103,104,105,106,107]
mask = [ T, F, T, T, F, T, F]
ans = merge(ifT, ifF, mask)
print'(7(i0,x))',ans
! 1 102 3 4 105 6 107
end program
merge
関数による疑似的な三項演算子
merge
関数は,引数に配列を与えた場合だけでなく,単一の値を与えた場合にも正常に働きます.これを用いて,疑似的に三項演算子として用いることができます.構文とサンプルのプログラムを示します.上述した一般的な三項演算子とは引数の順序が異なることに注意してください.
merge(consequent, alternative, condition)
program main
implicit none
integer :: ifT, ifF, ans
logical :: flag
flag = .true.
! flag = .false.
ifT = 1
ifF = 2
ans = merge(ifT, ifF, flag)
print'(I0)', ans
! flag==true => ans==1
! flag==false => ans==2
end program
おまけ(ユーザー定義演算子を用いた実装)
三項演算子というのですから,関数ではなく演算子を使いたくないですか?ということでユーザー定義演算子を用いて三項演算子と同じ挙動を目指して実装してみました.
Fortranで定義できる演算子は単項演算子と二項演算子のみで,残念ながら三項演算子を定義することはできません.今回は?
と:
を別に分けてそれぞれ2項演算子として定義することで実装しました.
とても使いにくそうな出来上がりになりました.
module myModule
implicit none
interface operator( .hatena. )
module procedure opHatena
end interface
interface operator( .TorF. )
module procedure opTorF
end interface
type myType
integer :: T, F
end type
contains
type(myType) function opTorF( i1, i2 )
implicit none
integer, intent(in) :: i1, i2
opTorF%T = i1
opTorF%F = i2
end function
integer function opHatena( bool, TorF )
implicit none
logical, intent(in) :: bool
type(myType), intent(in) :: TorF
if(bool)then
opHatena = TorF%T
else
opHatena = TorF%F
end if
end function
end module
program main
use myModule
implicit none
integer :: ifT, ifF, ans
logical :: flag
flag = .false.
ifT = 1
ifF = 2
ans = flag .hatena. (ifT.TorF.ifF)
print'(I0)', ans
! flag==true => ans==1
! flag==false => ans==2
end program