関数Functions

関数は、あらゆるプログラミング言語においてプログラムの実行の基本となる単位です。Functions are the fundamental unit of program execution in any programming language. 他の言語の場合と同様に、F# の関数にもそれぞれ名前と本体があり、パラメーターや引数を受け取ることができます。As in other languages, an F# function has a name, can have parameters and take arguments, and has a body. F# ではさらに、関数型プログラミング構成要素もサポートしています。たとえば、関数を値として処理したり、名前のない関数を式で使用したりできます。また、関数の合成による新しい関数の作成、カリー化関数、関数の引数の部分適用による関数の暗黙の定義などがサポートされます。F# also supports functional programming constructs such as treating functions as values, using unnamed functions in expressions, composition of functions to form new functions, curried functions, and the implicit definition of functions by way of the partial application of function arguments.

関数を定義するには let キーワードを使用します。再帰関数の場合は、let rec というキーワードの組み合わせを使用します。You define functions by using the let keyword, or, if the function is recursive, the let rec keyword combination.

構文Syntax

// Non-recursive function definition.
let [inline] function-name parameter-list [ : return-type ] = function-body
// Recursive function definition.
let rec function-name parameter-list = recursive-function-body

RemarksRemarks

function-name は、関数を表す識別子です。The function-name is an identifier that represents the function. parameter-list は、スペースで区切られた一連のパラメーターで構成されます。The parameter-list consists of successive parameters that are separated by spaces. 「パラメーター」で説明するように、各パラメーターの明示的な型を指定できます。You can specify an explicit type for each parameter, as described in the Parameters section. 特定の引数型を指定しない場合は、コンパイラによって型が関数本体から推測されます。If you do not specify a specific argument type, the compiler attempts to infer the type from the function body. function-body は式で構成されます。The function-body consists of an expression. 関数本体を構成する式は、通常、複数の式から成る複合式で、その最後の式が戻り値になります。The expression that makes up the function body is typically a compound expression consisting of a number of expressions that culminate in a final expression that is the return value. return-type では、コロンの後に戻り値の型を指定します。これは省略可能です。The return-type is a colon followed by a type and is optional. 戻り値の型を明示的に指定しない場合は、コンパイラによって最後の式から特定されます。If you do not specify the type of the return value explicitly, the compiler determines the return type from the final expression.

単純な関数定義は、次のようになります。A simple function definition resembles the following:

let f x = x + 1

この例では、関数の名前は f、引数は x、引数の型は int、関数本体は x + 1、戻り値の型は int です。In the previous example, the function name is f, the argument is x, which has type int, the function body is x + 1, and the return value is of type int.

関数は、inline としてマークできます。Functions can be marked inline. inline の詳細については、「Inline Functions」(インライン関数) を参照してください。For information about inline, see Inline Functions.

スコープScope

モジュール スコープ以外のスコープの任意のレベルでは、値または関数の名前を再利用してもエラーになりません。At any level of scope other than module scope, it is not an error to reuse a value or function name. 名前を再利用する場合、後から宣言した名前が前に宣言した名前をシャドウします。If you reuse a name, the name declared later shadows the name declared earlier. ただし、モジュールの最上位のスコープでは名前が一意である必要があります。However, at the top level scope in a module, names must be unique. たとえば次のコードは、モジュール スコープではエラーになりますが、関数内ではエラーになりません。For example, the following code produces an error when it appears at module scope, but not when it appears inside a function:

let list1 = [ 1; 2; 3]
// Error: duplicate definition.
let list1 = []
let function1 =
   let list1 = [1; 2; 3]
   let list1 = []
   list1

しかし、次のコードはどのスコープ レベルでも許容されます。But the following code is acceptable at any level of scope:

let list1 = [ 1; 2; 3]
let sumPlus x =
// OK: inner list1 hides the outer list1.
   let list1 = [1; 5; 10]
   x + List.sum list1

パラメーターParameters

パラメーターの名前は、関数名の後に指定されます。Names of parameters are listed after the function name. 次の例のように、パラメーターの型を指定できます。You can specify a type for a parameter, as shown in the following example:

let f (x : int) = x + 1

型を指定する場合は、パラメーターの名前の後にコロンで区切って指定します。If you specify a type, it follows the name of the parameter and is separated from the name by a colon. パラメーターの型を省略した場合、パラメーターの型がコンパイラによって推論されます。If you omit the type for the parameter, the parameter type is inferred by the compiler. たとえば、次の関数定義で、1 の型が int であるため、引数 x の型は int と推論されます。For example, in the following function definition, the argument x is inferred to be of type int because 1 is of type int.

let f x = x + 1

ただし、コンパイラは、可能な限り、関数を汎用的にしようとします。However, the compiler will attempt to make the function as generic as possible. たとえば次のようなコードがあるとします。For example, note the following code:

let f x = (x, x)

関数は、任意の型の 1 つの引数からタプルを作成します。The function creates a tuple from one argument of any type. 型が指定されていないために、任意の引数の型と関数を使用できます。Because the type is not specified, the function can be used with any argument type. 詳細については、「自動ジェネリック化」を参照してください。For more information, see Automatic Generalization.

