3つの引数を持つ関数

VBAHaskellで3つ以上の引数を持つ関数をファンクタ化したい。 APIのレベルでそれをサポートする気は今のところないので、VBA側で簡易的な対応をした。

Haskell_1_Core.bas にそれをサポートする関数 make_funPointer_with_3_parameters を追加した。

'ユーザ関数をbindファンクタ化する(3つのパラメータを持つ関数)
Function make_funPointer_with_3_parameters(ByVal func1 As LongPtr, _
                                        ByVal func2 As LongPtr, _
                                    ByVal func3 As LongPtr, _
                            ByRef firstParam As Variant, _
                            ByRef secondParam As Variant, _
                            ByRef thirdParam As Variant) As Variant
    If Is_Missing_(firstParam) Or is_placeholder(firstParam) Then
        make_funPointer_with_3_parameters = _
            VBA.Array(func1, _
                      IIf(Is_Missing_(firstParam), placeholder, firstParam), _
                      VBA.Array(secondParam, thirdParam), _
                      placeholder _
                     )
    ElseIf Is_Missing_(secondParam) Or is_placeholder(secondParam) Then
        make_funPointer_with_3_parameters = _
            VBA.Array(func2, VBA.Array(firstParam, thirdParam), _
                      IIf(Is_Missing_(secondParam), placeholder, secondParam), _
                      placeholder _
                     )
    ElseIf Is_Missing_(thirdParam) Or is_placeholder(thirdParam) Then
        make_funPointer_with_3_parameters = _
            VBA.Array(func3, _
                      VBA.Array(firstParam, secondParam), _
                      IIf(Is_Missing_(thirdParam), placeholder, thirdParam), _
                      placeholder _
                     )
    Else
        make_funPointer_with_3_parameters = Empty
    End If
End Function

少しややこしいので、ファイルをコピーする簡単な関数 copyFile で説明する。
copyFile はコピー先フォルダ、コピー元フォルダ、ファイル名を指定してファイルをコピーするだけだが、これまで vbaHaskell では扱っていなかった3パラメータ関数だ。

これを vbaHaskell の mapF に渡すと次のようなことができる。

  • 複数のコピー先フォルダを指定する(バックアップ等で複数の場所にコピーする時など)
    • mapF(p_copyFile( , コピー元フォルダ, ファイル名 ), コピー先フォルダ配列)
  • 複数のファイルを指定する(全ファイルをコピーするなど)
    • mapF(p_copyFile( コピー先フォルダ, コピー元フォルダ ), ファイル名配列)

(コピー元フォルダを複数指定するのはこの場合意味がない)

mapF で実際に呼ばれているのは3通りの補助関数のどれかで、それらは従来通りの2変数関数である。つまり3変数関数と言ってもそのうち2つを配列にパックしているだけのことだ。

' //ファイルのコピー
Function copyFile(ByVal targetDirectory As String, _    ' //コピー先フォルダ
                 ByVal sourceDirectory As String, _    ' //コピー元フォルダ
                  ByVal fileName As String) As Long     ' //ファイル名
    copyFile = 0
    Dim fso As Object
    Set fso = CreateObject("Scripting.FileSystemObject")
    On Error GoTo myError
    fso.copyFile sourceDirectory & "\" & fileName, targetDirectory & "\" & fileName, True
    copyFile = 1
myError:
    Set fso = Nothing
End Function

    ' //ファンクタ化する
    Function p_copyFile(Optional ByRef firstParam As Variant, _
                        Optional ByRef secondParam As Variant, _
                        Optional ByRef thirdParam As Variant) As Variant
        p_copyFile = make_funPointer_with_3_parameters( _
                                    AddressOf copyFile_partial1, _
                                    AddressOf copyFile_partial2, _
                                    AddressOf copyFile_partial3, _
                                    firstParam, _
                                    secondParam, _
                                    thirdParam)
    End Function

    ' //どの引数をプレースホルダにするかによって3通りの補助関数を作る

    ' //第1引数(コピー先フォルダ)をプレースホルダにする
    Private Function copyFile_partial1(ByRef target As Variant, ByRef source_fname As Variant) As Variant
        copyFile_partial1 = copyFile(target, source_fname(0), source_fname(1))
    End Function

    ' //第2引数(コピー元フォルダ)をプレースホルダにする
    Private Function copyFile_partial2(ByRef target As Variant, ByRef source_fname As Variant) As Variant
        copyFile_partial2 = 0   ' こんなコピーは無理
    End Function

    ' //第3引数(ファイル名)をプレースホルダにする
    Private Function copyFile_partial3(ByRef target_source As Variant, ByRef fname As Variant) As Variant
        copyFile_partial3 = copyFile(target_source(0), target_source(1), fname)
    End Function