関数本体Function Bodies

関数本体には、ローカル変数と関数の定義を含めることができます。A function body can contain definitions of local variables and functions. それらの変数と関数のスコープは、現在の関数の本体内に限られます。Such variables and functions are in scope in the body of the current function but not outside it. 軽量構文オプションを有効にしている場合は、次の例に示すように、定義が関数本体に含まれていることをインデントによって示す必要があります。When you have the lightweight syntax option enabled, you must use indentation to indicate that a definition is in a function body, as shown in the following example:

let cylinderVolume radius length =
    // Define a local value pi.
    let pi = 3.14159
    length * pi * radius * radius

詳細については、「コードのフォーマットに関するガイドライン」および「Verbose Syntax」 (冗語構文) を参照してください。For more information, see Code Formatting Guidelines and Verbose Syntax.

戻り値Return Values

コンパイラは、関数本体の最後の式を使用して戻り値とその型を特定します。The compiler uses the final expression in a function body to determine the return value and type. 最後の式の型が前の式から推論される場合もあります。The compiler might infer the type of the final expression from previous expressions. 前のセクションの関数 cylinderVolume では、pi の型は、リテラル 3.14159 の型から float と特定されます。In the function cylinderVolume, shown in the previous section, the type of pi is determined from the type of the literal 3.14159 to be float. コンパイラは、pi の型を使用して、式 h * pi * r * r の型が float であると判断します。The compiler uses the type of pi to determine the type of the expression h * pi * r * r to be float. このため、関数全体の戻り値の型が float になります。Therefore, the overall return type of the function is float.

戻り値を明示的に指定するには、次のようにコードを記述します。To specify the return value explicitly, write the code as follows:

let cylinderVolume radius length : float =
   // Define a local value pi.
   let pi = 3.14159
   length * pi * radius * radius

上記のコードが書き込まれると、コンパイラは関数全体に float を適用します。パラメーターの型にも適用する場合は、次のコードを使用します。As the code is written above, the compiler applies float to the entire function; if you mean to apply it to the parameter types as well, use the following code:

let cylinderVolume (radius : float) (length : float) : float

関数の呼び出しCalling a Function

関数を呼び出すには、関数名の後にスペースを入れ、その後にスペースで区切った引数を指定します。You call functions by specifying the function name followed by a space and then any arguments separated by spaces. たとえば、関数 cylinderVolume を呼び出して結果を値 vol に割り当てるには、次のコードを記述します。For example, to call the function cylinderVolume and assign the result to the value vol, you write the following code:

let vol = cylinderVolume 2.0 3.0

引数の部分適用Partial Application of Arguments

指定されている数より少ない数の引数を渡すと、残りの引数を使用する新しい関数が作成されます。If you supply fewer than the specified number of arguments, you create a new function that expects the remaining arguments. これは、カリー化と呼ばれる引数の処理方法で、F# のような関数型プログラミング言語の特徴の 1 つです。This method of handling arguments is referred to as currying and is a characteristic of functional programming languages like F#. たとえば、半径がそれぞれ 2.03.0 の 2 つのパイプを使用しているとします。For example, suppose you are working with two sizes of pipe: one has a radius of 2.0 and the other has a radius of 3.0. 次のようにして、パイプの体積を特定する関数を作成することができます。You could create functions that determine the volume of pipe as follows:

let smallPipeRadius = 2.0
let bigPipeRadius = 3.0

// These define functions that take the length as a remaining
// argument:

let smallPipeVolume = cylinderVolume smallPipeRadius
let bigPipeVolume = cylinderVolume bigPipeRadius

その後、必要に応じて、2 つのサイズのパイプのさまざまな長さを追加の引数として指定します。You would then supply the additional argument as needed for various lengths of pipe of the two different sizes:

let length1 = 30.0
let length2 = 40.0
let smallPipeVol1 = smallPipeVolume length1
let smallPipeVol2 = smallPipeVolume length2
let bigPipeVol1 = bigPipeVolume length1
let bigPipeVol2 = bigPipeVolume length2

再帰関数Recursive Functions

再帰関数はそれらの関数自体を呼び出す関数です。Recursive functions are functions that call themselves. 再帰関数を使用するには、let キーワードの後に rec キーワードを指定する必要があります。They require that you specify the rec keyword following the let keyword. 関数の本体から再帰関数を呼び出す方法は、他の関数呼び出しの場合と変わりません。Invoke the recursive function from within the body of the function just as you would invoke any function call. 次のような再帰関数を計算、 nthフィボナッチ数。The following recursive function computes the nth Fibonacci number. フィボナッチ数列は、古代から知られている数列で、数例の各数値が、前の 2 つの連続する数値の和になります。The Fibonacci number sequence has been known since antiquity and is a sequence in which each successive number is the sum of the previous two numbers in the sequence.

let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)

再帰関数は、特殊な手法 (アキュムレータや継続の使用など) を意識して慎重に使用しないと、プログラム スタックのオーバーフローを引き起こしたり、プログラムの実行効率が低下したりする可能性があります。Some recursive functions might overflow the program stack or perform inefficiently if you do not write them with care and with awareness of special techniques, such as the use of accumulators and continuations.

関数の値Function Values

F# では、すべての関数が値と見なされ、実際に、関数値と呼ばれています。In F#, all functions are considered values; in fact, they are known as function values. 関数は値であるため、他の関数の引数として使用したり、値が使用されるその他のコンテキストで使用したりできます。Because functions are values, they can be used as arguments to other functions or in other contexts where values are used. 次に関数値を引数として受け取る関数の例を示します。Following is an example of a function that takes a function value as an argument:

let apply1 (transform : int -> int ) y = transform y

関数値の型を指定するには、-> トークンを使用します。You specify the type of a function value by using the -> token. このトークンの左側に引数の型を、右側に戻り値の型を指定します。On the left side of this token is the type of the argument, and on the right side is the return value. 上の例の apply1 は、関数 transform を引数として受け取る関数で、transform は、整数を受け取る、別の整数を返す関数です。In the previous example, apply1 is a function that takes a function transform as an argument, where transform is a function that takes an integer and returns another integer. apply1 の使用例を次のコードに示します。The following code shows how to use apply1:

let increment x = x + 1

let result1 = apply1 increment 100

前のコードを実行した後の result の値は 101 になります。The value of result will be 101 after the previous code runs.

複数の引数を指定するには、次の例に示すように、連続する -> トークンで区切ります。Multiple arguments are separated by successive -> tokens, as shown in the following example:

let apply2 ( f: int -> int -> int) x y = f x y

let mul x y = x * y

let result2 = apply2 mul 10 20

結果は 200 になります。The result is 200.

ラムダ式Lambda Expressions

ラムダ式とは、名前のない関数です。A lambda expression is an unnamed function. 前の例では、名前のある関数 incrementmul を定義しましたが、次のように、代わりにラムダ式を使用することもできます。In the previous examples, instead of defining named functions increment and mul, you could use lambda expressions as follows:

let result3 = apply1 (fun x -> x + 1) 100

let result4 = apply2 (fun x y -> x * y ) 10 20

ラムダ式を定義するには、fun キーワードを使用します。You define lambda expressions by using the fun keyword. ラムダ式は関数定義に似ていますが、引数リストと関数本体の区切りに = トークンではなく -> トークンを使用する点が異なります。A lambda expression resembles a function definition, except that instead of the = token, the -> token is used to separate the argument list from the function body. 通常の関数定義と同様に、引数の型は、推論されるようにすることも、明示的に指定することもできます。ラムダ式の戻り値の型も、本体の最後の式の型から推論されます。As in a regular function definition, the argument types can be inferred or specified explicitly, and the return type of the lambda expression is inferred from the type of the last expression in the body. 詳細については、次を参照してください。ラムダ式。funキーワードします。For more information, see Lambda Expressions: The fun Keyword.

関数合成とパイプライン処理Function Composition and Pipelining

F# の関数は、その他の関数から構成することができます。Functions in F# can be composed from other functions. function1function2 という 2 つの関数を合成すると、function1 に続いて function2 を適用する別の関数になります。The composition of two functions function1 and function2 is another function that represents the application of function1 followed the application of function2:

let function1 x = x + 1
let function2 x = x * 2
let h = function1 >> function2
let result5 = h 100

結果は 202 になります。The result is 202.

パイプライン処理を使用すると、複数の関数呼び出しを一連の操作として連結することができます。Pipelining enables function calls to be chained together as successive operations. パイプラインは次のように処理されます。Pipelining works as follows:

let result = 100 |> function1 |> function2

結果は再び 202 になります。The result is again 202.

合成演算子は 2 個の関数を受け取り、関数を返します。これに対し、パイプライン演算子は、関数と引数を受け取り、値を返します。The composition operators take two functions and return a function; by contrast, the pipeline operators take a function and an argument and return a value. 次のコード例は、関数のシグネチャと使用の違いを示すことによって、パイプラインと合成演算子の違いを示しています。The following code example shows the difference between the pipeline and composition operators by showing the differences in the function signatures and usage.

// Function composition and pipeline operators compared.

let addOne x = x + 1
let timesTwo x = 2 * x

// Composition operator
// ( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3
let Compose2 = addOne >> timesTwo

// Backward composition operator
// ( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
let Compose1 = addOne << timesTwo

// Result is 5
let result1 = Compose1 2

// Result is 6
let result2 = Compose2 2

// Pipelining
// Pipeline operator
// ( |> ) : 'T1 -> ('T1 -> 'U) -> 'U
let Pipeline2 x = addOne x |> timesTwo

// Backward pipeline operator
// ( <| ) : ('T -> 'U) -> 'T -> 'U
let Pipeline1 x = addOne <| timesTwo x

// Result is 5
let result3 = Pipeline1 2

// Result is 6
let result4 = Pipeline2 2

オーバーロードの対象となる関数Overloading Functions

関数ではなく型のメソッドをオーバー ロードすることができます。You can overload methods of a type but not functions. 詳細については、「メソッド」を参照してください。For more information, see Methods.

関連項目See also