F#-クイックガイド

F#は関数型プログラミング言語です。F#構造を理解するには、という名前のプログラミングパラダイムに関する数行を読む必要があります。Functional Programming

関数型プログラミングは、コンピュータープログラムを数学関数として扱います。関数型プログラミングでは、変数や状態ではなく、定数や関数に焦点が当てられます。関数と定数は変わらないものだからです。

関数型プログラミングでは、モジュラープログラムを作成します。つまり、プログラムは、他の関数を入力として受け取る関数で構成されます。

関数型プログラミング言語で書かれたプログラムは簡潔になる傾向があります。

F#について

以下は、F#に関する基本情報です。

  • 2005年にMicrosoftResearchで開発されました。
  • これは、Microsoftの.Net言語ファミリの一部です。
  • 関数型プログラミング言語です。
  • 関数型プログラミング言語OCamlに基づいています。

F#の特徴

  • OCamlの.Net実装です。

  • これは、CLR(共通言語ランタイム)で実行される.Net CLI(共通言語インターフェイス)バイトコードまたはMSIL(Microsoft中間言語)をコンパイルします。

  • 型推論を提供します。

  • 豊富なパターンマッチング構造を提供します。

  • インタラクティブなスクリプトおよびデバッグ機能があります。

  • 高階関数を書くことができます。

  • 十分に開発されたオブジェクトモデルを提供します。

F#の使用

F#は通常、次の分野で使用されます-

  • 科学モデルの作成
  • 数学的問題解決
  • 人工知能の研究活動
  • 財務モデリング
  • グラフィックデザイン
  • CPU設計
  • コンパイラプログラミング
  • Telecommunications

また、CRUDアプリ、Webページ、GUIゲーム、その他の汎用プログラムでも使用されます。

この章では、F#プログラミングに必要なツールについて説明します。

F#用の統合開発環境(IDE)

Microsoftは、F#プログラミング用のVisual Studio2013を提供しています。

無料のVisualStudio 2013 Community Editionは、Microsoftの公式Webサイトから入手できます。Visual Studio 2013コミュニティ以降には、Visual F#ツールが付属しています。インストールの詳細は、Asp.netチュートリアルで入手できます。VisualF#ツールには、コマンドラインコンパイラ(fsc.exe)とF#インタラクティブ(fsi.exe)が含まれています。

これらのツールを使用すると、単純なコマンドラインアプリケーションからより複雑なアプリケーションまで、あらゆる種類のF#プログラムを作成できます。Notepadなどの基本的なテキストエディターを使用してF#ソースコードファイルを記述し、コマンドラインコンパイラを使用してコードをアセンブリにコンパイルすることもできます。

Microsoft VisualStudioからダウンロードできます。それはあなたのマシンに自動的にインストールされます。

リンクにF#プログラムを書く

ツールをDebianパッケージとして入手する、またはソースから直接コンパイルするための最新の手順については、F#の公式Webサイトにアクセスしてください。 https://fsharp.org/use/linux/.

F#は関数型プログラミング言語です。

F#では、関数はデータ型のように機能します。他の変数と同じように関数を宣言して使用できます。

一般に、F#アプリケーションには特定のエントリポイントはありません。コンパイラーは、ファイル内のすべての最上位ステートメントを上から下に実行します。

ただし、手続き型プログラミングスタイルに従うために、多くのアプリケーションは、メインループを呼び出す単一のトップレベルステートメントを保持します。

次のコードは、単純なF#プログラムを示しています-

open System
(* This is a multi-line comment *)
// This is a single-line comment

let sign num =
   if num > 0 then "positive"
   elif num < 0 then "negative"
   else "zero"

let main() =
   Console.WriteLine("sign 5: {0}", (sign 5))

main()

プログラムをコンパイルして実行すると、次の出力が生成されます。

sign 5: positive

注意してください-

  • F#コードファイルは、次の番号で始まる場合があります open 名前空間のインポートに使用されるステートメント。

  • ファイルの本体には、アプリケーションのビジネスロジックを実装する他の関数が含まれています。

  • メインループには、上位の実行可能ステートメントが含まれています。

F#プログラムの基本構造を見てきましたので、F#プログラミング言語の他の基本的な構成要素を理解するのは簡単です。

F#のトークン

F#プログラムは、さまざまなトークンで構成されています。トークンには、キーワード、識別子、定数、文字列リテラル、または記号を使用できます。F#トークンは2つのタイプに分類できます-

  • Keywords
  • 記号と演算子

F#キーワード

次の表に、キーワードとキーワードの簡単な説明を示します。これらのキーワードの使用については、以降の章で説明します。

キーワード 説明
abstract 宣言されたタイプに実装がないか、仮想でデフォルトの実装があるメソッドを示します。
and 相互再帰的なバインディング、プロパティ宣言、およびジェネリックパラメーターに対する複数の制約で使用されます。
as 現在のクラスオブジェクトにオブジェクト名を付けるために使用されます。パターンマッチ内のパターン全体に名前を付けるためにも使用されます。
assert デバッグ中にコードを検証するために使用されます。
base 基本クラスオブジェクトの名前として使用されます。
begin 詳細構文では、コードブロックの開始を示します。
class 詳細構文では、クラス定義の開始を示します。
default 抽象メソッドの実装を示します。仮想メソッドを作成するために抽象メソッド宣言と一緒に使用されます。
delegate デリゲートを宣言するために使用されます。
do ループ構造で、または命令型コードを実行するために使用されます。
done 詳細構文では、ループ式のコードブロックの終わりを示します。
downcast 継承チェーンの下位の型に変換するために使用されます。
downto for 式。逆に数えるときに使用されます。
elif 条件分岐で使用されます。elseifの短縮形。
else 条件分岐で使用されます。
end

タイプ定義およびタイプ拡張で、メンバー定義のセクションの終わりを示します。

詳細構文で、beginキーワードで始まるコードブロックの終わりを指定するために使用されます。

exception 例外タイプを宣言するために使用されます。
extern 宣言されたプログラム要素が別のバイナリまたはアセンブリで定義されていることを示します。
false ブールリテラルとして使用されます。
finally 例外が発生するかどうかに関係なく実行されるコードのブロックを導入しようと一緒に使用されます。
for ループ構造で使用されます。
fun ラムダ式で使用され、無名関数とも呼ばれます。
function funキーワードの短い代替手段として使用され、単一の引数でパターンマッチングが行われるラムダ式の一致式。
global トップレベルの.NET名前空間を参照するために使用されます。
if 条件分岐構造で使用されます。
in シーケンス式に使用され、詳細な構文では、式をバインディングから分離するために使用されます。
inherit 基本クラスまたは基本インターフェースを指定するために使用されます。
inline 呼び出し元のコードに直接統合する必要がある関数を示すために使用されます。
interface インターフェイスの宣言と実装に使用されます。
internal メンバーがアセンブリの内側に表示され、アセンブリの外側には表示されないように指定するために使用されます。
lazy 結果が必要な場合にのみ実行される計算を指定するために使用されます。
let 名前を値または関数に関連付ける、またはバインドするために使用されます。
let! 非同期ワークフローで名前を非同期計算の結果にバインドするために使用されます。または、他の計算式で、名前を計算タイプの結果にバインドするために使用されます。
match 値をパターンと比較して分岐するために使用されます。
member オブジェクトタイプでプロパティまたはメソッドを宣言するために使用されます。
module 名前を関連するタイプ、値、および関数のグループに関連付けて、他のコードから論理的に分離するために使用されます。
mutable 変数、つまり変更可能な値を宣言するために使用されます。
namespace 名前を関連するタイプおよびモジュールのグループに関連付けて、他のコードから論理的に分離するために使用されます。
new

オブジェクトを作成する、または作成できるコンストラクターを宣言、定義、または呼び出すために使用されます。

型に特定のコンストラクターが必要であることを示すために、ジェネリックパラメーター制約でも使用されます。

not 実際にはキーワードではありません。ただし、構造体を組み合わせて使用​​することは、一般的なパラメーター制約として使用されません。
null

オブジェクトがないことを示します。

一般的なパラメーター制約でも使用されます。

of 値のカテゴリのタイプを示すために識別された共用体で使用され、デリゲートおよび例外宣言で使用されます。
open 名前空間またはモジュールのコンテンツを修飾なしで使用できるようにするために使用されます。
or

ブール条件でブールまたは演算子として使用されます。||と同等です。

メンバー制約でも使用されます。

override 基本バージョンとは異なるバージョンの抽象メソッドまたは仮想メソッドを実装するために使用されます。
private メンバーへのアクセスを、同じタイプまたはモジュールのコードに制限します。
public タイプ外からのメンバーへのアクセスを許可します。
rec 関数が再帰的であることを示すために使用されます。
return 計算式の結果として提供する値を示すために使用されます。
return! 評価時に、含まれている計算式の結果を提供する計算式を示すために使用されます。
select クエリ式で使用して、抽出するフィールドまたは列を指定します。これはコンテキストキーワードであることに注意してください。つまり、実際には予約語ではなく、適切なコンテキストでキーワードのように機能するだけです。
static タイプのインスタンスなしで呼び出すことができるメソッドまたはプロパティ、またはタイプのすべてのインスタンス間で共有される値メンバーを示すために使用されます。
struct

構造型を宣言するために使用されます。

一般的なパラメーター制約でも使用されます。

モジュール定義のOCaml互換性のために使用されます。

then

条件式で使用されます。

オブジェクト構築後の副作用の実行にも使用されます。

to 範囲を示すためにforループで使用されます。
true ブールリテラルとして使用されます。
try 例外を生成する可能性のあるコードのブロックを導入するために使用されます。一緒に使用してか、最終的には。
type クラス、レコード、構造、識別された共用体、列挙型、測定単位、または型の省略形を宣言するために使用されます。
upcast 継承チェーンの上位にある型に変換するために使用されます。
use リソースを解放するためにDisposeを呼び出す必要がある値に対してletの代わりに使用されます。
use! letの代わりに使用!リソースを解放するためにDisposeを呼び出す必要がある値の非同期ワークフローおよびその他の計算式。
val 限られた状況で、値を示すための署名、またはメンバーを宣言するための型で使用されます。
void .NETvoidタイプを示します。他の.NET言語と相互運用するときに使用されます。
when パターン一致のブール条件(ガードの場合)に使用され、ジェネリック型パラメーターの制約節を導入します。
while ループ構造を導入します。
with パターンマッチング式でmatchキーワードと一緒に使用されます。オブジェクト式、レコードコピー式、および型拡張で使用され、メンバー定義を導入し、例外ハンドラーを導入します。
yield シーケンスの値を生成するためにシーケンス式で使用されます。
yield! 計算式で使用され、特定の計算式の結果を、含まれている計算式の結果のコレクションに追加します。

いくつかの予約キーワードはOCaml言語から来ました-

asr 土地 lor lsl lsr lxor モッド sig

他のいくつかの予約済みキーワードは、F#の将来の拡張のために保持されます。

アトミック ブレーク チェック済み 成分 const 制約 constructor
continue eager event external fixed functor include
method mixin object parallel process protected pure
sealed tailcall trait virtual volatile

Comments in F#

F# provides two types of comments −

  • One line comment starts with // symbol.
  • Multi line comment starts with (* and ends with *).

A Basic Program and Application Entry Point in F#

Generally, you don’t have any explicit entry point for F# programs. When you compile an F# application, the last file provided to the compiler becomes the entry point and all top level statements in that file are executed from top to bottom.

A well-written program should have a single top-level statement that would call the main loop of the program.

A very minimalistic F# program that would display ‘Hello World’ on the screen −

(* This is a comment *)
(* Sample Hello World program using F# *)
printfn "Hello World!"

When you compile and execute the program, it yields the following output −

Hello World!

The data types in F# can be classified as follows −

  • Integral types
  • Floating point types
  • Text types
  • Other types

Integral Data Type

The following table provides the integral data types of F#. These are basically integer data types.

F# Type Size Range Example Remarks
sbyte 1 byte -128 to 127

42y

-11y

8-bit signed integer
byte 1 byte 0 to 255

42uy

200uy

8-bit unsigned integer
int16 2 bytes -32768 to 32767

42s

-11s

16-bit signed integer
uint16 2 bytes 0 to 65,535

42us

200us

16-bit unsigned integer
int/int32 4 bytes -2,147,483,648 to 2,147,483,647

42

-11

32-bit signed integer
uint32 4 bytes 0 to 4,294,967,295

42u

200u

32-bit unsigned integer
int64 8 bytes -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

42L

-11L

64-bit signed integer
uint64 8 bytes 0 to 18,446,744,073,709,551,615

42UL

200UL

64-bit unsigned integer
bigint At least 4 bytes any integer

42I

1499999

9999999

9999999

9999999

9999I

arbitrary precision integer

Example

(* single byte integer *)
let x = 268.97f
let y = 312.58f
let z = x + y

printfn "x: %f" x
printfn "y: %f" y
printfn "z: %f" z

(* unsigned 8-bit natural number *)

let p = 2uy
let q = 4uy
let r = p + q

printfn "p: %i" p
printfn "q: %i" q
printfn "r: %i" r

(* signed 16-bit integer *)

let a = 12s
let b = 24s
let c = a + b

printfn "a: %i" a
printfn "b: %i" b
printfn "c: %i" c

(* signed 32-bit integer *)

let d = 212l
let e = 504l
let f = d + e

printfn "d: %i" d
printfn "e: %i" e
printfn "f: %i" f

When you compile and execute the program, it yields the following output −

x: 1
y: 2
z: 3
p: 2
q: 4
r: 6
a: 12
b: 24
c: 36
d: 212
e: 504
f: 716

Floating Point Data Types

The following table provides the floating point data types of F#.

F# Type Size Range Example Remarks
float32 4 bytes ±1.5e-45 to ±3.4e38

42.0F

-11.0F

32-bit signed floating point number (7 significant digits)
float 8 bytes ±5.0e-324 to ±1.7e308

42.0

-11.0

64-bit signed floating point number (15-16 significant digits)
decimal 16 bytes ±1.0e-28 to ±7.9e28

42.0M

-11.0M

128-bit signed floating point number (28-29 significant digits)
BigRational At least 4 bytes Any rational number.

42N

-11N

Arbitrary precision rational number. Using this type requires a reference to FSharp.PowerPack.dll.

Example

(* 32-bit signed floating point number *)
(* 7 significant digits *)

let d = 212.098f
let e = 504.768f
let f = d + e

printfn "d: %f" d
printfn "e: %f" e
printfn "f: %f" f

(* 64-bit signed floating point number *)
(* 15-16 significant digits *)
let x = 21290.098
let y = 50446.768
let z = x + y

printfn "x: %g" x
printfn "y: %g" y
printfn "z: %g" z

When you compile and execute the program, it yields the following output −

d: 212.098000
e: 504.768000
f: 716.866000
x: 21290.1
y: 50446.8
z: 71736.9

Text Data Types

The following table provides the text data types of F#.

F# Type Size Range Example Remarks
char 2 bytes U+0000 to U+ffff

'x'

'\t'

Single unicode characters
string 20 + (2 * string's length) bytes 0 to about 2 billion characters

"Hello"

"World"

Unicode text

Example

let choice = 'y'
let name = "Zara Ali"
let org = "Tutorials Point"

printfn "Choice: %c" choice
printfn "Name: %s" name
printfn "Organisation: %s" org

When you compile and execute the program, it yields the following output −

Choice: y
Name: Zara Ali
Organisation: Tutorials Point

Other Data Types

The following table provides some other data types of F#.

F# Type Size Range Example Remarks
bool 1 byte Only two possible values, true or false

true

false

Stores boolean values

Example

let trueVal = true
let falseVal = false

printfn "True Value: %b" (trueVal)
printfn "False Value: %b" (falseVal)

When you compile and execute the program, it yields the following output −

True Value: true
False Value: false

A variable is a name given to a storage area that our programs can manipulate. Each variable has a specific type, which determines the size and layout of the variable's memory; the range of values that can be stored within that memory; and the set of operations that can be applied to the variable.

Variable Declaration in F#

The let keyword is used for variable declaration −

For example,

let x = 10

It declares a variable x and assigns the value 10 to it.

You can also assign an expression to a variable −

let x = 10
let y = 20
let z = x + y

The following example illustrates the concept −

Example

let x = 10
let y = 20
let z = x + y

printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z

When you compile and execute the program, it yields the following output −

x: 10
y: 20
z: 30

Variables in F# are immutable, which means once a variable is bound to a value, it can’t be changed. They are actually compiled as static read-only properties.

The following example demonstrates this.

Example

let x = 10
let y = 20
let z = x + y

printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z

let x = 15
let y = 20
let z = x + y

printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z

When you compile and execute the program, it shows the following error message −

Duplicate definition of value 'x'
Duplicate definition of value 'Y'
Duplicate definition of value 'Z'

Variable Definition With Type Declaration

A variable definition tells the compiler where and how much storage for the variable should be created. A variable definition may specify a data type and contains a list of one or more variables of that type as shown in the following example.

Example

let x:int32 = 10
let y:int32 = 20
let z:int32 = x + y

printfn "x: %d" x
printfn "y: %d" y
printfn "z: %d" z

let p:float = 15.99
let q:float = 20.78
let r:float = p + q

printfn "p: %g" p
printfn "q: %g" q
printfn "r: %g" r

When you compile and execute the program, it shows the following error message −

x: 10
y: 20
z: 30
p: 15.99
q: 20.78
r: 36.77

Mutable Variables

At times you need to change the values stored in a variable. To specify that there could be a change in the value of a declared and assigned variable, in later part of a program, F# provides the mutable keyword. You can declare and assign mutable variables using this keyword, whose values you will change.

The mutable keyword allows you to declare and assign values in a mutable variable.

You can assign some initial value to a mutable variable using the let keyword. However, to assign new subsequent value to it, you need to use the operator.

For example,

let mutable x = 10
x ← 15

The following example will clear the concept −

Example

let mutable x = 10
let y = 20
let mutable z = x + y

printfn "Original Values:"
printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z

printfn "Let us change the value of x"
printfn "Value of z will change too."

x <- 15
z <- x + y

printfn "New Values:"
printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z

When you compile and execute the program, it yields the following output −

Original Values:
x: 10
y: 20
z: 30
Let us change the value of x
Value of z will change too.
New Values:
x: 15
y: 20
z: 35

An operator is a symbol that tells the compiler to perform specific mathematical or logical manipulations. F# is rich in built-in operators and provides the following types of operators −

  • Arithmetic Operators
  • Comparison Operators
  • Boolean Operators
  • Bitwise Operators

Arithmetic Operators

The following table shows all the arithmetic operators supported by F# language. Assume variable A holds 10 and variable B holds 20 then −

Show Example

Operator Description Example
+ Adds two operands A + B will give 30
- Subtracts second operand from the first A - B will give -10
* Multiplies both operands A * B will give 200
/ Divides numerator by de-numerator B / A will give 2
% Modulus Operator and remainder of after an integer division B % A will give 0
** Exponentiation Operator, raises an operand to the power of another B**A will give 2010

Comparison Operators

The following table shows all the comparison operators supported by F# language. These binary comparison operators are available for integral and floating-point types. These operators return values of type bool.

Assume variable A holds 10 and variable B holds 20, then −

Show Example

Operator Description Example
= Checks if the values of two operands are equal or not, if yes then condition becomes true. (A == B) is not true.
<> Checks if the values of two operands are equal or not, if values are not equal then condition becomes true. (A <> B) is true.
> Checks if the value of left operand is greater than the value of right operand, if yes then condition becomes true. (A > B) is not true.
< Checks if the value of left operand is less than the value of right operand, if yes then condition becomes true. (A < B) is true.
>= Checks if the value of left operand is greater than or equal to the value of right operand, if yes then condition becomes true. (A >= B) is not true.
<= Checks if the value of left operand is less than or equal to the value of right operand, if yes then condition becomes true. (A <= B) is true.

Boolean Operators

The following table shows all the Boolean operators supported by F# language. Assume variable A holds true and variable B holds false, then −

Show Example

Operator Description Example
&& Called Boolean AND operator. If both the operands are non-zero, then condition becomes true. (A && B) is false.
|| Called Boolean OR Operator. If any of the two operands is non-zero, then condition becomes true. (A || B) is true.
not Called Boolean NOT Operator. Use to reverses the logical state of its operand. If a condition is true then Logical NOT operator will make false. not (A && B) is true.

Bitwise Operators

Bitwise operators work on bits and perform bit-by-bit operation. The truth tables for &&& (bitwise AND), ||| (bitwise OR), and ^^^ (bitwise exclusive OR) are as follows −

Show Example

p q p &&& q p ||| q p ^^^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

Assume if A = 60; and B = 13; now in binary format they will be as follows −

A = 0011 1100

B = 0000 1101

A&&&B = 0000 1100

A|||B = 0011 1101

A^^^B = 0011 0001

~~~A = 1100 0011

The Bitwise operators supported by F# language are listed in the following table. Assume variable A holds 60 and variable B holds 13, then −

Operator Description Example
&&& Binary AND Operator copies a bit to the result if it exists in both operands. (A &&& B) will give 12, which is 0000 1100
||| Binary OR Operator copies a bit if it exists in either operand. (A ||| B) will give 61, which is 0011 1101
^^^ Binary XOR Operator copies the bit if it is set in one operand but not both. (A ^^^ B) will give 49, which is 0011 0001
~~~ Binary Ones Complement Operator is unary and has the effect of 'flipping' bits. (~~~A) will give -61, which is 1100 0011 in 2's complement form.
<<< Binary Left Shift Operator. The left operands value is moved left by the number of bits specified by the right operand. A <<< 2 will give 240 which is 1111 0000
>>> Binary Right Shift Operator. The left operands value is moved right by the number of bits specified by the right operand. A >>> 2 will give 15 which is 0000 1111

Operators Precedence

The following table shows the order of precedence of operators and other expression keywords in the F# language, from lowest precedence to the highest precedence.

Show Example

Operator Associativity
as Right
when Right
| (pipe) Left
; Right
let Non associative
function, fun, match, try Non associative
if Non associative
Right
:= Right
, Non associative
or, || Left
&, && Left
< op, >op, =, |op, &op Left
&&& , |||, ^^^, ~~~, <<<, >>> Left
^ op Right
:: Right
:?>, :? Non associative
- op, +op, (binary) Left
* op, /op, %op Left
** op Right
f x (function application) Left
| (pattern match) Right
prefix operators (+op, -op, %, %%, &, &&, !op, ~op) Left
. Left
f(x) Left
f<types> Left

Decision making structures require that the programmer specify one or more conditions to be evaluated or tested by the program. It should be along with a statement or statements to be executed if the condition is determined to be true, and optionally, other statements to be executed if the condition is determined to be false.

Following is the general form of a typical decision making structure found in most of the programming languages −

F# programming language provides the following types of decision making statements.

Statement Description
if /then statement An if/then statement consists of a Boolean expression followed by one or more statements.
if/then/ else statement An if/then statement can be followed by an optional else statement, which executes when the Boolean expression is false.
if/then/elif/else statement An if/then/elif/else statement allows you to have multiple else branches.
nested if statements You can use one if or else if statement inside another if or else if statement(s).

Programming languages provide various control structures that allow for more complicated execution paths.

A loop statement allows us to execute a statement or group of statements multiple times and following is the general form of a loop statement in most of the programming languages −

F# provides the following types of loops to handle the looping requirements.

Loop Type Description
for… to and for… downto expressions The for...to expression is used to iterate in a loop over a range of values of a loop variable. The for… downto expression reduces the value of loop variable.
for … in expression This form of for loop is used to iterate over collections of items i.e., loops over collections and sequences
While…do loop Repeats a statement or group of statements while a given condition is true. It tests the condition before executing the loop body.
nested loops You can use one or more loop inside any other for or while loop.

In F#, functions work like data types. You can declare and use a function in the same way like any other variable.

Since functions can be used like any other variables, you can −

  • Create a function, with a name and associate that name with a type.
  • Assign it a value.
  • Perform some calculation on that value.
  • Pass it as a parameter to another function or sub-routine.
  • Return a function as the result of another function.

Defining a Function

Functions are defined by using the let keyword. A function definition has the following syntax −

let [inline] function-name parameter-list [ : return-type ]
= function-body

Where,

  • function-name is an identifier that represents the function.

  • parameter-list gives the list of parameters separated by spaces. You can also specify an explicit type for each parameter and if not specified compiler tends to deduce it from the function body (like variables).

  • function-body consists of an expression, or a compound expression consisting of a number of expressions. The final expression in the function body is the return value.

  • return-type is a colon followed by a type and is optional. If the return type is not specified, then the compiler determines it from the final expression in the function body.

Parameters of a Function

You list the names of parameters right after the function name. You can specify the type of a parameter. The type of the parameter should follow the name of the parameter separated by a colon.

If no parameter type is specified, it is inferred by the compiler.

For example −

let doubleIt (x : int) = 2 * x

Calling a Function

A function is called by specifying the function name followed by a space and then any arguments separated by spaces.

For example −

let vol = cylinderVolume 3.0 5.0

The following programs illustrate the concepts.

Example 1

The following program calculates the volume of a cylinder when the radius and length are given as parameters

// the function calculates the volume of
// a cylinder with radius and length as parameters

let cylinderVolume radius length : float =

   // function body
   let pi = 3.14159
   length * pi * radius * radius

let vol = cylinderVolume 3.0 5.0
printfn " Volume: %g " vol

When you compile and execute the program, it yields the following output −

Volume: 141.372

Example 2

The following program returns the larger value of two given parameters −

// the function returns the larger value between two
// arguments

let max num1 num2 : int32 =
   // function body
   if(num1>num2)then
      num1
   else
      num2

let res = max 39 52
printfn " Max Value: %d " res

When you compile and execute the program, it yields the following output −

Max Value: 52

Example 3

let doubleIt (x : int) = 2 * x
printfn "Double 19: %d" ( doubleIt(19))

When you compile and execute the program, it yields the following output −

Double 19: 38

Recursive Functions

Recursive functions are functions that call themselves.

You define a recursive using the let rec keyword combination.

Syntax for defining a recursive function is −

//Recursive function definition
let rec function-name parameter-list = recursive-function-body

For example −

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

Example 1

The following program returns Fibonacci 1 to 10 −

let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)
for i = 1 to 10 do
   printfn "Fibonacci %d: %d" i (fib i)

When you compile and execute the program, it yields the following output −

Fibonacci 1: 1
Fibonacci 2: 2
Fibonacci 3: 3
Fibonacci 4: 5
Fibonacci 5: 8
Fibonacci 6: 13
Fibonacci 7: 21
Fibonacci 8: 34
Fibonacci 9: 55
Fibonacci 10: 89

Example 2

The following program returns factorial 8 −

open System
let rec fact x =
   if x < 1 then 1
   else x * fact (x - 1)
Console.WriteLine(fact 8)

When you compile and execute the program, it yields the following output −

40320

Arrow Notations in F#

F# reports about data type in functions and values, using a chained arrow notation. Let us take an example of a function that takes one int input, and returns a string. In arrow notation, it is written as −

int -> string

Data types are read from left to right.

Let us take another hypothetical function that takes two int data inputs and returns a string.

let mydivfunction x y = (x / y).ToString();;

F# reports the data type using chained arrow notation as −

val mydivfunction : x:int -> y:int -> string

The return type is represented by the rightmost data type in chained arrow notation.

Some more examples −

Notation Meaning
float → float → float The function takes two float inputs, returns another float.
int → string → float The function takes an int and a string input, returns a float.

Lambda Expressions

A lambda expression is an unnamed function.

Let us take an example of two functions −

let applyFunction ( f: int -> int -> int) x y = f x y
let mul x y = x * y
let res = applyFunction mul 5 7
printfn "%d" res

When you compile and execute the program, it yields the following output −

35

Now in the above example, if instead of defining the function mul, we could have used lambda expressions as −

let applyFunction ( f: int -> int -> int) x y = f x y
let res = applyFunction (fun x y -> x * y ) 5 7
printfn "%d" res

When you compile and execute the program, it yields the following output −

35

Function Composition and Pipelining

In F#, one function can be composed from other functions.

The following example shows the composition of a function named f, from two functions function1 and function2 −

let function1 x = x + 1
let function2 x = x * 5

let f = function1 >> function2
let res = f 10
printfn "%d" res

When you compile and execute the program, it yields the following output −

55

F# also provides a feature called pipelining of functions. Pipelining allows function calls to be chained together as successive operations.

The following example shows that −

let function1 x = x + 1
let function2 x = x * 5

let res = 10 |> function1 |> function2
printfn "%d" res

When you compile and execute the program, it yields the following output −

55

In F#, the string type represents immutable text as a sequence of Unicode characters.

String Literals

String literals are delimited by the quotation mark (") character.

Some special characters are there for special uses like newline, tab, etc. They are encoded using backslash (\) character. The backslash character and the related character make the escape sequence. The following table shows the escape sequence supported by F#.

Character Escape sequence
Backspace \b
Newline \n
Carriage return \r
Tab \t
Backslash \\
Quotation mark \"
Apostrophe \'
Unicode character \uXXXX or \UXXXXXXXX (where X indicates a hexadecimal digit)

Ways of lgnoring the Escape Sequence

The following two ways makes the compiler ignore the escape sequence −

  • Using the @ symbol.
  • Enclosing the string in triple quotes.

When a string literal is preceded by the @ symbol, it is called a verbatim string. In that way, all escape sequences in the string are ignored, except that two quotation mark characters are interpreted as one quotation mark character.

When a string is enclosed by triple quotes, then also all escape sequences are ignored, including double quotation mark characters.

Example

The following example demonstrates this technique showing how to work with XML or other structures that include embedded quotation marks −

// Using a verbatim string
let xmldata = @"<book author=""Lewis, C.S"" title=""Narnia"">"
printfn "%s" xmldata

When you compile and execute the program, it yields the following output −

<book author="Lewis, C.S" title="Narnia">

Basic Operators on Strings

The following table shows the basic operations on strings −

Value Description
collect : (char → string) → string → string Creates a new string whose characters are the results of applying a specified function to each of the characters of the input string and concatenating the resulting strings.
concat : string → seq<string> → string Returns a new string made by concatenating the given strings with a separator.
exists : (char → bool) → string → bool Tests if any character of the string satisfies the given predicate.
forall : (char → bool) → string → bool Tests if all characters in the string satisfy the given predicate.
init : int → (int → string) → string Creates a new string whose characters are the results of applying a specified function to each index and concatenating the resulting strings.
iter : (char → unit) → string → unit Applies a specified function to each character in the string.
iteri : (int → char → unit) → string → unit Applies a specified function to the index of each character in the string and the character itself.
length : string → int Returns the length of the string.
map : (char → char) → string → string Creates a new string whose characters are the results of applying a specified function to each of the characters of the input string.
mapi : (int → char → char) → string → string Creates a new string whose characters are the results of applying a specified function to each character and index of the input string.
replicate : int → string → string Returns a string by concatenating a specified number of instances of a string.

The following examples demonstrate the uses of some of the above functionalities −

Example 1

The String.collect function builds a new string whose characters are the results of applying a specified function to each of the characters of the input string and concatenating the resulting strings.

let collectTesting inputS =
   String.collect (fun c -> sprintf "%c " c) inputS
printfn "%s" (collectTesting "Happy New Year!")

When you compile and execute the program, it yields the following output −

H a p p y N e w Y e a r !

Example 2

The String.concat function concatenates a given sequence of strings with a separator and returns a new string.

let strings = [ "Tutorials Point"; "Coding Ground"; "Absolute Classes" ]
let ourProducts = String.concat "\n" strings
printfn "%s" ourProducts

When you compile and execute the program, it yields the following output −

Tutorials Point
Coding Ground
Absolute Classes

Example 3

The String.replicate method returns a string by concatenating a specified number of instances of a string.

printfn "%s" <| String.replicate 10 "*! "

When you compile and execute the program, it yields the following output −

*! *! *! *! *! *! *! *! *! *!

The option type in F# is used in calculations when there may or may not exist a value for a variable or function. Option types are used for representing optional values in calculations. They can have two possible values − Some(x) or None.

For example, a function performing a division will return a value in normal situation, but will throw exceptions in case of a zero denominator. Using options here will help to indicate whether the function has succeeded or failed.

An option has an underlying type and can hold a value of that type, or it might not have a value.

Using Options

Let us take the example of division function. The following program explains this −

Let us write a function div, and send two arguments to it 20 and 5 −

let div x y = x / y
let res = div 20 5
printfn "Result: %d" res

When you compile and execute the program, it yields the following output −

Result: 4

If the second argument is zero, then the program throws an exception −

let div x y = x / y
let res = div 20 0
printfn "Result: %d" res

When you compile and execute the program, it yields the following output −

Unhandled Exception:
System.DivideByZeroException: Division by zero

In such cases, we can use option types to return Some (value) when the operation is successful or None if the operation fails.

The following example demonstrates the use of options −

Example

let div x y =
   match y with
   | 0 -> None
   | _ -> Some(x/y)

let res : int option = div 20 4
printfn "Result: %A " res

When you compile and execute the program, it yields the following output −

Result: Some 5

Option Properties and Methods

The option type supports the following properties and methods −

Property or method Type Description
None 'T option A static property that enables you to create an option value that has the None value.
IsNone bool Returns true if the option has the None value.
IsSome bool Returns true if the option has a value that is not None.
Some 'T option A static member that creates an option that has a value that is not None.
Value 'T Returns the underlying value, or throws a NullReferenceException if the value is None.

Example 1

let checkPositive (a : int) =
   if a > 0 then
      Some(a)
   else
      None

let res : int option = checkPositive(-31)
printfn "Result: %A " res

When you compile and execute the program, it yields the following output −

Result: <null>

Example 2

let div x y =
   match y with
   | 0 -> None
   | _ -> Some(x/y)

let res : int option = div 20 4
printfn "Result: %A " res
printfn "Result: %A " res.Value

When you compile and execute the program, it yields the following output −

Result: Some 5
Result: 5

Example 3

let isHundred = function
   | Some(100) -> true
   | Some(_) | None -> false

printfn "%A" (isHundred (Some(45)))
printfn "%A" (isHundred (Some(100)))
printfn "%A" (isHundred None)

When you compile and execute the program, it yields the following output −

false
true
false

A tuple値のコンマ区切りのコレクションです。これらは、関連する値をグループ化するアドホックデータ構造を作成するために使用されます。

たとえば、(“ Zara Ali”、“ Hyderabad”、10)は、2つの文字列値とint値を持つ3タプルであり、タイプは(string * string * int)です。

タプルは、同じタイプまたは異なるタイプのペア、トリプルなどです。

いくつかの例をここに示します-

// Tuple of two integers.
( 4, 5 )

// Triple of strings.
( "one", "two", "three" )

// Tuple of unknown types.
( a, b )

// Tuple that has mixed types.
( "Absolute Classes", 1, 2.0 )

// Tuple of integer expressions.
( a * 4, b + 7)

このプログラムには、4つのfloat値のタプルを取り、平均を返す関数があります。

let averageFour (a, b, c, d) =
   let sum = a + b + c + d
   sum / 4.0

let avg:float = averageFour (4.0, 5.1, 8.0, 12.0)
printfn "Avg of four numbers: %f" avg

プログラムをコンパイルして実行すると、次の出力が生成されます。

Avg of four numbers: 7.275000

個々のタプルメンバーへのアクセス

タプルの個々のメンバーは、パターンマッチングを使用して評価および印刷できます。

次の例は、概念を示しています-

let display tuple1 =
   match tuple1 with
   | (a, b, c) -> printfn "Detail Info: %A %A %A" a b c

display ("Zara Ali", "Hyderabad", 10 )

プログラムをコンパイルして実行すると、次の出力が生成されます。

Detail Info: "Zara Ali" "Hyderabad" 10

F#には2つの組み込み関数があります。 fst そして snd, 2タプルで1番目と2番目のアイテムを返します。

次の例は、概念を示しています-

printfn "First member: %A" (fst(23, 30))
printfn "Second member: %A" (snd(23, 30))

printfn "First member: %A" (fst("Hello", "World!"))
printfn "Second member: %A" (snd("Hello", "World!"))

let nameTuple = ("Zara", "Ali")

printfn "First Name: %A" (fst nameTuple)
printfn "Second Name: %A" (snd nameTuple)

プログラムをコンパイルして実行すると、次の出力が生成されます。

First member: 23
Second member: 30
First member: "Hello"
Second member: "World!"
First Name: "Zara"
Second Name: "Ali"

A recordタプルに似ていますが、名前付きフィールドが含まれています。例えば、

type website =
   { title : string;
      url : string }

レコードの定義

レコードは、を使用してタイプとして定義されます type キーワード、およびレコードのフィールドは、セミコロンで区切られたリストとして定義されます。

レコードを定義するための構文は次のとおりです。

type recordName =
   { [ fieldName : dataType ] + }

レコードの作成

レコードのフィールドを指定することにより、レコードを作成できます。たとえば、私たちが作成してみましょうウェブサイトの名前のレコードのホームページ-

let homepage = { Title = "TutorialsPoint"; Url = "www.tutorialspoint.com" }

次の例で概念を説明します-

例1

このプログラムは、websiteという名前のレコードタイプを定義します。次に、タイプWebサイトのレコードをいくつか作成し、レコードを印刷します。

(* defining a record type named website *)
type website =
   { Title : string;
      Url : string }

(* creating some records *)
let homepage = { Title = "TutorialsPoint"; Url = "www.tutorialspoint.com" }
let cpage = { Title = "Learn C"; Url = "www.tutorialspoint.com/cprogramming/index.htm" }
let fsharppage = { Title = "Learn F#"; Url = "www.tutorialspoint.com/fsharp/index.htm" }
let csharppage = { Title = "Learn C#"; Url = "www.tutorialspoint.com/csharp/index.htm" }

(*printing records *)
(printfn "Home Page: Title: %A \n \t URL: %A") homepage.Title homepage.Url
(printfn "C Page: Title: %A \n \t URL: %A") cpage.Title cpage.Url
(printfn "F# Page: Title: %A \n \t URL: %A") fsharppage.Title fsharppage.Url
(printfn "C# Page: Title: %A \n \t URL: %A") csharppage.Title csharppage.Url

プログラムをコンパイルして実行すると、次の出力が生成されます。

Home Page: Title: "TutorialsPoint"
       URL: "www.tutorialspoint.com"
C Page: Title: "Learn C"
      URL: "www.tutorialspoint.com/cprogramming/index.htm"
F# Page: Title: "Learn F#"
      URL: "www.tutorialspoint.com/fsharp/index.htm"
C# Page: Title: "Learn C#"
      URL: "www.tutorialspoint.com/csharp/index.htm"

例2

type student =
   { Name : string;
      ID : int;
      RegistrationText : string;
      IsRegistered : bool }

let getStudent name id =
   { Name = name; ID = id; RegistrationText = null; IsRegistered = false }

let registerStudent st =
   { st with
      RegistrationText = "Registered";
      IsRegistered = true }

let printStudent msg st =
   printfn "%s: %A" msg st

let main() =
   let preRegisteredStudent = getStudent "Zara" 10
   let postRegisteredStudent = registerStudent preRegisteredStudent

   printStudent "Before Registration: " preRegisteredStudent
   printStudent "After Registration: " postRegisteredStudent

main()

プログラムをコンパイルして実行すると、次の出力が生成されます。

Before Registration: : {Name = "Zara";
   ID = 10;
   RegistrationText = null;
   IsRegistered = false;}
After Registration: : {Name = "Zara";
   ID = 10;
   RegistrationText = "Registered";
   IsRegistered = true;}

F#では、リストは同じタイプの順序付けられた不変の一連の要素です。これは、リンクリストのデータ構造とある程度同等です。

F#モジュール、 Microsoft.FSharp.Collections.List,リストに対する一般的な操作があります。ただし、F#はこのモジュールを自動的にインポートし、すべてのF#アプリケーションからアクセスできるようにします。

リストの作成と初期化

リストを作成するさまざまな方法は次のとおりです-

  • リストを使用する literals

  • 使用する cons (::)演算子。

  • を使用して List.init リストモジュールのメソッド。

  • いくつかを使用して syntactic constructs と呼ばれる List Comprehensions

リテラルのリスト

この方法では、セミコロンで区切られた値のシーケンスを角括弧で囲んで指定するだけです。例-

let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]

短所(::)演算子

この方法では、またはを前に付けることでいくつかの値を追加できます cons-ing::演算子を使用して既存のリストに追加します。例-

let list2 = 1::2::3::4::5::6::7::8::9::10::[];;

[]は空のリストを示します。

リスト初期化メソッド

ListモジュールのList.initメソッドは、リストの作成によく使用されます。このメソッドのタイプは-

val init : int -> (int -> 'T) -> 'T list

最初の引数は新しいリストの目的の長さであり、2番目の引数はリスト内の項目を生成する初期化関数です。

例えば、

let list5 = List.init 5 (fun index -> (index, index * index, index * index * index))

ここで、インデックス関数はリストを生成します。

リスト内包表記

リスト内包表記は、リストの生成に使用される特別な構文構造です。

F#リスト内包構文には、範囲とジェネレーターの2つの形式があります。

範囲には構成があります-[開始..終了]および[開始..ステップ..終了]

例えば、

let list3 = [1 .. 10]

ジェネレーターの構成は-[コレクション内のxの場合... yield expr]

例えば、

let list6 = [ for a in 1 .. 10 do yield (a * a) ]

として yield キーワードは、単一の値をリストにプッシュします。キーワード、 yield!, 値のコレクションをリストにプッシュします。

次の関数は、上記の方法を示しています-

(* using list literals *)
let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
printfn "The list: %A" list1

(*using cons operator *)
let list2 = 1 :: 2 :: 3 :: []
printfn "The list: %A" list2

(* using range constructs*)
let list3 = [1 .. 10]
printfn "The list: %A" list3

(* using range constructs *)
let list4 = ['a' .. 'm']
printfn "The list: %A" list4

(* using init method *)
let list5 = List.init 5 (fun index -> (index, index * index, index * index * index))
printfn "The list: %A" list5

(* using yield operator *)
let list6 = [ for a in 1 .. 10 do yield (a * a) ]
printfn "The list: %A" list6

(* using yield operator *)
let list7 = [ for a in 1 .. 100 do if a % 3 = 0 && a % 5 = 0 then yield a]
printfn "The list: %A" list7

(* using yield! operator *)
let list8 = [for a in 1 .. 3 do yield! [ a .. a + 3 ] ]
printfn "The list: %A" list8

プログラムをコンパイルして実行すると、次の出力が生成されます。

The list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
The list: [1; 2; 3]
The list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
The list: ['a'; 'b'; 'c'; 'd'; 'e'; 'f'; 'g'; 'h'; 'i'; 'j'; 'k'; 'l'; 'm']
The list: [(0, 0, 0); (1, 1, 1); (2, 4, 8); (3, 9, 27); (4, 16, 64)]
The list: [1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
The list: [15; 30; 45; 60; 75; 90]
The list: [1; 2; 3; 4; 2; 3; 4; 5; 3; 4; 5; 6]

リストデータ型のプロパティ

次の表は、リストデータ型のさまざまなプロパティを示しています。

プロパティ タイプ 説明
'T 最初の要素。
空の 'Tリスト 適切なタイプの空のリストを返す静的プロパティ。
IsEmpty ブール true リストに要素がない場合。
項目 'T 指定されたインデックスの要素(ゼロベース)。
長さ int 要素の数。
'Tリスト 最初の要素のないリスト。

次の例は、これらのプロパティの使用法を示しています-

let list1 = [ 2; 4; 6; 8; 10; 12; 14; 16 ]

// Use of Properties
printfn "list1.IsEmpty is %b" (list1.IsEmpty)
printfn "list1.Length is %d" (list1.Length)
printfn "list1.Head is %d" (list1.Head)
printfn "list1.Tail.Head is %d" (list1.Tail.Head)
printfn "list1.Tail.Tail.Head is %d" (list1.Tail.Tail.Head)
printfn "list1.Item(1) is %d" (list1.Item(1))

プログラムをコンパイルして実行すると、次の出力が生成されます。

list1.IsEmpty is false
list1.Length is 8
list1.Head is 2
list1.Tail.Head is 4
list1.Tail.Tail.Head is 6
list1.Item(1) is 4

リストの基本的な演算子

次の表は、リストデータ型の基本的な操作を示しています。

説明
追加: 'Tリスト→' Tリスト→ 'Tリスト 最初のリストの要素とそれに続く2番目のリストの要素を含む新しいリストを返します。
平均: 'Tリスト→^ T リスト内の要素の平均を返します。
averageBy :( 'T→^ U)→' Tリスト→^ U リストの各要素に関数を適用して生成された要素の平均を返します。
選択:( 'T→' Uオプション)→ 'Tリスト→' Uリスト 指定された関数をリストの各要素に適用します。関数が返す各要素の結果で構成されるリストを返しますSome
収集:( 'T→' Uリスト)→ 'Tリスト→' Uリスト リストの各要素に対して、指定された関数を適用します。すべての結果を連結し、結合されたリストを返します。
concat:seq <'Tリスト>→' Tリスト 各リストの要素を順番に含む新しいリストを返します。
空: 'Tリスト 指定されたタイプの空のリストを返します。
存在する:( 'T→bool)→' Tリスト→bool リストのいずれかの要素が指定された述語を満たすかどうかをテストします。
存在2 :( 'T1→' T2→bool)→ 'T1リスト→' T2リスト→bool リストの対応する要素のペアが指定された述語を満たすかどうかをテストします。
フィルタ:( 'T→bool)→' Tリスト→ 'Tリスト 指定された述語が返すコレクションの要素のみを含む新しいコレクションを返します true
検索:( 'T→bool)→' Tリスト→ 'T 指定された関数が返す最初の要素を返します true
findIndex :( 'T→bool)→' Tリスト→int 指定された述語を満たすリストの最初の要素のインデックスを返します。
fold :( '状態→' T→ '状態)→'状態→ 'Tリスト→'状態 コレクションの各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。この関数は2番目の引数を取り、その引数とリストの最初の要素に関数を適用します。次に、この結果を2番目の要素とともに関数に渡します。最後に、最終結果を返します。入力関数がfで、要素がi0 ... iNの場合、この関数はf(...(fs i0)i1 ...)iNを計算します。
fold2 :( '状態→' T1→ 'T2→'状態)→ '状態→' T1リスト→ 'T2リスト→'状態 2つのコレクションの対応する要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。コレクションのサイズは同じである必要があります。入力関数がfで、要素がi0 ... iNおよびj0 ... jNの場合、この関数はf(...(fs i0 j0)...)iNjNを計算します。
foldBack :( 'T→'状態→ '状態)→' Tリスト→ '状態→'状態 コレクションの各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。入力関数がisfで、要素がi0 ... iNの場合、f i0(...(f iN s))を計算します。
foldBack2 :( 'T1→' T2→ '状態→'状態)→ 'T1リスト→' T2リスト→ '状態→'状態 2つのコレクションの対応する要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。コレクションのサイズは同じである必要があります。入力関数がfで、要素がi0 ... iNおよびj0 ... jNの場合、この関数はf i0 j0(...(f iN jN s))を計算します。
forall :( 'T→bool)→' Tリスト→bool コレクションのすべての要素が指定された述語を満たしているかどうかをテストします。
forall2 :( 'T1→' T2→bool)→ 'T1リスト→' T2リスト→bool コレクションの対応するすべての要素が、指定された述語をペアごとに満たすかどうかをテストします。
ヘッド: 'Tリスト→' T リストの最初の要素を返します。
init:int→(int→ 'T)→' Tリスト 各インデックスで指定されたジェネレーターを呼び出すことにより、リストを作成します。
isEmpty: 'Tリスト→bool 戻り値 true リストに要素が含まれていない場合、 false そうでなければ。
iter :( 'T→ユニット)→' Tリスト→ユニット 指定された関数をコレクションの各要素に適用します。
iter2 :( 'T1→' T2→ユニット)→ 'T1リスト→' T2リスト→ユニット 指定された関数を2つのコレクションに同時に適用します。コレクションのサイズは同じである必要があります。
iteri:(int→ 'T→unit)→' Tリスト→unit 指定された関数をコレクションの各要素に適用します。関数に渡される整数は、要素のインデックスを示します。
iteri2:(int→ 'T1→' T2→unit)→ 'T1list→' T2list→unit 指定された関数を2つのコレクションに同時に適用します。コレクションのサイズは同じである必要があります。関数に渡される整数は、要素のインデックスを示します。
長さ: 'Tリスト→int リストの長さを返します。
マップ:( 'T→' U)→ 'Tリスト→' Uリスト コレクションの各要素に指定された関数を適用した結果を要素とする新しいコレクションを作成します。
map2 :( 'T1→' T2→ 'U)→' T1リスト→ 'T2リスト→' Uリスト 指定された関数を2つのコレクションの対応する要素にペアごとに適用した結果である要素を持つ新しいコレクションを作成します。
map3 :( 'T1→' T2→ 'T3→' U)→ 'T1リスト→' T2リスト→ 'T3リスト→' Uリスト 指定された関数を3つのコレクションの対応する要素に同時に適用した結果である要素を持つ新しいコレクションを作成します。
mapi:(int→ 'T→' U)→ 'Tリスト→' Uリスト コレクションの各要素に指定された関数を適用した結果を要素とする新しいコレクションを作成します。関数に渡される整数インデックスは、変換される要素のインデックス(0から)を示します。
mapi2:(int→ 'T1→' T2→ 'U)→' T1リスト→ 'T2リスト→' Uリスト List.mapiと似ていますが、同じ長さの2つのリストから対応する要素をマッピングします。
max: 'Tリスト→' T Operators.maxを使用して比較した、リストのすべての要素の最大のものを返します。
maxBy :( 'T→' U)→ 'Tリスト→' T 関数の結果でOperators.maxを使用して比較した、リストのすべての要素の最大値を返します。
min: 'Tリスト→' T Operators.minを使用して比較した、リストのすべての要素の最低値を返します。
minBy :( 'T→' U)→ 'Tリスト→' T 関数の結果でOperators.minを使用して比較した、リストのすべての要素の最低値を返します
n番目: 'Tリスト→int→' T リストへのインデックス。最初の要素のインデックスは0です。
ofArray: 'T []→' Tリスト 指定された配列からリストを作成します。
ofSeq:seq <'T>→' Tリスト 指定された列挙可能なオブジェクトから新しいリストを作成します。
パーティション:( 'T→bool)→' Tリスト* 'Tリスト コレクションを2つのコレクションに分割し、指定された述語が返す要素を含みます true そして false それぞれ。
順列:(int→int)→ 'Tリスト→' Tリスト 指定された順列に従ってすべての要素が順列されたリストを返します。
ピック:( 'T→' Uオプション)→ 'Tリスト→' U 指定された関数を連続する要素に適用し、関数が返す最初の結果を返します Some いくつかの値のために。
削減:( 'T→' T→ 'T)→' Tリスト→ 'T コレクションの各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。この関数は、指定された関数をリストの最初の2つの要素に適用します。次に、この結果を3番目の要素とともに関数に渡します。最後に、最終結果を返します。入力関数がfで、要素がi0 ... iNの場合、この関数はf(...(f i0 i1)i2 ...)iNを計算します。
reduceBack :( 'T→' T→ 'T)→' Tリスト→ 'T コレクションの各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。入力関数がisfで、要素がi0 ... iNの場合、この関数はf i0(...(f iN-1 iN))を計算します。
レプリケート:(int→ 'T→' Tリスト) 各インデックスで指定されたジェネレーターを呼び出すことにより、リストを作成します。
rev: 'Tリスト→' Tリスト 要素を逆の順序で含む新しいリストを返します。
スキャン:( '状態→' T→ '状態)→'状態→ 'Tリスト→'状態リスト コレクションの各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。この関数は2番目の引数を取り、指定された関数をその引数とリストの最初の要素に適用します。次に、この結果を2番目の要素とともに関数に渡します。最後に、中間結果と最終結果のリストを返します。
scanBack :( 'T→'状態→ '状態)→' Tリスト→ '状態→'状態リスト foldBackと同様ですが、中間結果と最終結果の両方を返します
ソート: 'Tリスト→' Tリスト Operators.compareを使用して、指定されたリストを並べ替えます。
sortBy :( 'T→'キー)→ 'Tリスト→' Tリスト 指定されたプロジェクションによって指定されたキーを使用して、指定されたリストを並べ替えます。キーはOperators.compareを使用して比較されます。
sortWith :( 'T→' T→int)→ 'Tリスト→' Tリスト 指定された比較関数を使用して、指定されたリストをソートします。
合計:^ Tリスト→^ T リスト内の要素の合計を返します。
sumBy :( 'T→^ U)→' Tリスト→^ U リストの各要素に関数を適用して生成された結果の合計を返します。
テール: 'Tリスト→' Tリスト 最初の要素なしで入力リストを返します。
toArray: 'Tリスト→' T [] 指定されたリストから配列を作成します。
toSeq: 'Tリスト→seq <' T> 指定されたリストをシーケンスとして表示します。
tryFind :( 'T→bool)→' Tリスト→ 'Tオプション 指定された関数が返す最初の要素を返します true。戻るNone そのような要素が存在しない場合。
tryFindIndex :( 'T→bool)→' Tリスト→intオプション 指定された述語を満たすリストの最初の要素のインデックスを返します。戻るNone そのような要素が存在しない場合。
tryPick :( 'T→' Uオプション)→ 'Tリスト→' Uオプション 指定された関数を連続する要素に適用し、関数が返す最初の結果を返します Someいくつかの値のために。そのような要素が存在しない場合は、None
解凍:( 'T1 *' T2)リスト→ 'T1リスト*' T2リスト ペアのリストを2つのリストに分割します。
unzip3 :( 'T1 *' T2 * 'T3)リスト→' T1リスト* 'T2リスト*' T3リスト トリプルのリストを3つのリストに分割します。
zip: 'T1リスト→' T2リスト→( 'T1 *' T2)リスト 2つのリストをペアのリストに結合します。2つのリストの長さは同じでなければなりません。
zip3: 'T1リスト→' T2リスト→ 'T3リスト→(' T1 * 'T2 *' T3)リスト 3つのリストをトリプルのリストに結合します。リストの長さは同じでなければなりません。

次の例は、上記の機能の使用法を示しています-

例1

このプログラムは、リストを再帰的に反転することを示しています-

let list1 = [ 2; 4; 6; 8; 10; 12; 14; 16 ]
printfn "The original list: %A" list1

let reverse lt =
   let rec loop acc = function
      | [] -> acc
      | hd :: tl -> loop (hd :: acc) tl
   loop [] lt

printfn "The reversed list: %A" (reverse list1)

プログラムをコンパイルして実行すると、次の出力が生成されます。

The original list: [2; 4; 6; 8; 10; 12; 14; 16]
The reversed list: [16; 14; 12; 10; 8; 6; 4; 2]

ただし、 rev 同じ目的のためのモジュールの機能-

let list1 = [ 2; 4; 6; 8; 10; 12; 14; 16 ]
printfn "The original list: %A" list1
printfn "The reversed list: %A" (List.rev list1)

プログラムをコンパイルして実行すると、次の出力が生成されます。

The original list: [2; 4; 6; 8; 10; 12; 14; 16]
The reversed list: [16; 14; 12; 10; 8; 6; 4; 2]

例2

このプログラムは、を使用してリストをフィルタリングすることを示しています List.filter 方法−

let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
printfn "The list: %A" list1
let list2 = list1 |> List.filter (fun x -> x % 2 = 0);;
printfn "The Filtered list: %A" list2

プログラムをコンパイルして実行すると、次の出力が生成されます。

The list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
The Filtered list: [2; 4; 6; 8; 10]

例3

ザ・ List.map メソッドは、リストをあるタイプから別のタイプにマップします-

let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
printfn "The list: %A" list1
let list2 = list1 |> List.map (fun x -> (x * x).ToString());;
printfn "The Mapped list: %A" list2

プログラムをコンパイルして実行すると、次の出力が生成されます。

The list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
The Mapped list: ["1"; "4"; "9"; "16"; "25"; "36"; "49"; "64"; "81"; "100"]

例4

ザ・ List.append メソッドと@演算子は、あるリストを別のリストに追加します-

let list1 = [1; 2; 3; 4; 5 ]
let list2 = [6; 7; 8; 9; 10]
let list3 = List.append list1 list2

printfn "The first list: %A" list1
printfn "The second list: %A" list2
printfn "The appened list: %A" list3

let lt1 = ['a'; 'b';'c' ]
let lt2 = ['e'; 'f';'g' ]
let lt3 = lt1 @ lt2

printfn "The first list: %A" lt1
printfn "The second list: %A" lt2
printfn "The appened list: %A" lt3

プログラムをコンパイルして実行すると、次の出力が生成されます。

The first list: [1; 2; 3; 4; 5]
The second list: [6; 7; 8; 9; 10]
The appened list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
The first list: ['a'; 'b'; 'c']
The second list: ['e'; 'f'; 'g']
The appened list: ['a'; 'b'; 'c'; 'e'; 'f'; 'g']

例5

ザ・ List.sortメソッドはリストをソートします。ザ・List.sum メソッドは、リスト内の要素の合計と List.average メソッドはリスト内の要素の平均を与えます-

let list1 = [9.0; 0.0; 2.0; -4.5; 11.2; 8.0; -10.0]
printfn "The list: %A" list1

let list2 = List.sort list1
printfn "The sorted list: %A" list2

let s = List.sum list1
let avg = List.average list1
printfn "The sum: %f" s
printfn "The average: %f" avg

プログラムをコンパイルして実行すると、次の出力が生成されます。

The list: [9.0; 0.0; 2.0; -4.5; 11.2; 8.0; -10.0]
The sorted list: [-10.0; -4.5; 0.0; 2.0; 8.0; 9.0; 11.2]
The sum: 15.700000
The average: 2.242857

「フォールド」操作は、リスト内の各要素に関数を適用し、関数の結果をアキュムレータ変数に集約し、フォールド操作の結果としてアキュムレータを返します。

例6

ザ・ List.fold メソッドは、左から右に各要素に関数を適用しますが、 List.foldBack 右から左に各要素に関数を適用します。

let sumList list = List.fold (fun acc elem -> acc + elem) 0 list
printfn "Sum of the elements of list %A is %d." [ 1 .. 10 ] (sumList [ 1 .. 10 ])

プログラムをコンパイルして実行すると、次の出力が生成されます。

Sum of the elements of list [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] is 55.

リストのようなシーケンスも、順序付けられた値のコレクションを表します。ただし、シーケンスまたはシーケンス式の要素は、必要に応じて計算されます。それらは一度に計算されないため、無限のデータ構造を表すために使用されます。

シーケンスの定義

シーケンスは、次の構文を使用して定義されます-

seq { expr }

例えば、

let seq1 = seq { 1 .. 10 }

シーケンスとシーケンス式の作成

リストと同様に、範囲と内包表記を使用してシーケンスを作成できます。

シーケンス式は、シーケンスを作成するために記述できる式です。これらは行うことができます-

  • 範囲を指定する。
  • 範囲をインクリメントまたはデクリメントで指定する。
  • を使用して yield シーケンスの一部となる値を生成するキーワード。
  • →演算子を使用する。

次の例は、概念を示しています-

例1

(* Sequences *)
let seq1 = seq { 1 .. 10 }

(* ascending order and increment*)
printfn "The Sequence: %A" seq1
let seq2 = seq { 1 .. 5 .. 50 }

(* descending order and decrement*)
printfn "The Sequence: %A" seq2
let seq3 = seq {50 .. -5 .. 0}
printfn "The Sequence: %A" seq3

(* using yield *)
let seq4 = seq { for a in 1 .. 10 do yield a, a*a, a*a*a }
printfn "The Sequence: %A" seq4

プログラムをコンパイルして実行すると、次の出力が生成されます。

The Sequence: seq [1; 2; 3; 4; ...]
The Sequence: seq [1; 6; 11; 16; ...]
The Sequence: seq [50; 45; 40; 35; ...]
The Sequence: seq [(1, 1, 1); (2, 4, 8); (3, 9, 27); (4, 16, 64); ...]

例2

次のプログラムは、1から50までの素数を出力します-

(* Recursive isprime function. *)
let isprime n =
   let rec check i =
      i > n/2 || (n % i <> 0 && check (i + 1))
   check 2

let primeIn50 = seq { for n in 1..50 do if isprime n then yield n }
for x in primeIn50 do
   printfn "%d" x

プログラムをコンパイルして実行すると、次の出力が生成されます。

1
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47

シーケンスの基本操作

次の表に、シーケンスデータ型の基本的な操作を示します。

説明
追加:seq <'T>→seq <' T>→seq <'T> 指定された2つの列挙を単一の連結列挙としてラップします。
平均:seq <^ T>→^ T シーケンス内の要素の平均を返します。
AverageBy :( 'T→^ U)→seq <' T>→^ U シーケンスの各要素に関数を適用して生成された結果の平均を返します。
キャッシュ:seq <'T>→seq <' T> 入力シーケンスのキャッシュバージョンに対応するシーケンスを返します。
キャスト:IEnumerable→seq <'T> 緩く型付けされたシステムをラップします。型付きシーケンスとしてのコレクションシーケンス。
選択:( 'T→' Uオプション)→seq <'T>→seq <' U> 指定された関数をリストの各要素に適用します。関数が返す各要素の結果で構成されるリストを返しますSome
収集:( 'T→'コレクション)→seq <'T>→seq <' U> 指定された関数をシーケンスの各要素に適用し、すべての結果を連結します。
compareWith :( 'T→' T→int)→seq <'T>→seq <' T>→int 指定された比較関数を使用して、要素ごとに2つのシーケンスを比較します。
concat:seq <'コレクション>→seq <' T> 指定された列挙の列挙を単一の連結された列挙として結合します。
countBy :( 'T→' Key)→seq <'T>→seq <' Key * int> シーケンスの各要素にキー生成関数を適用し、シーケンスを返し、元のシーケンスでの一意のキーとその出現回数を生成します。
遅延:(ユニット→seq <'T>)→seq <' T> シーケンスの指定された遅延指定から構築されたシーケンスを返します。
異なる:seq <'T>→seq <' T> エントリの一般的なハッシュと等価性の比較に従って、重複するエントリを含まないシーケンスを返します。要素がシーケンス内で複数回出現する場合、それ以降の出現は破棄されます。
DistinctBy :( 'T→'キー)→seq <'T>→seq <' T> 指定されたキー生成関数によって返されるキーの一般的なハッシュと等価性の比較に従って、重複するエントリを含まないシーケンスを返します。要素がシーケンス内で複数回出現する場合、それ以降の出現は破棄されます。
空:seq <'T> 空のシーケンスを作成します。
正確に1つ:seq <'T>→' T シーケンスの唯一の要素を返します。
存在する:( 'T→bool)→seq <' T>→bool シーケンスのいずれかの要素が指定された述語を満たすかどうかをテストします。
存在2 :( 'T1→' T2→bool)→seq <'T1>→seq <' T2>→bool 入力シーケンスの対​​応する要素のペアが指定された述語を満たすかどうかをテストします。
フィルタ:( 'T→bool)→seq <' T>→seq <'T> 指定された述語が返すコレクションの要素のみを含む新しいコレクションを返します true
検索:( 'T→bool)→seq <' T>→ 'T 指定された関数が返す最初の要素を返します true
findIndex :( 'T→bool)→seq <' T>→int 指定された関数が返す最初の要素のインデックスを返します true
fold :( '状態→' T→ '状態)→'状態→seq <'T>→'状態 コレクションの各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。入力関数がfで、要素がi0 ... iNの場合、この関数はf(...(fs i0)...)iNを計算します。
forall :( 'T→bool)→seq <' T>→bool シーケンスのすべての要素が指定された述語を満たしているかどうかをテストします。
forall2 :( 'T1→' T2→bool)→seq <'T1>→seq <' T2>→bool 2つのシーケンスから抽出された要素のすべてのペアが、指定された述語を満たすことをテストします。一方のシーケンスがもう一方のシーケンスよりも短い場合、長いシーケンスの残りの要素は無視されます。
groupBy :( 'T→' Key)→seq <'T>→seq <' Key * seq <'T >> シーケンスの各要素にキー生成関数を適用し、一意のキーのシーケンスを生成します。各一意のキーには、このキーに一致するすべての要素のシーケンスも含まれています。
ヘッド:seq <'T>→' T シーケンスの最初の要素を返します。
init:int→(int→ 'T)→seq <' T> 繰り返されると、指定された関数を呼び出すことにより、指定されたカウントまで連続する要素を返す新しいシーケンスを生成します。関数を呼び出した結果は保存されません。つまり、要素を再生成するために必要に応じて関数が再適用されます。関数には、生成されるアイテムのインデックスが渡されます。
initInfinite:(int→ 'T)→seq <' T> 繰り返されると、指定された関数を呼び出すことによって連続する要素を返す新しいシーケンスを生成します。関数を呼び出した結果は保存されません。つまり、要素を再生成するために必要に応じて関数が再適用されます。関数には、生成されるアイテムのインデックスが渡されます。
isEmpty:seq <'T>→bool シーケンスに要素があるかどうかをテストします。
iter :( 'T→ユニット)→seq <' T>→ユニット 指定された関数をコレクションの各要素に適用します。
iter2 :( 'T1→' T2→単位)→seq <'T1>→seq <' T2>→単位 指定された関数を2つのコレクションに同時に適用します。一方のシーケンスがもう一方のシーケンスよりも短い場合、長いシーケンスの残りの要素は無視されます。
iteri:(int→ 'T→unit)→seq <' T>→unit 指定された関数をコレクションの各要素に適用します。関数に渡される整数は、要素のインデックスを示します。
最後:seq <'T>→' T シーケンスの最後の要素を返します。
長さ:seq <'T>→int シーケンスの長さを返します。
マップ:( 'T→' U)→seq <'T>→seq <' U> コレクションの各要素に指定された関数を適用した結果を要素とする新しいコレクションを作成します。指定された関数は、オブジェクトから取得された列挙子でMoveNextメソッドを使用して要素が要求されるときに適用されます。
map2 :( 'T1→' T2→ 'U)→seq <' T1>→seq <'T2>→seq <' U> 指定された関数を2つのシーケンスの対​​応する要素のペアに適用した結果である要素を持つ新しいコレクションを作成します。一方の入力シーケンスがもう一方よりも短い場合、長いシーケンスの残りの要素は無視されます。
mapi:(int→ 'T→' U)→seq <'T>→seq <' U> コレクションの各要素に指定された関数を適用した結果を要素とする新しいコレクションを作成します。関数に渡される整数インデックスは、変換される要素のインデックス(0から)を示します。
max:seq <'T>→' T Operators.maxを使用して比較した、シーケンスのすべての要素の最大値を返します。
maxBy :( 'T→' U)→seq <'T>→' T 関数の結果でOperators.maxを使用して比較した、シーケンスのすべての要素の最大値を返します。
min:seq <'T>→' T Operators.minを使用して比較した、シーケンスのすべての要素の最低値を返します。
minBy :( 'T→' U)→seq <'T>→' T 関数の結果でOperators.minを使用して比較した、シーケンスのすべての要素の最低値を返します。
n番目:int→seq <'T>→' T コレクションのn番目の要素を計算します。
ofArray: 'T配列→seq <' T> 指定された配列をシーケンスとして表示します。
ofList: 'Tリスト→seq <' T> 指定されたリストをシーケンスとして表示します。
ペアワイズ:seq <'T>→seq <' T * 'T> 2番目の要素の先行としてのみ返される最初の要素を除いて、入力シーケンスとその先行要素の各要素のシーケンスを返します。
ピック:( 'T→' Uオプション)→seq <'T>→' U 指定された関数を連続する要素に適用し、関数が返す最初の値を返します。 Some 値。
読み取り専用:seq <'T>→seq <' T> 指定されたシーケンスオブジェクトに委任する新しいシーケンスオブジェクトを作成します。これにより、型キャストによって元のシーケンスが再検出および変更されないことが保証されます。たとえば、配列が指定された場合、返されるシーケンスは配列の要素を返しますが、返されたシーケンスオブジェクトを配列にキャストすることはできません。
削減:( 'T→' T→ 'T)→seq <' T>→ 'T シーケンスの各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。最初の2つの要素に関数を適用することから始めます。次に、この結果を3番目の要素とともに関数にフィードします。最終結果を返します。
スキャン:( '状態→' T→ '状態)→'状態→seq <'T>→seq <'状態> Seq.foldと同様ですが、オンデマンドで計算し、中間結果と最終結果のシーケンスを返します。
シングルトン: 'T→seq <' T> 1つのアイテムのみを生成するシーケンスを返します。
スキップ:int→seq <'T>→seq <' T> 基になるシーケンスの指定された数の要素をスキップして、シーケンスの残りの要素を生成するシーケンスを返します。
skipWhile :( 'T→bool)→seq <' T>→seq <'T> 指定された述語が返す間、繰り返されると、基になるシーケンスの要素をスキップするシーケンスを返します true, 次に、シーケンスの残りの要素を生成します。
ソート:seq <'T>→seq <' T> キー順に並べられたシーケンスを生成します。
sortBy :( 'T→'キー)→seq <'T>→seq <' T> シーケンスの各要素にキー生成関数を適用し、キー順に並べられたシーケンスを生成します。キーは、Operators.compareによって実装された一般的な比較を使用して比較されます。
合計:seq <^ T>→^ T シーケンス内の要素の合計を返します。
sumBy シーケンスの各要素に関数を適用して生成された結果の合計を返します。
取る:int→seq <'T>→seq <' T> 指定されたカウントまでのシーケンスの最初の要素を返します。
takeWhile :( 'T→bool)→seq <' T>→seq <'T> 繰り返されると、基になるシーケンスの要素を生成するシーケンスを返しますが、指定された述語は true, その後、それ以上の要素を返しません。
toArray:seq <'T>→' T [] 指定されたコレクションから配列を作成します。
toList:seq <'T>→' Tリスト 指定されたコレクションからリストを作成します。
切り捨て:int→seq <'T>→seq <' T> 列挙されたときに指定された数以下の要素を返すシーケンスを返します。
tryFind :( 'T→bool)→seq <' T>→ 'Tオプション 指定された関数が返す最初の要素を返します true, または None そのような要素が存在しない場合。
tryFindIndex :( 'T→bool)→seq <' T>→intオプション 指定された述語を満たすシーケンスの最初の要素のインデックスを返します。または None そのような要素が存在しない場合。
tryPick :( 'T→' Uオプション)→seq <'T>→' Uオプション 指定された関数を連続する要素に適用し、関数が返す最初の値を返します。 Some 値。
展開:( '状態→' T * '状態オプション)→'状態→seq <'T> 指定された計算によって生成された要素を含むシーケンスを返します。
ここで、:( 'T→bool)→seq <' T>→seq <'T> 指定された述語が返すコレクションの要素のみを含む新しいコレクションを返します true。Seq.filterの同義語。
ウィンドウ:int→seq <'T>→seq <' T []> 入力シーケンスから描画された要素を含むスライディングウィンドウを生成するシーケンスを返します。各ウィンドウは新しい配列として返されます。
zip:seq <'T1>→seq <' T2>→seq <'T1 *' T2> 2つのシーケンスをペアのリストに結合します。2つのシーケンスの長さは同じである必要はありません。一方のシーケンスが使い果たされると、もう一方のシーケンスの残りの要素は無視されます。
zip3:seq <'T1>→seq <' T2>→seq <'T3>→seq <' T1 * 'T2 *' T3> 3つのシーケンスを組み合わせてトリプルのリストにします。シーケンスの長さは同じである必要はありません。1つのシーケンスが使い果たされると、他のシーケンスの残りの要素は無視されます。

次の例は、上記の機能のいくつかの使用法を示しています-

例1

このプログラムは空のシーケンスを作成し、後でそれを埋めます-

(* Creating sequences *)
let emptySeq = Seq.empty
let seq1 = Seq.singleton 20

printfn"The singleton sequence:"
printfn "%A " seq1
printfn"The init sequence:"

let seq2 = Seq.init 5 (fun n -> n * 3)
Seq.iter (fun i -> printf "%d " i) seq2
printfn""

(* converting an array to sequence by using cast *)
printfn"The array sequence 1:"
let seq3 = [| 1 .. 10 |] :> seq<int>
Seq.iter (fun i -> printf "%d " i) seq3
printfn""

(* converting an array to sequence by using Seq.ofArray *)
printfn"The array sequence 2:"
let seq4 = [| 2..2.. 20 |] |> Seq.ofArray
Seq.iter (fun i -> printf "%d " i) seq4
printfn""

プログラムをコンパイルして実行すると、次の出力が生成されます。

The singleton sequence:
seq [20]
The init sequence:
0 3 6 9 12
The array sequence 1:
1 2 3 4 5 6 7 8 9 10
The array sequence 2:
2 4 6 8 10 12 14 16 18 20

注意してください-

  • Seq.emptyメソッドは、空のシーケンスを作成します。

  • Seq.singletonメソッドは、指定された1つの要素のシーケンスを作成します。

  • Seq.initメソッドは、特定の関数を使用して要素が作成されるシーケンスを作成します。

  • Seq.ofArrayメソッドとSeq.ofList <'T>メソッドは、配列とリストからシーケンスを作成します。

  • Seq.iterメソッドを使用すると、シーケンスを反復処理できます。

例2

Seq.unfoldメソッドは、状態を取得し、それを変換してシーケンス内の後続の各要素を生成する計算関数からシーケンスを生成します。

次の関数は最初の20個の自然数を生成します-

let seq1 = Seq.unfold (fun state -> if (state > 20) then None else Some(state, state + 1)) 0
printfn "The sequence seq1 contains numbers from 0 to 20."
for x in seq1 do printf "%d " x
printfn" "

プログラムをコンパイルして実行すると、次の出力が生成されます。

The sequence seq1 contains numbers from 0 to 20.
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

例3

Seq.truncateメソッドは、別のシーケンスからシーケンスを作成しますが、シーケンスを指定された要素数に制限します。

Seq.takeメソッドは、シーケンスの先頭から指定された数の要素を含む新しいシーケンスを作成します。

let mySeq = seq { for i in 1 .. 10 -> 3*i }
let truncatedSeq = Seq.truncate 5 mySeq
let takeSeq = Seq.take 5 mySeq

printfn"The original sequence"
Seq.iter (fun i -> printf "%d " i) mySeq
printfn""

printfn"The truncated sequence"
Seq.iter (fun i -> printf "%d " i) truncatedSeq
printfn""

printfn"The take sequence"
Seq.iter (fun i -> printf "%d " i) takeSeq
printfn""

プログラムをコンパイルして実行すると、次の出力が生成されます。

The original sequence
3 6 9 12 15 18 21 24 27 30
The truncated sequence
3 6 9 12 15
The take sequence
3 6 9 12 15

F#のセットは、アイテムが挿入される順序を保持せずにアイテムのコレクションとして機能するデータ構造です。セットでは、重複するエントリをコレクションに挿入することはできません。

セットの作成

セットは次の方法で作成できます-

  • Set.emptyを使用して空のセットを作成し、add関数を使用してアイテムを追加します。
  • シーケンスとリストをセットに変換します。

次のプログラムはテクニックを示しています-

(* creating sets *)
let set1 = Set.empty.Add(3).Add(5).Add(7). Add(9)
printfn"The new set: %A" set1

let weekdays = Set.ofList ["mon"; "tues"; "wed"; "thurs"; "fri"]
printfn "The list set: %A" weekdays

let set2 = Set.ofSeq [ 1 .. 2.. 10 ]
printfn "The sequence set: %A" set2

プログラムをコンパイルして実行すると、次の出力が生成されます。

The new set: set [3; 5; 7; 9]
The list set: set ["fri"; "mon"; "thurs"; "tues"; "wed"]
The sequence set: set [1; 3; 5; 7; 9]

セットの基本操作

次の表は、セットの基本的な操作を示しています-

説明
追加: 'T→Set <' T>→Set <'T> セットに要素が追加された新しいセットを返します。セットに指定された要素がすでに含まれている場合、例外は発生しません。
含む: 'T→Set <' T>→bool に評価します true 指定された要素が指定されたセットにある場合。
カウント:Set <'T>→int セット内の要素の数を返します。
違い:Set <'T>→Set <' T>→Set <'T> 2番目のセットの要素が最初のセットから削除された新しいセットを返します。
空:Set <'T> 指定されたタイプの空のセット。
存在する:( 'T→bool)→Set <' T>→bool コレクションのいずれかの要素が指定された述語を満たすかどうかをテストします。入力関数が述語であり、要素がi0 ... iNの場合、この関数は述語i0または...または述語iNを計算します。
フィルタ:( 'T→bool)→Set <' T>→Set <'T> 指定された述語が返すコレクションの要素のみを含む新しいコレクションを返します true
fold :( 'State→' T→ 'State)→' State→Set <'T>→' State 指定された累積関数をセットのすべての要素に適用します。
foldBack :( 'T→' State→ 'State)→Set <' T>→ 'State→' State 指定された累積関数をセットのすべての要素に適用します。
forall :( 'T→bool)→Set <' T>→bool コレクションのすべての要素が指定された述語を満たしているかどうかをテストします。入力関数がpで、要素がi0 ... iNの場合、この関数はp i0 && ... && piNを計算します。
交差:Set <'T>→Set <' T>→Set <'T> 2つのセットの共通部分を計算します。
crossMany:seq <Set <'T >>→Set <' T> セットのシーケンスの共通部分を計算します。シーケンスは空でない必要があります。
isEmpty:Set <'T>→bool 戻り値 true セットが空の場合。
isProperSubset:Set <'T>→Set <' T>→bool に評価します true 最初のセットのすべての要素が2番目のセットにあり、2番目のセットの少なくとも1つの要素が最初のセットにない場合。
isProperSuperset:Set <'T>→Set <' T>→bool に評価します true 2番目のセットのすべての要素が最初のセットにあり、最初のセットの少なくとも1つの要素が2番目のセットにない場合。
isSubset:Set <'T>→Set <' T>→bool に評価します true 最初のセットのすべての要素が2番目のセットにある場合。
isSuperset:Set <'T>→Set <' T>→bool に評価します true 2番目のセットのすべての要素が最初のセットにある場合。
iter :( 'T→unit)→Set <' T>→unit 比較関数に従って、指定された関数をセットの各要素に適用します。
マップ:( 'T→' U)→Set <'T>→Set <' U> 指定された関数を入力セットの各要素に適用した結果を含む新しいコレクションを返します。
maxElement:Set <'T>→' T セットに使用されている順序に従って、セットの最上位の要素を返します。
minElement:Set <'T>→' T セットに使用されている順序に従って、セットの最下位の要素を返します。
ofArray: 'T配列→Set <' T> 指定された配列と同じ要素を含むセットを作成します。
ofList: 'Tリスト→Set <' T> 指定されたリストと同じ要素を含むセットを作成します。
ofSeq:seq <'T>→Set <' T> 指定された列挙可能なオブジェクトから新しいコレクションを作成します。
パーティション:( 'T→bool)→Set <' T>→Set <'T> * Set <' T> セットを、指定された述語がそれぞれtrueとfalseを返す要素を含む2つのセットに分割します。
削除: 'T→Set <' T>→Set <'T> 指定された要素が削除された新しいセットを返します。セットに指定された要素が含まれていない場合、例外は発生しません。
シングルトン: 'T→Set <' T> 指定された要素を含むセット。
toArray:Set <'T>→' T配列 セットの要素を順番に含む配列を作成します。
toList:Set <'T>→' Tリスト セットの要素を順番に含むリストを作成します。
toSeq:Set <'T>→seq <' T> コレクションの順序付けられたビューを列挙可能なオブジェクトとして返します。
和集合:Set <'T>→Set <' T>→Set <'T> 2つのセットの和集合を計算します。
unionMany:seq <Set <'T >>→Set <' T> セットのシーケンスの和集合を計算します。

次の例は、上記の機能のいくつかの使用法を示しています-

let a = Set.ofSeq [ 1 ..2.. 20 ]
let b = Set.ofSeq [ 1 ..3 .. 20 ]
let c = Set.intersect a b
let d = Set.union a b
let e = Set.difference a b

printfn "Set a: "
Set.iter (fun x -> printf "%O " x) a
printfn""

printfn "Set b: "
Set.iter (fun x -> printf "%O " x) b
printfn""

printfn "Set c = set intersect of a and b : "
Set.iter (fun x -> printf "%O " x) c
printfn""

printfn "Set d = set union of a and b : "
Set.iter (fun x -> printf "%O " x) d
printfn""

printfn "Set e = set difference of a and b : "
Set.iter (fun x -> printf "%O " x) e
printfn""

プログラムをコンパイルして実行すると、次の出力が生成されます。

Set a:
1 3 5 7 9 11 13 15 17 19
Set b:
1 4 7 10 13 16 19
Set c = set intersect of a and b :
1 7 13 19
Set d = set union of a and b :
1 3 4 5 7 9 10 11 13 15 16 17 19
Set e = set difference of a and b :
3 5 9 11 15 17

F#では、マップは値をキーに関連付ける特別な種類のセットです。マップは、セットの作成と同様の方法で作成されます。

マップの作成

マップは、Map.emptyを使用して空のマップを作成し、追加機能を使用してアイテムを追加することによって作成されます。次の例はこれを示しています-

(* Create an empty Map *)
let students =
   Map.empty. (* Creating an empty Map *)
      Add("Zara Ali", "1501").
      Add("Rishita Gupta", "1502").
      Add("Robin Sahoo", "1503").
      Add("Gillian Megan", "1504");;
printfn "Map - students: %A" students

(* Convert a list to Map *)
let capitals =
   [ "Argentina", "Buenos Aires";
      "France ", "Paris";
      "Chili", "Santiago";
      "Malaysia", " Kuala Lumpur";
      "Switzerland", "Bern" ]
   |> Map.ofList;;
printfn "Map capitals : %A" capitals

プログラムをコンパイルして実行すると、次の出力が生成されます。

Map - students: map
[("Gillian Megan", "1504"); ("Rishita Gupta", "1502"); ("Robin Sahoo", "1503
");
("Zara Ali", "1501")]
Map capitals : map
[("Argentina", "Buenos Aires"); ("Chili", "Santiago"); ("France ", "Paris");
("Malaysia", " Kuala Lumpur"); ("Switzerland", "Bern")]

キーを使用して、マップ内の個々の要素にアクセスできます。

(* Create an empty Map *)
let students =
   Map.empty. (* Creating an empty Map *)
      Add("Zara Ali", "1501").
      Add("Rishita Gupta", "1502").
      Add("Robin Sahoo", "1503").
      Add("Gillian Megan", "1504");;
printfn "Map - students: %A" students

(*Accessing an element using key *)
printfn "%A" students.["Zara Ali"]

プログラムをコンパイルして実行すると、次の出力が生成されます。

Map - students: map
[("Gillian Megan", "1504"); ("Rishita Gupta", "1502"); ("Robin Sahoo", "1503
");
("Zara Ali", "1501")]
"1501"

マップの基本操作

モジュール名を追加

次の表は、マップの基本的な操作を示しています-

メンバー 説明
追加 指定されたマップにバインディングが追加された新しいマップを返します。
含むキー 要素がマップのドメインにあるかどうかをテストします。
カウント マップ内のバインディングの数。
IsEmpty マップにバインディングがない場合はtrueを返します。
項目 マップ内の要素を検索します。マップにバインディングが存在しない場合、KeyNotFoundExceptionが発生します。
削除する マップのドメインから要素を削除します。要素が存在しない場合、例外は発生しません。
TryFind マップ内の要素を検索し、 Some 要素がマップのドメインにある場合の値と None そうでない場合。

次の例は、上記の機能のいくつかの使用法を示しています-

(* Create an empty Map *)
let students =
   Map.empty. (* Creating an empty Map *)
      Add("Zara Ali", "1501").
      Add("Rishita Gupta", "1502").
      Add("Robin Sahoo", "1503").
      Add("Gillian Megan", "1504").
      Add("Shraddha Dubey", "1505").
      Add("Novonil Sarker", "1506").
      Add("Joan Paul", "1507");;
printfn "Map - students: %A" students
printfn "Map - number of students: %d" students.Count

(* finding the registration number of a student*)
let found = students.TryFind "Rishita Gupta"
match found with
| Some x -> printfn "Found %s." x
| None -> printfn "Did not find the specified value."

プログラムをコンパイルして実行すると、次の出力が生成されます。

Map - students: map
[("Gillian Megan", "1504"); ("Joan Paul", "1507"); ("Novonil Sarker", "1506"
);
("Rishita Gupta", "1502"); ("Robin Sahoo", "1503");
("Shraddha Dubey", "1505"); ("Zara Ali", "1501")]
Map - number of students: 7
Found 1502.

共用体、または識別された共用体を使用すると、明確に定義された選択肢のセットを表す複雑なデータ構造を構築できます。たとえば、yesとnoの2つの値を持つchoice変数の実装を構築する必要があります。ユニオンツールを使用して、これを設計できます。

構文

識別された共用体は、次の構文を使用して定義されます-

type type-name =
   | case-identifier1 [of [ fieldname1 : ] type1 [ * [ fieldname2 : ] 
type2 ...]
   | case-identifier2 [of [fieldname3 : ]type3 [ * [ fieldname4 : ]type4 ...]
...

choiceの単純な実装は、次のようになります。

type choice =
   | Yes
   | No

次の例では、タイプの選択を使用しています-

type choice =
   | Yes
   | No

let x = Yes (* creates an instance of choice *)
let y = No (* creates another instance of choice *)
let main() =
   printfn "x: %A" x
   printfn "y: %A" y
main()

プログラムをコンパイルして実行すると、次の出力が生成されます。

x: Yes
y: No

例1

次の例は、ビットをハイまたはローに設定する電圧状態の実装を示しています。

type VoltageState =
   | High
   | Low

let toggleSwitch = function (* pattern matching input *)
   | High -> Low
   | Low -> High

let main() =
   let on = High
   let off = Low
   let change = toggleSwitch off

   printfn "Switch on state: %A" on
   printfn "Switch off state: %A" off
   printfn "Toggle off: %A" change
   printfn "Toggle the Changed state: %A" (toggleSwitch change)

main()

プログラムをコンパイルして実行すると、次の出力が生成されます。

Switch on state: High
Switch off state: Low
Toggle off: High
Toggle the Changed state: Low

例2

type Shape =
   // here we store the radius of a circle
   | Circle of float

   // here we store the side length.
   | Square of float

   // here we store the height and width.
   | Rectangle of float * float

let pi = 3.141592654

let area myShape =
   match myShape with
   | Circle radius -> pi * radius * radius
   | Square s -> s * s
   | Rectangle (h, w) -> h * w

let radius = 12.0
let myCircle = Circle(radius)
printfn "Area of circle with radius %g: %g" radius (area myCircle)

let side = 15.0
let mySquare = Square(side)
printfn "Area of square that has side %g: %g" side (area mySquare)

let height, width = 5.0, 8.0
let myRectangle = Rectangle(height, width)
printfn "Area of rectangle with height %g and width %g is %g" height width (area myRectangle)

プログラムをコンパイルして実行すると、次の出力が生成されます。

Area of circle with radius 12: 452.389
Area of square that has side 15: 225
Area of rectangle with height 5 and width 8 is 40

F#の変数は immutable,つまり、変数が値にバインドされると、それを変更することはできません。これらは実際には静的な読み取り専用プロパティとしてコンパイルされます。

次の例はこれを示しています。

let x = 10
let y = 20
let z = x + y

printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z

let x = 15
let y = 20
let z = x + y

printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z

プログラムをコンパイルして実行すると、次のエラーメッセージが表示されます-

Duplicate definition of value 'x'
Duplicate definition of value 'Y'
Duplicate definition of value 'Z'

可変変数

変数に格納されている値を変更する必要がある場合があります。プログラムの後半で宣言および割り当てられた変数の値が変更される可能性があることを指定するために、F#はmutableキーワード。このキーワードを使用して、値を変更する可変変数を宣言して割り当てることができます。

ザ・ mutable キーワードを使用すると、可変変数で値を宣言して割り当てることができます。

を使用して、可変変数に初期値を割り当てることができます。 letキーワード。ただし、それに新しい後続の値を割り当てるには、を使用する必要があります<- オペレーター。

例えば、

let mutable x = 10
x <- 15

次の例は、概念をクリアします-

let mutable x = 10
let y = 20
let mutable z = x + y

printfn "Original Values:"
printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z

printfn "Let us change the value of x"
printfn "Value of z will change too."

x <- 15
z <- x + y

printfn "New Values:"
printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z

プログラムをコンパイルして実行すると、次の出力が生成されます。

Original Values:
x: 10
y: 20
z: 30
Let us change the value of x
Value of z will change too.
New Values:
x: 15
y: 20
z: 35

可変データの使用

可変データは、データ処理、特にレコードデータ構造で必要とされ、使用されることがよくあります。次の例はこれを示しています-

open System

type studentData =
   { ID : int;
      mutable IsRegistered : bool;
      mutable RegisteredText : string; }

let getStudent id =
   { ID = id;
      IsRegistered = false;
      RegisteredText = null; }

let registerStudents (students : studentData list) =
   students |> List.iter(fun st ->
      st.IsRegistered <- true
      st.RegisteredText <- sprintf "Registered %s" (DateTime.Now.ToString("hh:mm:ss"))

      Threading.Thread.Sleep(1000) (* Putting thread to sleep for 1 second to simulate processing overhead. *))

let printData (students : studentData list) =
   students |> List.iter (fun x -> printfn "%A" x)

let main() =
   let students = List.init 3 getStudent

   printfn "Before Process:"
   printData students

   printfn "After process:"
   registerStudents students
   printData students

   Console.ReadKey(true) |> ignore

main()

プログラムをコンパイルして実行すると、次の出力が生成されます。

Before Process:
{ID = 0;
IsRegistered = false;
RegisteredText = null;}
{ID = 1;
IsRegistered = false;
RegisteredText = null;}
{ID = 2;
IsRegistered = false;
RegisteredText = null;}
After process:
{ID = 0;
IsRegistered = true;
RegisteredText = "Registered 05:39:15";}
{ID = 1;
IsRegistered = true;
RegisteredText = "Registered 05:39:16";}
{ID = 2;
IsRegistered = true;
RegisteredText = "Registered 05:39:17";}

配列は、すべて同じタイプの連続するデータ要素の固定サイズのゼロベースの可変コレクションです。

配列の作成

さまざまな構文と方法を使用するか、配列モジュールの関数を使用して、配列を作成できます。このセクションでは、モジュール関数を使用せずに配列を作成する方法について説明します。

関数なしで配列を作成する構文上の方法は3つあります-

  • [|の間の連続する値をリストすることによって および|]およびセミコロンで区切られます。
  • 各要素を別々の行に配置する。この場合、セミコロン区切り文字はオプションです。
  • シーケンス式を使用する。

ドット演算子(。)と角かっこ([および])を使用して、配列要素にアクセスできます。

次の例は、配列の作成を示しています-

//using semicolon separator
let array1 = [| 1; 2; 3; 4; 5; 6 |]
for i in 0 .. array1.Length - 1 do
   printf "%d " array1.[i]
printfn" "

// without semicolon separator
let array2 =
   [|
      1
      2
      3
      4
      5
   |]
for i in 0 .. array2.Length - 1 do
   printf "%d " array2.[i]
printfn" "

//using sequence
let array3 = [| for i in 1 .. 10 -> i * i |]
for i in 0 .. array3.Length - 1 do
   printf "%d " array3.[i]
printfn" "

プログラムをコンパイルして実行すると、次の出力が生成されます。

1 2 3 4 5 6
1 2 3 4 5
1 4 9 16 25 36 49 64 81 100

配列の基本操作

ライブラリモジュールMicrosoft.FSharp.Collections.Arrayは、1次元配列の操作をサポートしています。

次の表に、配列の基本的な操作を示します。

説明
追加: 'T []→' T []→ 'T [] ある配列の要素とそれに続く別の配列の要素を含む配列を作成します。
平均:^ T []→^ T 配列内の要素の平均を返します。
AverageBy :( 'T→^ U)→' T []→^ U 配列の各要素に関数を適用することによって生成された要素の平均を返します。
blit: 'T []→int→' T []→int→int→unit ある配列から要素の範囲を読み取り、それらを別の配列に書き込みます。
選択:( 'T→Uオプション)→' T []→ 'U [] 提供された関数を配列の各要素に適用します。関数がSome(x)を返す各要素の結果xを含む配列を返します。
収集:( 'T→' U [])→T []→ 'U [] 提供された関数を配列の各要素に適用し、結果を連結して、結合された配列を返します。
concat:seq <'T []>→' T [] 提供された配列の各シーケンスの要素を含む配列を作成します。
コピー: 'T→' T [] 指定された配列の要素を含む配列を作成します。
create:int→ 'T→' T [] 要素がすべて最初に指定された値である配列を作成します。
空: 'T [] 指定されたタイプの空の配列を返します。
存在する:( 'T→bool)→' T []→bool 配列のいずれかの要素が指定された述語を満たすかどうかをテストします。
存在2 :( 'T1→' T2→bool)→ 'T1 []→' T2 []→bool 2つの配列の対応する要素のいずれかのペアが、指定された条件を満たすかどうかをテストします。
塗りつぶし: 'T []→int→int→' T→unit 配列の要素の範囲を指定された値で埋めます。
フィルタ:( 'T→bool)→' T []→ 'T [] 指定された条件が返す指定された配列の要素のみを含むコレクションを返します true
検索:( 'T→bool)→' T []→ 'T 指定された関数が返す最初の要素を返します true。そのような要素が存在しない場合、KeyNotFoundExceptionを発生させます。
findIndex :( 'T→bool)→' T []→int 指定された条件を満たす配列の最初の要素のインデックスを返します。どの要素も条件を満たさない場合、KeyNotFoundExceptionを発生させます。
fold :( '状態→' T→ '状態)→'状態→ 'T []→'状態 配列の各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。入力関数がfで、配列要素がi0 ... iNの場合、この関数はf(...(fs i0)...)iNを計算します。
fold2 :( '状態→' T1→ 'T2→'状態)→ '状態→' T1 []→ 'T2 []→'状態 提供された2つの配列の要素のペアに関数を左から右に適用し、計算を通じてアキュムレータ引数をスレッド化します。2つの入力配列は同じ長さである必要があります。それ以外の場合、ArgumentExceptionが発生します。
foldBack :( 'T→'状態→ '状態)→' T []→ '状態→'状態 配列の各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。入力関数がfで、配列要素がi0 ... iNの場合、この関数はf i0(...(f iN s))を計算します。
foldBack2 :( 'T1→' T2→ '状態→'状態)→ 'T1 []→' T2 []→ '状態→'状態 提供された2つの配列の要素のペアに関数を右から左に適用し、計算を通じてアキュムレータ引数をスレッド化します。2つの入力配列は同じ長さである必要があります。それ以外の場合、ArgumentExceptionが発生します。
forall :( 'T→bool)→' T []→bool 配列のすべての要素が指定された条件を満たすかどうかをテストします。
forall2 :( 'T1→' T2→bool)→ 'T1 []→' T2 []→bool 提供された2つの配列の対応するすべての要素が、提供された条件を満たすかどうかをテストします。
get: 'T []→int→' T 配列から要素を取得します。
init:int→(int→ 'T)→' T [] 提供された関数を使用して、提供された次元の配列を作成します。
isEmpty: 'T []→bool 配列に要素があるかどうかをテストします。
iter :( 'T→ユニット)→' T []→ユニット 提供された関数を配列の各要素に適用します。
iter2 :( 'T1→' T2→単位)→ 'T1 []→' T2 []→単位) 提供された関数を、2つの配列の一致するインデックスからの要素のペアに適用します。2つの配列の長さは同じである必要があります。それ以外の場合、ArgumentExceptionが発生します。
iteri:(int→ 'T→unit)→' T []→unit 提供された関数を配列の各要素に適用します。関数に渡される整数は、要素のインデックスを示します。
iteri2:(int→ 'T1→' T2→unit)→ 'T1 []→' T2 []→unit 提供された関数を、2つの配列の一致するインデックスから要素のペアに適用し、要素のインデックスも渡します。2つの配列の長さは同じである必要があります。それ以外の場合は、ArgumentExceptionが発生します。
長さ: 'T []→int 配列の長さを返します。Lengthプロパティは同じことをします。
マップ:( 'T→' U)→ 'T []→' U [] 提供された配列の各要素に提供された関数を適用した結果である要素を持つ配列を作成します。
map2 :( 'T1→' T2→ 'U)→' T1 []→ 'T2 []→' U [] 提供された関数を2つの提供された配列の対応する要素に適用した結果である要素を持つ配列を作成します。2つの入力配列は同じ長さである必要があります。それ以外の場合、ArgumentExceptionが発生します。
mapi:(int→ 'T→' U)→ 'T []→' U [] 提供された配列の各要素に提供された関数を適用した結果である要素を持つ配列を作成します。関数に渡される整数インデックスは、変換される要素のインデックスを示します。
mapi2:(int→ 'T1→' T2→ 'U)→' T1 []→ 'T2 []→' U [] 提供された関数を2つのコレクションの対応する要素にペアごとに適用した結果である要素を持つ配列を作成し、要素のインデックスも渡します。2つの入力配列は同じ長さである必要があります。それ以外の場合、ArgumentExceptionが発生します。
最大: 'T []→' T 配列のすべての要素の中で最大のものを返します。Operators.maxは、要素を比較するために使用されます。
maxBy :( 'T→' U)→ 'T []→' T 関数の結果でOperators.maxを介して比較された、配列のすべての要素の最大値を返します。
分:( 'T []→' T 配列のすべての要素の最小値を返します。Operators.minは、要素を比較するために使用されます。
minBy :( 'T→' U)→ 'T []→' T 配列のすべての要素の最小値を返します。Operators.minは、要素を比較するために使用されます。
ofList: 'Tリスト→' T [] 指定されたリストから配列を作成します。
ofSeq:seq <'T>→' T [] 指定された列挙可能なオブジェクトから配列を作成します。
パーティション:( 'T→bool)→' T []→ 'T [] *' T [] 配列を2つの配列に分割し、1つは指定された条件が返す要素を含みます true, そしてそれが返すものを含む他のもの false
順列:(int→int)→ 'T []→' T [] 指定された順列に従って配列の要素を並べ替えます。
ピック:( 'T→' Uオプション)→ 'T []→' U 指定された関数を指定された配列の連続する要素に適用し、関数がいくつかのxに対してSome(x)を返す最初の結果を返します。関数がSome(x)を返さない場合、KeyNotFoundExceptionが発生します。
削減:( 'T→' T→ 'T)→' T []→ 'T 配列の各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。入力関数がfで、配列要素がi0 ... iNの場合、この関数はf(...(f i0 i1)...)iNを計算します。配列のサイズがゼロの場合、ArgumentExceptionが発生します。
reduceBack :( 'T→' T→ 'T)→' T []→ 'T 配列の各要素に関数を適用し、計算を通じてアキュムレータ引数をスレッド化します。入力関数がfで、要素がi0 ... iNの場合、この関数はf i0(...(f iN-1 iN))を計算します。配列のサイズがゼロの場合、ArgumentExceptionが発生します。
rev: 'T []→' T [] 指定された配列内の要素の順序を逆にします。
スキャン:( '状態→' T→ '状態)→'状態→ 'T []→'状態[]) foldのように動作しますが、中間結果と最終結果を返します。
scanBack :( 'T→'状態→ '状態)→' T []→ '状態→'状態[] foldBackのように動作しますが、中間結果と最終結果を返します。
セット: 'T []→int→' T→unit 配列の要素を設定します。
並べ替え: 'T []→' T [] 配列の要素を並べ替えて、新しい配列を返します。Operators.compareは、要素を比較するために使用されます。
sortBy :( 'T→'キー)→ 'T []→' T [] 提供されている関数を使用して配列の要素を並べ替え、要素を並べ替え操作の基になる型に変換し、新しい配列を返します。Operators.compareは、要素を比較するために使用されます。
sortInPlace: 'T []→ユニット 提供されている比較関数を使用して、配列を所定の位置に変更することにより、配列の要素を並べ替えます。Operators.compareは、要素を比較するために使用されます。
sortInPlaceBy :( 'T→'キー)→ 'T []→ユニット 提供されているキーの射影を使用して、配列を所定の位置に変更することにより、配列の要素を並べ替えます。Operators.compareは、要素を比較するために使用されます。
sortInPlaceWith :( 'T→' T→int)→ 'T []→unit 提供されている比較関数を使用して配列の要素を並べ替え、配列を所定の位置に変更します。
sortWith :( 'T→' T→int)→ 'T []→' T [] 提供されている比較関数を使用して配列の要素を並べ替え、新しい配列を返します。
sub: 'T []→int→int→' T [] 開始インデックスと長さで指定された、指定されたサブ範囲を含む配列を作成します。
合計: 'T []→^ T 配列内の要素の合計を返します。
sumBy :( 'T→^ U)→' T []→^ U 配列の各要素に関数を適用して生成された結果の合計を返します。
toList: 'T []→' Tリスト 指定された配列をリストに変換します。
toSeq: 'T []→seq <' T> 指定された配列をシーケンスとして表示します。
tryFind :( 'T→bool)→' T []→ 'Tオプション 指定された関数が返す、指定された配列の最初の要素を返します true。戻り値None そのような要素が存在しない場合。
tryFindIndex :( 'T→bool)→' T []→intオプション 指定された条件を満たす配列の最初の要素のインデックスを返します。
tryPick :( 'T→' Uオプション)→ 'T []→' Uオプション 指定された関数を指定された配列の連続する要素に適用し、関数がいくつかのxに対してSome(x)を返す最初の結果を返します。関数がSome(x)を返さない場合は、None が返されます。
解凍:( 'T1 *' T2)[]→ 'T1 [] *' T2 [] タプルペアの配列を2つの配列のタプルに分割します。
unzip3 :( 'T1 *' T2 * 'T3)[]→' T1 [] * 'T2 [] *' T3 [] 3つの要素のタプルの配列を3つの配列のタプルに分割します。
zeroCreate:int→ 'T [] 要素が最初にデフォルト値Unchecked.defaultof <'T>に設定されている配列を作成します。
zip: 'T1 []→' T2 []→( 'T1 *' T2)[] 2つの配列を、2つの要素を持つタプルの配列に結合します。2つの配列の長さは同じである必要があります。それ以外の場合、ArgumentExceptionが発生します。
zip3: 'T1 []→' T2 []→ 'T3 []→(' T1 * 'T2 * 113' T3)[] 3つの配列を、3つの要素を持つタプルの配列に結合します。3つの配列の長さは同じでなければなりません。それ以外の場合、ArgumentExceptionが発生します。

次のセクションでは、これらの機能のいくつかの使用法を見ていきます。

関数を使用した配列の作成

配列モジュールは、配列を最初から作成するいくつかの関数を提供します。

  • ザ・ Array.empty 関数は新しい空の配列を作成します。

  • ザ・ Array.create 関数は、指定されたサイズの配列を作成し、すべての要素を指定された値に設定します。

  • ザ・ Array.init 関数は、要素を生成するための次元と関数を指定して、配列を作成します。

  • ザ・ Array.zeroCreate 関数は、すべての要素がゼロ値に初期化される配列を作成します。

  • ザ・ Array.copy 関数は、既存の配列からコピーされた要素を含む新しい配列を作成します。

  • ザ・ Array.sub 関数は、配列のサブ範囲から新しい配列を生成します。

  • ザ・ Array.append 関数は、2つの既存の配列を組み合わせて新しい配列を作成します。

  • ザ・ Array.choose 関数は、新しい配列に含める配列の要素を選択します。

  • ザ・ Array.collect 関数は、既存の配列の各配列要素で指定された関数を実行し、関数によって生成された要素を収集して、それらを新しい配列に結合します。

  • ザ・ Array.concat 関数は配列のシーケンスを受け取り、それらを1つの配列に結合します。

  • ザ・ Array.filter functionはブール条件関数を受け取り、条件が真である入力配列からの要素のみを含む新しい配列を生成します。

  • ザ・ Array.rev 関数は、既存の配列の順序を逆にすることによって新しい配列を生成します。

次の例は、これらの機能を示しています-

例1

(* using create and set *)
let array1 = Array.create 10 ""
for i in 0 .. array1.Length - 1 do
   Array.set array1 i (i.ToString())
for i in 0 .. array1.Length - 1 do
   printf "%s " (Array.get array1 i)
printfn " "

(* empty array *)
let array2 = Array.empty
printfn "Length of empty array: %d" array2.Length

let array3 = Array.create 10 7.0
printfn "Float Array: %A" array3

(* using the init and zeroCreate *)
let array4 = Array.init 10 (fun index -> index * index)
printfn "Array of squares: %A" array4

let array5 : float array = Array.zeroCreate 10
let (myZeroArray : float array) = Array.zeroCreate 10
printfn "Float Array: %A" array5

プログラムをコンパイルして実行すると、次の出力が生成されます。

0 1 2 3 4 5 6 7 8 9
Length of empty array: 0
Float Array: [|7.0; 7.0; 7.0; 7.0; 7.0; 7.0; 7.0; 7.0; 7.0; 7.0|]
Array of squares: [|0; 1; 4; 9; 16; 25; 36; 49; 64; 81|]
Float Array: [|0.0; 0.0; 0.0; 0.0; 0.0; 0.0; 0.0; 0.0; 0.0; 0.0|]

例2

(* creating subarray from element 5 *)
(* containing 15 elements thereon *)

let array1 = [| 0 .. 50 |]
let array2 = Array.sub array1 5 15
printfn "Sub Array:"
printfn "%A" array2

(* appending two arrays *)
let array3 = [| 1; 2; 3; 4|]
let array4 = [| 5 .. 9 |]
printfn "Appended Array:"
let array5 = Array.append array3 array4
printfn "%A" array5

(* using the Choose function *)
let array6 = [| 1 .. 20 |]
let array7 = Array.choose (fun elem -> if elem % 3 = 0 then
                                             Some(float (elem))
                                          else
                                             None) array6
printfn "Array with Chosen elements:"
printfn "%A" array7

(*using the Collect function *)
let array8 = [| 2 .. 5 |]
let array9 = Array.collect (fun elem -> [| 0 .. elem - 1 |]) array8
printfn "Array with collected elements:"
printfn "%A" array9

プログラムをコンパイルして実行すると、次の出力が生成されます。

Sub Array:
[|5; 6; 7; 8; 9; 10; 11; 12; 13; 14; 15; 16; 17; 18; 19|]
Appended Array:
[|1; 2; 3; 4; 5; 6; 7; 8; 9|]
Array with Chosen elements:
[|3.0; 6.0; 9.0; 12.0; 15.0; 18.0|]
Array with collected elements:
[|0; 1; 0; 1; 2; 0; 1; 2; 3; 0; 1; 2; 3; 4|]

配列の検索

ザ・ Array.find functionはブール関数を取り、関数がtrueを返す最初の要素を返します。それ以外の場合はKeyNotFoundExceptionを発生させます。

ザ・ Array.findIndex 関数は、要素自体ではなく要素のインデックスを返すことを除いて、同様に機能します。

次の例はこれを示しています。

マイクロソフトは、この興味深いプログラムの例を提供しています。この例では、指定された数値の範囲内で、完全な正方形と完全な立方体の両方である最初の要素を見つけます。

let array1 = [| 2 .. 100 |]
let delta = 1.0e-10
let isPerfectSquare (x:int) =
   let y = sqrt (float x)
   abs(y - round y) < delta

let isPerfectCube (x:int) =
   let y = System.Math.Pow(float x, 1.0/3.0)
   abs(y - round y) < delta

let element = Array.find (fun elem -> isPerfectSquare elem && isPerfectCube elem) array1

let index = Array.findIndex (fun elem -> isPerfectSquare elem && isPerfectCube elem) array1

printfn "The first element that is both a square and a cube is %d and its index is %d." element index

プログラムをコンパイルして実行すると、次の出力が生成されます。

The first element that is both a square and a cube is 64 and its index is 62.

ザ・ List<'T> classは、インデックスでアクセスできるオブジェクトの厳密に型指定されたリストを表します。

これは、Listクラスの変更可能な対応物です。インデックスからアクセスできるという点で配列に似ていますが、配列とは異なり、リストのサイズを変更できます。したがって、宣言時にサイズを指定する必要はありません。

可変リストの作成

リストは、 newキーワードとリストのコンストラクターの呼び出し。次の例はこれを示しています-

(* Creating a List *)
open System.Collections.Generic

let booksList = new List<string>()
booksList.Add("Gone with the Wind")
booksList.Add("Atlas Shrugged")
booksList.Add("Fountainhead")
booksList.Add("Thornbirds")
booksList.Add("Rebecca")
booksList.Add("Narnia")

booksList |> Seq.iteri (fun index item -> printfn "%i: %s" index booksList.[index])

プログラムをコンパイルして実行すると、次の出力が生成されます。

0: Gone with the Wind
1: Atlas Shrugged
2: Fountainhead
3: Thornbirds
4: Rebecca
5: Narnia

List(T)クラス

List(T)クラスは、インデックスでアクセスできるオブジェクトの厳密に型指定されたリストを表します。リストを検索、ソート、および操作するためのメソッドを提供します。

次の表に、List(T)クラスのプロパティ、コンストラクター、およびメソッドを示します。

プロパティ

プロパティ 説明
容量 内部データ構造がサイズ変更せずに保持できる要素の総数を取得または設定します。
カウント List(T)に含まれる要素の数を取得します。
項目 指定されたインデックスで要素を取得または設定します。

コンストラクター

コンストラクタ 説明
リスト(T)() 空でデフォルトの初期容量を持つList(T)クラスの新しいインスタンスを初期化します。
List(T)(IEnumerable(T)) 指定されたコレクションからコピーされた要素を含み、コピーされた要素の数に対応するのに十分な容量を持つList(T)クラスの新しいインスタンスを初期化します。
リスト(T)(Int32) 空で、指定された初期容量を持つList(T)クラスの新しいインスタンスを初期化します。

方法

メソッド 説明
追加 List(T)の最後にオブジェクトを追加します。
AddRange 指定されたコレクションの要素をList(T)の最後に追加します。
AsReadOnly 現在のコレクションの読み取り専用IList(T)ラッパーを返します。
BinarySearch(T) デフォルトの比較子を使用して、ソートされたリスト(T)全体で要素を検索し、要素のゼロベースのインデックスを返します。
BinarySearch(T、IComparer(T)) 指定された比較子を使用して、ソートされたリスト(T)全体で要素を検索し、要素のゼロベースのインデックスを返します。
BinarySearch(Int32、Int32、T、IComparer(T)) 指定された比較子を使用して、ソートされたList(T)内の要素の範囲で要素を検索し、要素のゼロベースのインデックスを返します。
晴れ List(T)からすべての要素を削除します。
含まれています 要素がList(T)にあるかどうかを判別します。
ConvertAll(TOutput) 現在のList(T)の要素を別のタイプに変換し、変換された要素を含むリストを返します。
CopyTo(T []) List(T)全体を、ターゲット配列の先頭から始めて、互換性のある1次元配列にコピーします。
CopyTo(T []、Int32) List(T)全体を、ターゲット配列の指定されたインデックスから始めて、互換性のある1次元配列にコピーします。
CopyTo(Int32、T []、Int32、Int32) List(T)から互換性のある一次元配列に、ターゲット配列の指定されたインデックスから開始して、要素の範囲をコピーします。
Equals(Object) 指定されたオブジェクトが現在のオブジェクトと等しいかどうかを判別します。(オブジェクトから継承されます。)
存在する List(T)に、指定された述部によって定義された条件に一致する要素が含まれているかどうかを判別します。
ファイナライズ オブジェクトがガベージコレクション(オブジェクトから継承)によって再利用される前に、リソースを解放し、他のクリーンアップ操作を実行できるようにします。
検索 指定された述語によって定義された条件に一致する要素を検索し、List(T)全体の中で最初に出現したものを返します。
FindAll 指定された述部によって定義された条件に一致するすべての要素を取得します。
FindIndex(Predicate(T)) 指定された述語によって定義された条件に一致する要素を検索し、List(T)全体の中で最初に出現するゼロベースのインデックスを返します。
FindIndex(Int32、Predicate(T)) 指定された述語によって定義された条件に一致する要素を検索し、指定されたインデックスから最後の要素までのList(T)内の要素の範囲内で最初に出現したゼロベースのインデックスを返します。
FindIndex(Int32、Int32、Predicate(T)) 指定された述語によって定義された条件に一致する要素を検索し、指定されたインデックスから始まり、指定された数の要素を含むList(T)内の要素の範囲内で最初に出現するゼロベースのインデックスを返します。
FindLast 指定された述語によって定義された条件に一致する要素を検索し、List(T)全体の中で最後に出現したものを返します。
FindLastIndex(Predicate(T)) 指定された述語によって定義された条件に一致する要素を検索し、List(T)全体の中で最後に出現したゼロベースのインデックスを返します。
FindLastIndex(Int32、Predicate(T)) 指定された述部によって定義された条件に一致する要素を検索し、最初の要素から指定されたインデックスまでのList(T)内の要素の範囲内で最後に出現したゼロベースのインデックスを返します。
FindLastIndex(Int32、Int32、Predicate(T)) 指定された述部によって定義された条件に一致する要素を検索し、指定された数の要素を含み、指定されたインデックスで終了するList(T)内の要素の範囲内で最後に出現したゼロベースのインデックスを返します。
ForEach List(T)の各要素に対して指定されたアクションを実行します。
GetEnumerator List(T)を反復処理する列挙子を返します。
GetHashCode デフォルトのハッシュ関数として機能します。(オブジェクトから継承されます。)
GetRange ソースList(T)内の要素の範囲の浅いコピーを作成します。
GetType 現在のインスタンスのタイプを取得します。(オブジェクトから継承されます。)
IndexOf(T) 指定されたオブジェクトを検索し、List(T)全体の中で最初に出現したゼロベースのインデックスを返します。
IndexOf(T、Int32) 指定されたオブジェクトを検索し、指定されたインデックスから最後の要素までのList(T)内の要素の範囲内で最初に出現したゼロベースのインデックスを返します。
IndexOf(T、Int32、Int32) 指定されたオブジェクトを検索し、指定されたインデックスから始まり、指定された数の要素を含むList(T)内の要素の範囲内で最初に出現するゼロベースのインデックスを返します。
インサート 指定されたインデックスのList(T)に要素を挿入します。
InsertRange コレクションの要素を、指定されたインデックスのList(T)に挿入します。
LastIndexOf(T) 指定されたオブジェクトを検索し、List(T)全体の中で最後に出現したゼロベースのインデックスを返します。
LastIndexOf(T、Int32) 指定されたオブジェクトを検索し、最初の要素から指定されたインデックスまでのList(T)内の要素の範囲内で最後に出現したゼロベースのインデックスを返します。
LastIndexOf(T、Int32、Int32) 指定されたオブジェクトを検索し、指定された数の要素を含み、指定されたインデックスで終了するList(T)内の要素の範囲内で最後に出現したゼロベースのインデックスを返します。
MemberwiseClone 現在のオブジェクトの浅いコピーを作成します。(オブジェクトから継承されます。)
削除する List(T)から特定のオブジェクトの最初の出現を削除します。
すべて削除する 指定された述部によって定義された条件に一致するすべての要素を削除します。
RemoveAt List(T)の指定されたインデックスにある要素を削除します。
RemoveRange List(T)から要素の範囲を削除します。
逆行する() List(T)全体の要素の順序を逆にします。
Reverse(Int32、Int32) 指定された範囲内の要素の順序を逆にします。
ソート() デフォルトの比較子を使用して、List(T)全体の要素を並べ替えます。
並べ替え(比較(T)) 指定されたシステムを使用して、List(T)全体の要素を並べ替えます。比較(T)。
Sort(IComparer(T)) 指定された比較子を使用して、List(T)全体の要素を並べ替えます。
Sort(Int32、Int32、IComparer(T)) 指定された比較子を使用して、List(T)内の要素の範囲内の要素を並べ替えます。
ToArray List(T)の要素を新しい配列にコピーします。
ToString 現在のオブジェクトを表す文字列を返します。(オブジェクトから継承されます。)
TrimExcess リスト(T)の要素の数がしきい値よりも小さい場合、その数に容量を設定します。
TrueForAll List(T)内のすべての要素が、指定された述部によって定義された条件に一致するかどうかを判別します。

(* Creating a List *)
open System.Collections.Generic

let booksList = new List<string>()
booksList.Add("Gone with the Wind")
booksList.Add("Atlas Shrugged")
booksList.Add("Fountainhead")
booksList.Add("Thornbirds")
booksList.Add("Rebecca")
booksList.Add("Narnia")

printfn"Total %d books" booksList.Count
booksList |> Seq.iteri (fun index item -> printfn "%i: %s" index booksList.[index])
booksList.Insert(2, "Roots")

printfn("after inserting at index 2")
printfn"Total %d books" booksList.Count

booksList |> Seq.iteri (fun index item -> printfn "%i: %s" index booksList.[index])
booksList.RemoveAt(3)

printfn("after removing from index 3")
printfn"Total %d books" booksList.Count

booksList |> Seq.iteri (fun index item -> printfn "%i: %s" index booksList.[index])

プログラムをコンパイルして実行すると、次の出力が生成されます。

Total 6 books
0: Gone with the Wind
1: Atlas Shrugged
2: Fountainhead
3: Thornbirds
4: Rebecca
5: Narnia
after inserting at index 2
Total 7 books
0: Gone with the Wind
1: Atlas Shrugged
2: Roots
3: Fountainhead
4: Thornbirds
5: Rebecca
6: Narnia
after removing from index 3
Total 6 books
0: Gone with the Wind
1: Atlas Shrugged
2: Roots
3: Thornbirds
4: Rebecca
5: Narnia

ザ・ Dictionary<'TKey, 'TValue> クラスはF#マップデータ構造の可変アナログであり、同じ関数の多くが含まれています。

F#のマップの章から要約すると、マップは値をキーに関連付ける特別な種類のセットです。

可変辞書の作成

可変辞書は、 newキーワードとリストのコンストラクターの呼び出し。次の例はこれを示しています-

open System.Collections.Generic
let dict = new Dictionary<string, string>()
dict.Add("1501", "Zara Ali")
dict.Add("1502","Rishita Gupta")
dict.Add("1503","Robin Sahoo")
dict.Add("1504","Gillian Megan")
printfn "Dictionary - students: %A" dict

プログラムをコンパイルして実行すると、次の出力が生成されます。

Dictionary - students: seq
[[1501, Zara Ali]; [1502, Rishita Gupta]; [1503, Robin Sahoo];
[1504, Gillian Megan]]

Dictionary(TKey、TValue)クラス

Dictionary(TKey、TValue)クラスは、キーと値のコレクションを表します。

次の表に、List(T)クラスのプロパティ、コンストラクター、およびメソッドを示します。

プロパティ

プロパティ 説明
比較者 ディクショナリのキーの同等性を判別するために使用されるIEqualityComparer(T)を取得します。
カウント Dictionary(TKey、TValue)に含まれるキーと値のペアの数を取得します。
項目 指定されたキーに関連付けられた値を取得または設定します。
キー Dictionary(TKey、TValue)のキーを含むコレクションを取得します。
Dictionary(TKey、TValue)の値を含むコレクションを取得します。

コンストラクター

コンストラクター 説明
Dictionary(TKey、TValue)() の新しいインスタンスを初期化します Dictionary(TKey, TValue) 空で、デフォルトの初期容量を持ち、キータイプにデフォルトの等式比較子を使用するクラス。
辞書(TKey、TValue)(IDictionary(TKey、TValue)) の新しいインスタンスを初期化します Dictionary(TKey, TValue) 指定されたものからコピーされた要素を含むクラス IDictionary(TKey, TValue) キータイプにはデフォルトの等式比較器を使用します。
辞書(TKey、TValue)(IEqualityComparer(TKey)) の新しいインスタンスを初期化します Dictionary(TKey, TValue) 空で、デフォルトの初期容量を持ち、指定されたものを使用するクラス IEqualityComparer(T).
辞書(TKey、TValue)(Int32) の新しいインスタンスを初期化します Dictionary(TKey, TValue) 空で、指定された初期容量を持ち、キータイプにデフォルトの等式比較子を使用するクラス。
辞書(TKey、TValue)(IDictionary(TKey、TValue)、IEqualityComparer(TKey)) の新しいインスタンスを初期化します Dictionary(TKey, TValue) 指定されたものからコピーされた要素を含むクラス IDictionary(TKey, TValue) 指定されたものを使用します IEqualityComparer(T).
辞書(TKey、TValue)(Int32、IEqualityComparer(TKey)) の新しいインスタンスを初期化します Dictionary(TKey, TValue) 空で、指定された初期容量を持ち、指定されたを使用するクラス IEqualityComparer(T).
辞書(TKey、TValue)(SerializationInfo、StreamingContext) の新しいインスタンスを初期化します ictionary(TKey, TValue) シリアル化されたデータを持つクラス。

メソッド

方法 説明
追加 指定されたキーと値を辞書に追加します。
晴れ ディクショナリ(TKey、TValue)からすべてのキーと値を削除します。
含むキー Dictionary(TKey、TValue)に指定されたキーが含まれているかどうかを判別します。
含む値 Dictionary(TKey、TValue)に特定の値が含まれているかどうかを判別します。
Equals(Object) 指定されたオブジェクトが現在のオブジェクトと等しいかどうかを判別します。(オブジェクトから継承されます。)
ファイナライズ ガベージコレクションによって再利用される前に、オブジェクトがリソースを解放し、他のクリーンアップ操作を実行できるようにします。(オブジェクトから継承されます。)
GetEnumerator Dictionary(TKey、TValue)を反復処理する列挙子を返します。
GetHashCode デフォルトのハッシュ関数として機能します。(オブジェクトから継承されます。)
GetObjectData System.Runtime.Serialization.ISerializableインターフェイスを実装し、Dictionary(TKey、TValue)インスタンスをシリアル化するために必要なデータを返します。
GetType 現在のインスタンスのタイプを取得します。(オブジェクトから継承されます。)
MemberwiseClone 現在のオブジェクトの浅いコピーを作成します。(オブジェクトから継承されます。)
OnDeserialization System.Runtime.Serialization.ISerializableインターフェイスを実装し、逆シリアル化が完了すると逆シリアル化イベントを発生させます。
削除する 指定されたキーを持つ値をディクショナリ(TKey、TValue)から削除します。
ToString 現在のオブジェクトを表す文字列を返します。(オブジェクトから継承されます。)
TryGetValue 指定されたキーに関連付けられた値を取得します。

open System.Collections.Generic
let dict = new Dictionary<string, string>()

dict.Add("1501", "Zara Ali")
dict.Add("1502","Rishita Gupta")
dict.Add("1503","Robin Sahoo")
dict.Add("1504","Gillian Megan")

printfn "Dictionary - students: %A" dict
printfn "Total Number of Students: %d" dict.Count
printfn "The keys: %A" dict.Keys
printf"The Values: %A" dict.Values

プログラムをコンパイルして実行すると、次の出力が生成されます。

Dictionary - students: seq
[[1501, Zara Ali]; [1502, Rishita Gupta]; [1503, Robin Sahoo];
[1504, Gillian Megan]]
Total Number of Students: 4
The keys: seq ["1501"; "1502"; "1503"; "1504"]
The Values: seq ["Zara Ali"; "Rishita Gupta"; "Robin Sahoo"; "Gillian Megan"]

基本入出力には以下が含まれます-

  • コンソールからの読み取りとコンソールへの書き込み。
  • ファイルからの読み取りとファイルへの書き込み。

Core.Printfモジュール

コンソールへの書き込みには、printf関数とprintfn関数を使用しました。このセクションでは、詳細を調べます。Printf F#のモジュール。

上記の関数とは別に、F#のCore.Printfモジュールには、プレースホルダーとして%マーカーを使用して印刷およびフォーマットするためのさまざまな方法があります。次の表に、メソッドの簡単な説明を示します。

説明
bprintf:StringBuilder→BuilderFormat <'T>→' T StringBuilderに出力します。
eprintf:TextWriterFormat <'T>→' T フォーマットされた出力をstderrに出力します。
eprintfn:TextWriterFormat <'T>→' T フォーマットされた出力をstderrに出力し、改行を追加します。
failwithf:StringFormat <'T、'結果>→ 'T 文字列バッファに出力し、指定された結果で例外を発生させます。
fprintf:TextWriter→TextWriterFormat <'T>→' T テキストライターに印刷します。
fprintfn:TextWriter→TextWriterFormat <'T>→' T 改行を追加して、テキストライターに印刷します。
kbprintf :(ユニット→ '結果)→StringBuilder→BuilderFormat <' T、 '結果>→' T bprintfと同様ですが、指定された関数を呼び出して結果を生成します。
kfprintf :(ユニット→ '結果)→TextWriter→TextWriterFormat <' T、 '結果>→' T fprintfと同様ですが、指定された関数を呼び出して結果を生成します。
kprintf :(文字列→ '結果)→StringFormat <' T、 '結果>→' T printfと同様ですが、指定された関数を呼び出して結果を生成します。たとえば、これらにより、すべての出力がチャネルに入力された後、印刷が強制的にフラッシュされますが、それ以前はフラッシュされません。
ksprintf :(文字列→ '結果)→StringFormat <' T、 '結果>→' T sprintfと同様ですが、指定された関数を呼び出して結果を生成します。
printf:TextWriterFormat <'T>→' T フォーマットされた出力をstdoutに出力します。
printfn:TextWriterFormat <'T>→' T フォーマットされた出力をstdoutに出力し、改行を追加します。
sprintf:StringFormat <'T>→' T 内部文字列バッファを使用して文字列に出力し、結果を文字列として返します。

フォーマット仕様

フォーマット仕様は、プログラマーのニーズに応じて、入力または出力をフォーマットするために使用されます。

これらは、フォーマットプレースホルダーを示す%マーカー付きの文字列です。

Formatプレースホルダーの構文は次のとおりです。

%[flags][width][.precision][type]

ザ・ type −として解釈されます

タイプ 説明
%b フォーマットa bool, 次のようにフォーマットされます true または false
%c 文字をフォーマットします。
%s フォーマットa string, エスケープ文字を解釈せずに、その内容としてフォーマットされます。
%d、%i 10進整数としてフォーマットされた基本整数タイプをフォーマットします。基本整数タイプが符号付きの場合は、符号付きです。
%u 符号なし10進整数としてフォーマットされた基本整数タイプをフォーマットします。
%バツ 小文字のaからfを使用して、符号なし16進整数としてフォーマットされた基本整数タイプをフォーマットします。
%バツ 大文字のAからFを使用して、符号なし16進整数としてフォーマットされた基本整数タイプをフォーマットします。
%o 符号なし8進整数としてフォーマットされた基本整数型をフォーマットします。
%e、%E、%f、%F、%g、%G 基本的な浮動小数点型をフォーマットします (float, float32) Cスタイルの浮動小数点形式の仕様を使用してフォーマットされます。
%e、%E [-] d.dddde [sign] dddの形式の符号付き値をフォーマットします。ここで、dは1桁の10進数、ddddは1つ以上の10進数、dddは正確に3桁の10進数、符号は+または-です。
%f [-] dddd.ddddの形式の符号付き値をフォーマットします。ここで、ddddは1つ以上の10進数です。小数点の前の桁数は数値の大きさによって異なり、小数点の後の桁数は要求された精度によって異なります。
%g、%G fまたはe形式のいずれか、指定された値と精度に対してよりコンパクトな方で印刷された符号付き値をフォーマットします。
%M 10進値をフォーマットします。
%O オブジェクトをボックス化し、そのオブジェクトを使用して印刷された任意の値をフォーマットします ToString 方法。
%A、%+ A デフォルトのレイアウト設定で印刷された任意の値をフォーマットします。%+ Aを使用して、内部表現とプライベート表現を使用して、識別された共用体の構造を出力します。
%a

一般的なフォーマット指定子には、2つの引数が必要です。最初の引数は、2つの引数を受け入れる関数です。1つは、指定されたフォーマット関数に適切なタイプのコンテキストパラメーター(たとえば、TextWriter)で、もう1つは、印刷する値であり、適切なテキストを出力または返します。

2番目の引数は、印刷する特定の値です。

%t 一般的なフォーマット指定子には、1つの引数が必要です。指定されたフォーマット関数(aTextWriter)に適切なタイプのコンテキストパラメータを受け入れ、適切なテキストを出力または返す関数です。基本的な整数型はbyte, sbyte, int16, uint16, int32, uint32, int64, uint64, nativeint, そして unativeint. 基本的な浮動小数点タイプは float そして float32.

ザ・ widthオプションのパラメータです。結果の最小幅を示す整数です。たとえば、%5dは、少なくとも5文字のスペースを持つ整数を出力します。

有効 flags 次の表で説明します-

説明
0 必要な幅を構成するために、スペースの代わりにゼロを追加することを指定します。
- 指定された幅内で結果を左揃えにすることを指定します。
+ 数値が正の場合に+文字を追加することを指定します(負の数値の-記号と一致するため)。
' ' (スペース) 数値が正の場合にスペースを追加することを指定します(負の数値の-記号と一致するため)。
無効。

printf "Hello "
printf "World"
printfn ""
printfn "Hello "
printfn "World"
printf "Hi, I'm %s and I'm a %s" "Rohit" "Medical Student"

printfn "d: %f" 212.098f
printfn "e: %f" 504.768f

printfn "x: %g" 212.098f
printfn "y: %g" 504.768f

printfn "x: %e" 212.098f
printfn "y: %e" 504.768f
printfn "True: %b" true

プログラムをコンパイルして実行すると、次の出力が生成されます。

Hello World
Hello
World
Hi, I'm Rohit and I'm a Medical Studentd: 212.098000
e: 504.768000
x: 212.098
y: 504.768
x: 2.120980e+002
y: 5.047680e+002
True: true

コンソールクラス

このクラスは、.NETFrameworkの一部です。これは、コンソールアプリケーションの標準の入力、出力、およびエラーストリームを表します。

コンソールからの読み取りおよびコンソールへの書き込みのためのさまざまな方法を提供します。次の表にメソッドを示します-

方法 説明
ビープ() コンソールスピーカーからビープ音を鳴らします。
ビープ音(Int32、Int32) コンソールスピーカーから、指定した周波数と持続時間のビープ音を鳴らします。
晴れ 表示情報のコンソールバッファおよび対応するコンソールウィンドウをクリアします。
MoveBufferArea(Int32、Int32、Int32、Int32、Int32、Int32) スクリーンバッファの指定されたソース領域を指定された宛先領域にコピーします。
MoveBufferArea(Int32、Int32、Int32、Int32、Int32、Int32、Char、ConsoleColor、ConsoleColor) スクリーンバッファの指定されたソース領域を指定された宛先領域にコピーします。
OpenStandardError() 標準エラーストリームを取得します。
OpenStandardError(Int32) 指定されたバッファサイズに設定されている標準エラーストリームを取得します。
OpenStandardInput() 標準入力ストリームを取得します。
OpenStandardInput(Int32) 指定されたバッファサイズに設定されている標準入力ストリームを取得します。
OpenStandardOutput() 標準出力ストリームを取得します。
OpenStandardOutput(Int32) 指定されたバッファサイズに設定されている標準出力ストリームを取得します。
読んだ 標準入力ストリームから次の文字を読み取ります。
ReadKey() ユーザーが次に押す文字またはファンクションキーを取得します。押されたキーがコンソールウィンドウに表示されます。
ReadKey(ブール値) ユーザーが次に押す文字またはファンクションキーを取得します。押されたキーは、オプションでコンソールウィンドウに表示されます。
読み込まれた行 標準入力ストリームから次の文字行を読み取ります。
ResetColor 前景色と背景コンソールの色をデフォルトに設定します。
SetBufferSize 画面バッファ領域の高さと幅を指定された値に設定します。
SetCursorPosition カーソルの位置を設定します。
SetError Errorプロパティを指定されたTextWriterオブジェクトに設定します。
始まる Inプロパティを指定されたTextReaderオブジェクトに設定します。
SetOut Outプロパティを指定されたTextWriterオブジェクトに設定します。
SetWindowPosition 画面バッファに対するコンソールウィンドウの位置を設定します。
SetWindowSize コンソールウィンドウの高さと幅を指定された値に設定します。
Write(ブール値) 指定されたブール値のテキスト表現を標準出力ストリームに書き込みます。
Write(Char) 指定されたUnicode文字値を標準出力ストリームに書き込みます。
Write(Char []) 指定されたUnicode文字の配列を標準出力ストリームに書き込みます。
書き込み(10進数) 指定されたDecimal値のテキスト表現を標準出力ストリームに書き込みます。
書き込み(ダブル) 指定された倍精度浮動小数点値のテキスト表現を標準出力ストリームに書き込みます。
Write(Int32) 指定された32ビットの符号付き整数値のテキスト表現を標準出力ストリームに書き込みます。
Write(Int64) 指定された64ビットの符号付き整数値のテキスト表現を標準出力ストリームに書き込みます。
Write(Object) 指定されたオブジェクトのテキスト表現を標準出力ストリームに書き込みます。
書き込み(シングル) 指定された単精度浮動小数点値のテキスト表現を標準出力ストリームに書き込みます。
Write(String) 指定された文字列値を標準出力ストリームに書き込みます。
書き込み(UInt32) 指定された32ビットの符号なし整数値のテキスト表現を標準出力ストリームに書き込みます。
書き込み(UInt64) 指定された64ビットの符号なし整数値のテキスト表現を標準出力ストリームに書き込みます。
Write(String、Object) 指定されたフォーマット情報を使用して、指定されたオブジェクトのテキスト表現を標準出力ストリームに書き込みます。
Write(String、Object []) 指定されたフォーマット情報を使用して、指定されたオブジェクトの配列のテキスト表現を標準出力ストリームに書き込みます。
Write(Char []、Int32、Int32) 指定されたUnicode文字のサブ配列を標準出力ストリームに書き込みます。
Write(String、Object、Object) 指定されたフォーマット情報を使用して、指定されたオブジェクトのテキスト表現を標準出力ストリームに書き込みます。
Write(String、Object、Object、Object) 指定されたフォーマット情報を使用して、指定されたオブジェクトのテキスト表現を標準出力ストリームに書き込みます。
Write(String、Object、Object、Object、Object) 指定されたフォーマット情報を使用して、指定されたオブジェクトと可変長パラメーターリストのテキスト表現を標準出力ストリームに書き込みます。
WriteLine() 現在のラインターミネータを標準出力ストリームに書き込みます。
WriteLine(ブール値) 指定されたブール値のテキスト表現に続いて現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(Char) 指定されたUnicode文字に続いて、現在の行末記号の値を標準出力ストリームに書き込みます。
WriteLine(Char []) 指定されたUnicode文字の配列と、それに続く現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(Decimal) 指定された10進値のテキスト表現と、それに続く現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(Double) 指定された倍精度浮動小数点値のテキスト表現と、それに続く現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(Int32) 指定された32ビットの符号付き整数値のテキスト表現と、それに続く現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(Int64) 指定された64ビットの符号付き整数値のテキスト表現と、それに続く現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(Object) 指定されたオブジェクトのテキスト表現に続いて現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(シングル) 指定された単精度浮動小数点値のテキスト表現と、それに続く現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(String) 指定された文字列値に続いて現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(UInt32) 指定された32ビットの符号なし整数値のテキスト表現と、それに続く現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(UInt64) 指定された64ビットの符号なし整数値のテキスト表現と、それに続く現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(String、Object) 指定されたフォーマット情報を使用して、指定されたオブジェクトのテキスト表現に続いて現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(String、Object []) 指定されたフォーマット情報を使用して、指定されたオブジェクトの配列のテキスト表現と、それに続く現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(Char []、Int32、Int32) 指定されたUnicode文字のサブ配列と、それに続く現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(String、Object、Object) 指定されたフォーマット情報を使用して、指定されたオブジェクトのテキスト表現に続いて現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(String、Object、Object、Object) 指定されたフォーマット情報を使用して、指定されたオブジェクトのテキスト表現に続いて現在の行末記号を標準出力ストリームに書き込みます。
WriteLine(文字列、オブジェクト、オブジェクト、オブジェクト、オブジェクト) 指定されたフォーマット情報を使用して、指定されたオブジェクトと可変長パラメーターリストのテキスト表現と、それに続く現在の行ターミネーターを標準出力ストリームに書き込みます。

次の例は、コンソールからの読み取りとコンソールへの書き込みを示しています。

open System
let main() =
   Console.Write("What's your name? ")
   let name = Console.ReadLine()
   Console.Write("Hello, {0}\n", name)
   Console.WriteLine(System.String.Format("Big Greetings from {0} and {1}", "TutorialsPoint", "Absoulte Classes"))
   Console.WriteLine(System.String.Format("|{0:yyyy-MMM-dd}|", System.DateTime.Now))
main()

プログラムをコンパイルして実行すると、次の出力が生成されます。

What's your name? Kabir
Hello, Kabir
Big Greetings from TutorialsPoint and Absoulte Classes
|2015-Jan-05|

System.IO名前空間

System.IO名前空間には、基本的なI / Oを実行するためのさまざまな便利なクラスが含まれています。

これには、ファイルとデータストリームの読み取りと書き込みを可能にするタイプまたはクラスと、基本的なファイルとディレクトリのサポートを提供するタイプが含まれています。

ファイルシステムの操作に役立つクラス-

  • System.IO.Fileクラスは、ファイルの作成、追加、および削除に使用されます。
  • System.IO.Directoryクラスは、ディレクトリの作成、移動、および削除に使用されます。
  • System.IO.Pathクラスは、ファイルパスを表す文字列に対して操作を実行します。
  • System.IO.FileSystemWatcherクラスを使用すると、ユーザーはディレクトリの変更をリッスンできます。

ストリームの操作に役立つクラス(バイトのシーケンス)-

  • System.IO.StreamReaderクラスは、ストリームから文字を読み取るために使用されます。
  • System.IO.StreamWriterクラスは、ストリームに文字を書き込むために使用されます。
  • System.IO.MemoryStreamクラスは、バイトのメモリ内ストリームを作成します。

次の表は、名前空間で提供されるすべてのクラスと簡単な説明を示しています。

クラス 説明
BinaryReader プリミティブデータ型を特定のエンコーディングのバイナリ値として読み取ります。
BinaryWriter プリミティブ型をバイナリでストリームに書き込み、特定のエンコーディングでの文字列の書き込みをサポートします。
BufferedStream 別のストリームの読み取りおよび書き込み操作にバッファリングレイヤーを追加します。
ディレクトリ ディレクトリおよびサブディレクトリを介して作成、移動、および列挙するための静的メソッドを公開します。
DirectoryInfo ディレクトリおよびサブディレクトリを介して作成、移動、および列挙するためのインスタンスメソッドを公開します。
DirectoryNotFoundException ファイルまたはディレクトリの一部が見つからない場合にスローされる例外。
DriveInfo ドライブ上の情報へのアクセスを提供します。
DriveNotFoundException 使用できないドライブまたは共有にアクセスしようとしたときにスローされる例外。
EndOfStreamException ストリームの終わりを超えて読み取りが試行されたときにスローされる例外。
ErrorEventArgs FileSystemWatcher.Errorイベントのデータを提供します。
ファイル 単一のファイルを作成、コピー、削除、移動、および開くための静的メソッドを提供し、FileStreamオブジェクトの作成を支援します。
FileFormatException 特定のファイル形式の仕様に準拠しているはずの入力ファイルまたはデータストリームの形式が正しくない場合にスローされる例外。
FileInfo ファイルの作成、コピー、削除、移動、および開くためのプロパティとインスタンスメソッドを提供し、FileStreamオブジェクトの作成を支援します。
FileLoadException 管理対象アセンブリが見つかったがロードできない場合にスローされる例外。
FileNotFoundException ディスク上に存在しないファイルにアクセスしようとして失敗した場合にスローされる例外。
FileStream ファイルの周囲にストリームを公開し、同期と非同期の両方の読み取りおよび書き込み操作をサポートします。
FileSystemEventArgs ディレクトリイベントのデータを提供します-変更、作成、削除。
FileSystemInfo FileInfoオブジェクトとDirectoryInfoオブジェクトの両方の基本クラスを提供します。
FileSystemWatcher ファイルシステムの変更通知をリッスンし、ディレクトリまたはディレクトリ内のファイルが変更されたときにイベントを発生させます。
InternalBufferOverflowException 内部バッファがオーバーフローしたときにスローされる例外。
InvalidDataException データストリームが無効な形式の場合にスローされる例外。
IODescriptionAttribute イベント、エクステンダー、またはプロパティを参照するときにビジュアルデザイナーが表示できる説明を設定します。
IOException I / Oエラーが発生したときにスローされる例外。
MemoryStream バッキングストアがメモリであるストリームを作成します。
ファイルまたはディレクトリのパス情報を含むStringインスタンスに対して操作を実行します。これらの操作は、クロスプラットフォームの方法で実行されます。
PathTooLongException パスまたはファイル名がシステム定義の最大長より長い場合にスローされる例外。
PipeException 名前付きパイプ内でエラーが発生したときにスローされます。
RenamedEventArgs Renamedイベントのデータを提供します。
ストリーム バイトシーケンスの一般的なビューを提供します。これは抽象クラスです。
StreamReader 特定のエンコーディングでバイトストリームから文字を読み取るTextReaderを実装します。
StreamWriter 特定のエンコーディングでストリームに文字を書き込むためのTextWriterを実装します。このタイプの.NETFrameworkソースコードを参照するには、リファレンスソースを参照してください。
StringReader 文字列から読み取るTextReaderを実装します。
StringWriter 文字列に情報を書き込むためのTextWriterを実装します。情報は、基礎となるStringBuilderに格納されます。
TextReader 一連の文字を連続して読み取ることができるリーダーを表します。
TextWriter 一連の文字を連続して書き込むことができるライターを表します。このクラスは抽象です。
UnmanagedMemoryAccessor マネージコードからアンマネージメモリブロックへのランダムアクセスを提供します。
UnmanagedMemoryStream マネージコードからアンマネージメモリブロックへのアクセスを提供します。
WindowsRuntimeStorageExtensions Windowsストアアプリを開発する際のWindowsランタイムのIStorageFileおよびIStorageFolderインターフェイスの拡張メソッドが含まれています。
WindowsRuntimeStreamExtensions Windowsランタイムのストリームと.NETforWindowsストアアプリのマネージドストリームを変換するための拡張メソッドが含まれています。

次の例では、test.txtというファイルを作成し、そこにメッセージを書き込み、ファイルからテキストを読み取り、コンソールに出力します。

Note −これを行うために必要なコードの量は驚くほど少ないです!

open System.IO // Name spaces can be opened just as modules
File.WriteAllText("test.txt", "Hello There\n Welcome to:\n Tutorials Point")
let msg = File.ReadAllText("test.txt")
printfn "%s" msg

プログラムをコンパイルして実行すると、次の出力が生成されます。

Hello There
Welcome to:
Tutorials Point

ジェネリックスを使用すると、プログラムで実際に使用されるまで、クラスまたはメソッド内のプログラミング要素のデータ型の指定を遅らせることができます。言い換えると、ジェネリックスを使用すると、任意のデータ型で機能するクラスまたはメソッドを記述できます。

クラスまたはメソッドの仕様を、データ型の代替パラメーターを使用して記述します。コンパイラーは、クラスのコンストラクターまたはメソッドの関数呼び出しを検出すると、特定のデータ型を処理するコードを生成します。

F#では、関数値、メソッド、プロパティ、およびクラス、レコード、識別された共用体などの集計タイプを汎用にすることができます。

一般的な構成には、少なくとも1つの型パラメーターが含まれます。ジェネリック関数と型を使用すると、型ごとにコードを繰り返すことなく、さまざまな型で機能するコードを記述できます。

構文

一般的な構成を記述するための構文は次のとおりです-

// Explicitly generic function.
let function-name<type-parameters> parameter-list =
   function-body

// Explicitly generic method.
[ static ] member object-identifer.method-name<type-parameters> parameter-list [ return-type ] =
   method-body

// Explicitly generic class, record, interface, structure,
// or discriminated union.
type type-name<type-parameters> type-definition

(* Generic Function *)
let printFunc<'T> x y =
   printfn "%A, %A" x y

printFunc<float> 10.0 20.0

プログラムをコンパイルして実行すると、次の出力が生成されます。

10.0, 20.0

一重引用符の構文を使用して、関数をジェネリックにすることもできます-

(* Generic Function *)
let printFunction (x: 'a) (y: 'a) =
   printfn "%A %A" x y

printFunction 10.0 20.0

プログラムをコンパイルして実行すると、次の出力が生成されます。

10.0 20.0

ジェネリック関数またはメソッドを使用する場合、型引数を指定する必要がない場合があることに注意してください。ただし、あいまいな場合は、最初の例で行ったように、角かっこで型引数を指定できます。

複数の型がある場合は、複数の型引数をコンマで区切ります。

ジェネリッククラス

ジェネリック関数と同様に、ジェネリッククラスを作成することもできます。次の例はこれを示しています-

type genericClass<'a> (x: 'a) =
   do printfn "%A" x

let gr = new genericClass<string>("zara")
let gs = genericClass( seq { for i in 1 .. 10 -> (i, i*i) } )

プログラムをコンパイルして実行すると、次の出力が生成されます。

"zara"
seq [(1, 1); (2, 4); (3, 9); (4, 16); ...]

デリゲートは、メソッドへの参照を保持する参照型変数です。参照は実行時に変更できます。F#デリゲートは、CまたはC ++の関数へのポインターに似ています。

代表者の宣言

デリゲート宣言は、デリゲートが参照できるメソッドを決定します。デリゲートは、デリゲートと同じシグネチャを持つメソッドを参照できます。

デリゲート宣言の構文は次のとおりです。

type delegate-typename = delegate of type1 -> type2

たとえば、代表者を考えてみましょう-

// Delegate1 works with tuple arguments.
type Delegate1 = delegate of (int * int) -> int
// Delegate2 works with curried arguments.
type Delegate2 = delegate of int * int -> int

両方のデリゲートを使用して、2つのintパラメーターを持ち、int型変数を返す任意のメソッドを参照できます。

構文では-

  • type1 引数のタイプを表します。

  • type2 戻り値の型を表します。

注意してください-

  • 引数の型は自動的にカレーされます。

  • デリゲートは、関数値、静的メソッドまたはインスタンスメソッドにアタッチできます。

  • F#関数の値は、コンストラクターを委任するための引数として直接渡すことができます。

  • 静的メソッドの場合、デリゲートはクラスの名前とメソッドを使用して呼び出されます。インスタンスメソッドの場合、オブジェクトインスタンスとメソッドの名前が使用されます。

  • デリゲート型のInvokeメソッドは、カプセル化された関数を呼び出します。

  • また、括弧なしでInvokeメソッド名を参照することにより、デリゲートを関数値として渡すことができます。

次の例は、概念を示しています-

type Myclass() =
   static member add(a : int, b : int) =
      a + b
   static member sub (a : int) (b : int) =
      a - b
   member x.Add(a : int, b : int) =
      a + b
   member x.Sub(a : int) (b : int) =
      a - b

// Delegate1 works with tuple arguments.
type Delegate1 = delegate of (int * int) -> int
// Delegate2 works with curried arguments.
type Delegate2 = delegate of int * int -> int

let InvokeDelegate1 (dlg : Delegate1) (a : int) (b: int) =
   dlg.Invoke(a, b)
let InvokeDelegate2 (dlg : Delegate2) (a : int) (b: int) =
   dlg.Invoke(a, b)

// For static methods, use the class name, the dot operator, and the
// name of the static method.
let del1 : Delegate1 = new Delegate1( Myclass.add )
let del2 : Delegate2 = new Delegate2( Myclass.sub )

let mc = Myclass()
// For instance methods, use the instance value name, the dot operator, and the instance method name.

let del3 : Delegate1 = new Delegate1( mc.Add )
let del4 : Delegate2 = new Delegate2( mc.Sub )

for (a, b) in [ (400, 200); (100, 45) ] do
   printfn "%d + %d = %d" a b (InvokeDelegate1 del1 a b)
   printfn "%d - %d = %d" a b (InvokeDelegate2 del2 a b)
   printfn "%d + %d = %d" a b (InvokeDelegate1 del3 a b)
   printfn "%d - %d = %d" a b (InvokeDelegate2 del4 a b)

プログラムをコンパイルして実行すると、次の出力が生成されます。

400 + 200 = 600
400 - 200 = 200
400 + 200 = 600
400 - 200 = 200
100 + 45 = 145
100 - 45 = 55
100 + 45 = 145
100 - 45 = 55

列挙型は、名前付き整数定数のセットです。

F#では、 enumerations, としても知られている enums,ラベルが値のサブセットに割り当てられる整数型です。リテラルの代わりにそれらを使用して、コードをより読みやすく、保守しやすくすることができます。

列挙の宣言

列挙型を宣言するための一般的な構文は次のとおりです。

type enum-name =
   | value1 = integer-literal1
   | value2 = integer-literal2
...

次の例は、列挙の使用法を示しています。

// Declaration of an enumeration.
type Days =
   | Sun = 0
   | Mon = 1
   | Tues = 2
   | Wed = 3
   | Thurs = 4
   | Fri = 5
   | Sat = 6

// Use of an enumeration.
let weekend1 : Days = Days.Sat
let weekend2 : Days = Days.Sun
let weekDay1 : Days = Days.Mon

printfn "Monday: %A" weekDay1
printfn "Saturday: %A" weekend1
printfn "Sunday: %A" weekend2

プログラムをコンパイルして実行すると、次の出力が生成されます。

Monday: Mon
Saturday: Sat
Sunday: Sun

パターンマッチングを使用すると、「データを論理構造と比較したり、データを構成要素に分解したり、さまざまな方法でデータから情報を抽出したりする」ことができます。

言い換えると、一連の条件に対してデータをテストし、満たされた条件に基づいていくつかの計算を実行する、より柔軟で強力な方法を提供します。

概念的には、一連のif…thenステートメントのようなものです。

構文

大まかに言えば、パターンマッチングはF#-のこの構文に従います。

match expr with
| pat1 - result1
| pat2 -> result2
| pat3 when expr2 -> result3
| _ -> defaultResult

どこ、

  • それぞれ| シンボルは条件を定義します。
  • ->記号は、「条件が真の場合、この値を返す...」を意味します。
  • _記号はデフォルトのパターンを提供します。これは、ワイルドカードなどの他のすべてのものと一致することを意味します。

例1

次の例では、パターンマッチング構文を使用してフィボナッチ数を計算します-

let rec fib n =
   match n with
   | 0 -> 0
   | 1 -> 1
   | _ -> fib (n - 1) + fib (n - 2)
for i = 1 to 10 do
   printfn "Fibonacci %d: %d" i (fib i)

プログラムをコンパイルして実行すると、次の出力が生成されます。

Fibonacci 1: 1
Fibonacci 2: 1
Fibonacci 3: 2
Fibonacci 4: 3
Fibonacci 5: 5
Fibonacci 6: 8
Fibonacci 7: 13
Fibonacci 8: 21
Fibonacci 9: 34
Fibonacci 10: 55

同じ値を返す複数の条件をチェーン化することもできます。例-

例2

let printSeason month =
   match month with
   | "December" | "January" | "February" -> printfn "Winter"
   | "March" | "April" -> printfn "Spring"
   | "May" | "June" -> printfn "Summer"
   | "July" | "August" -> printfn "Rainy"
   | "September" | "October" | "November" -> printfn "Autumn"
   | _ -> printfn "Season depends on month!"

printSeason "February"
printSeason "April"
printSeason "November"
printSeason "July"

プログラムをコンパイルして実行すると、次の出力が生成されます。

Winter
Spring
Autumn
Rainy

パターンマッチング機能

F#を使用すると、を使用してパターンマッチング関数を記述できます。 function キーワード−

let getRate = function
   | "potato" -> 10.00
   | "brinjal" -> 20.50
   | "cauliflower" -> 21.00
   | "cabbage" -> 8.75
   | "carrot" -> 15.00
   | _ -> nan (* nan is a special value meaning "not a number" *)

printfn "%g"(getRate "potato")
printfn "%g"(getRate "brinjal")
printfn "%g"(getRate "cauliflower")
printfn "%g"(getRate "cabbage")
printfn "%g"(getRate "carrot")

プログラムをコンパイルして実行すると、次の出力が生成されます。

10
20.5
21
8.75
15

パターンへのフィルターまたはガードの追加

を使用して、パターンにフィルターまたはガードを追加できます。 when キーワード。

例1

let sign = function
   | 0 -> 0
   | x when x < 0 -> -1
   | x when x > 0 -> 1

printfn "%d" (sign -20)
printfn "%d" (sign 20)
printfn "%d" (sign 0)

プログラムをコンパイルして実行すると、次の出力が生成されます。

-1
1
0

例2

let compareInt x =
   match x with
   | (var1, var2) when var1 > var2 -> printfn "%d is greater than %d" var1 var2
   | (var1, var2) when var1 < var2 -> printfn "%d is less than %d" var1 var2
   | (var1, var2) -> printfn "%d equals %d" var1 var2

compareInt (11,25)
compareInt (72, 10)
compareInt (0, 0)

プログラムをコンパイルして実行すると、次の出力が生成されます。

11 is less than 25
72 is greater than 10
0 equals 0

タプルとのパターンマッチング

次の例は、タプルとのパターンマッチングを示しています-

let greeting (name, subject) =
   match (name, subject) with
   | ("Zara", _) -> "Hello, Zara"
   | (name, "English") -> "Hello, " + name + " from the department of English"
   | (name, _) when subject.StartsWith("Comp") -> "Hello, " + name + " from the department of Computer Sc."
   | (_, "Accounts and Finance") -> "Welcome to the department of Accounts and Finance!"
   | _ -> "You are not registered into the system"

printfn "%s" (greeting ("Zara", "English"))
printfn "%s" (greeting ("Raman", "Computer Science"))
printfn "%s" (greeting ("Ravi", "Mathematics"))

プログラムをコンパイルして実行すると、次の出力が生成されます。

Hello, Zara
Hello, Raman from the department of Computer Sc.
You are not registered into the system

レコードとのパターンマッチング

次の例は、レコードとのパターンマッチングを示しています-

type Point = { x: float; y: float }
let evaluatePoint (point: Point) =
   match point with
   | { x = 0.0; y = 0.0 } -> printfn "Point is at the origin."
   | { x = xVal; y = 0.0 } -> printfn "Point is on the x-axis. Value is %f." xVal
   | { x = 0.0; y = yVal } -> printfn "Point is on the y-axis. Value is %f." yVal
   | { x = xVal; y = yVal } -> printfn "Point is at (%f, %f)." xVal yVal

evaluatePoint { x = 0.0; y = 0.0 }
evaluatePoint { x = 10.0; y = 0.0 }
evaluatePoint { x = 0.0; y = 10.0 }
evaluatePoint { x = 10.0; y = 10.0 }

プログラムをコンパイルして実行すると、次の出力が生成されます。

Point is at the origin.
Point is on the x-axis. Value is 10.000000.
Point is on the y-axis. Value is 10.000000.
Point is at (10.000000, 10.000000).

例外は、プログラムの実行中に発生する問題です。F#例外は、ゼロ除算の試行など、プログラムの実行中に発生する例外的な状況への応答です。

例外は、プログラムのある部分から別の部分に制御を移す方法を提供します。F#例外処理は、次の構成を提供します-

構築する 説明
exprを上げる 指定された例外を発生させます。
exprで失敗 を上げる System.Exception 例外。
ルールでexprを試してください パターンルールに一致する式をキャッチします。
exprを最後にexprを試してください 実行 finally 計算が成功したときと例外が発生したときの両方の式。
| :?ArgumentException 指定された.NET例外タイプに一致するルール。
| :?eとしてのArgumentException 指定された.NET例外タイプに一致し、名前をバインドするルール e 例外オブジェクト値に。
| 失敗(msg)→expr 指定されたデータを運ぶF#例外に一致するルール。
| exn→expr 名前をバインドする、任意の例外に一致するルール exn 例外オブジェクト値に。
| expr→exprの場合のexn 指定された条件下で例外に一致し、名前をバインドするルール exn 例外オブジェクト値に。

例外処理の基本的な構文から始めましょう。

構文

F#例外処理ブロックの基本的な構文は次のとおりです。

exception exception-type of argument-type

どこ、

  • exception-type 新しいF#例外タイプの名前です。

  • argument-type このタイプの例外を発生させたときに指定できる引数のタイプを表します。

  • 引数タイプにタプル型を使用すると、複数の引数を指定できます。

ザ・ try...with 式は、F#言語での例外処理に使用されます。

try…with式の構文は次のとおりです。

try
   expression1
with
   | pattern1 -> expression2
   | pattern2 -> expression3
...

ザ・ try...finally 式を使用すると、コードのブロックが例外をスローした場合でも、クリーンアップコードを実行できます。

tryの構文…finally式は-

try
   expression1
finally
   expression2

ザ・ raise関数は、エラーまたは例外的な状態が発生したことを示すために使用されます。また、例外オブジェクトのエラーに関する情報も取得します。

raise関数の構文は次のとおりです。

raise (expression)

ザ・ failwith 関数はF#例外を生成します。

failwith関数の構文は次のとおりです。

failwith error-message-string

ザ・ invalidArg 関数は引数例外を生成します。

invalidArg parameter-name error-message-string

例外処理の例

例1

次のプログラムは、単純な試行による基本的な例外処理を示しています…ブロック-

let divisionprog x y =
   try
      Some (x / y)
   with
      | :? System.DivideByZeroException -> printfn "Division by zero!"; None

let result1 = divisionprog 100 0

プログラムをコンパイルして実行すると、次の出力が生成されます。

Division by zero!

例2

F#は exception例外を宣言するためのタイプ。のフィルタで例外タイプを直接使用できます。try...with 式。

次の例はこれを示しています-

exception Error1 of string
// Using a tuple type as the argument type.
exception Error2 of string * int

let myfunction x y =
   try
      if x = y then raise (Error1("Equal Number Error"))
      else raise (Error2("Error Not detected", 100))
   with
      | Error1(str) -> printfn "Error1 %s" str
      | Error2(str, i) -> printfn "Error2 %s %d" str i
myfunction 20 10
myfunction 5 5

プログラムをコンパイルして実行すると、次の出力が生成されます。

Error2 Error Not detected 100
Error1 Equal Number Error

例3

次の例は、ネストされた例外処理を示しています-

exception InnerError of string
exception OuterError of string

let func1 x y =
   try
      try
         if x = y then raise (InnerError("inner error"))
         else raise (OuterError("outer error"))
      with
         | InnerError(str) -> printfn "Error:%s" str
   finally
      printfn "From the finally block."

let func2 x y =
   try
      func1 x y
   with
      | OuterError(str) -> printfn "Error: %s" str

func2 100 150
func2 100 100
func2 100 120

プログラムをコンパイルして実行すると、次の出力が生成されます。

From the finally block.
Error: outer error
Error:inner error
From the finally block.
From the finally block.
Error: outer error

例4

次の関数は、 failwith 関数-

let divisionFunc x y =
   if (y = 0) then failwith "Divisor cannot be zero."
   else
      x / y

let trydivisionFunc x y =
   try
      divisionFunc x y
   with
      | Failure(msg) -> printfn "%s" msg; 0

let result1 = trydivisionFunc 100 0
let result2 = trydivisionFunc 100 4
printfn "%A" result1
printfn "%A" result2

プログラムをコンパイルして実行すると、次の出力が生成されます。

Divisor cannot be zero.
0
25

例5

ザ・ invalidArg関数は引数例外を生成します。次のプログラムはこれを示しています-

let days = [| "Sunday"; "Monday"; "Tuesday"; "Wednesday"; "Thursday"; "Friday"; "Saturday" |]
let findDay day =
   if (day > 7 || day < 1)
      then invalidArg "day" (sprintf "You have entered %d." day)
   days.[day - 1]

printfn "%s" (findDay 1)
printfn "%s" (findDay 5)
printfn "%s" (findDay 9)

プログラムをコンパイルして実行すると、次の出力が生成されます。

Sunday
Thursday
Unhandled Exception:
System.ArgumentException: You have entered 9.
…

システムによっては、システムでエラーを引き起こすファイルと変数に関するその他の情報も表示されます。

クラスは、プロパティ、メソッド、およびイベントを持つことができるオブジェクトを表すタイプです。「これらは、アプリケーションのアクション、プロセス、および概念エンティティをモデル化するために使用されます」。

構文

クラスタイプを定義するための構文は次のとおりです。

// Class definition:
type [access-modifier] type-name [type-params] [access-modifier] ( parameter-list ) [ as identifier ] =
   [ class ]
      [ inherit base-type-name(base-constructor-args) ]
      [ let-bindings ]
      [ do-bindings ]
      member-list
      ...
   [ end ]

// Mutually recursive class definitions:
type [access-modifier] type-name1 ...
and [access-modifier] type-name2 ...
...

どこ、

  • ザ・ type-name有効な識別子です。このためのデフォルトのアクセス修飾子はpublic

  • ザ・ type-params オプションのジェネリック型パラメーターについて説明します。

  • ザ・ parameter-listコンストラクターパラメーターについて説明します。プライマリコンストラクタのデフォルトのアクセス修飾子はpublic

  • ザ・ identifier オプションで使用 as キーワードはインスタンス変数に名前を付けます、または self-identifier, これは、型定義で使用して、型のインスタンスを参照できます。

  • ザ・ inherit キーワードを使用すると、クラスの基本クラスを指定できます。

  • ザ・ let バインディングを使用すると、クラスに対してローカルなフィールドまたは関数値を宣言できます。

  • ザ・ do-bindings セクションには、オブジェクトの構築時に実行されるコードが含まれています。

  • ザ・ member-list 追加のコンストラクター、インスタンスと静的メソッドの宣言、インターフェイスの宣言、抽象バインディング、およびプロパティとイベントの宣言で構成されます。

  • キーワード class そして end 定義の開始と終了を示すマークはオプションです。

クラスのコンストラクタ

コンストラクターは、クラス型のインスタンスを作成するコードです。

F#では、コンストラクターは他の.Net言語と少し異なります。クラス定義では、プライマリコンストラクタの引数はパラメータリストとして記述されています。

コンストラクターの本体は、 let そして do バインディング。

newキーワードを使用してメンバーを追加することにより、コンストラクターを追加できます-

new (argument-list) = constructor-body

次の例は、概念を示しています-

次のプログラムは、クラスのオブジェクトの作成中に行の長さを計算するコンストラクターとともに行クラスを作成します-

type Line = class
   val X1 : float
   val Y1 : float
   val X2 : float
   val Y2 : float

   new (x1, y1, x2, y2) as this =
      { X1 = x1; Y1 = y1; X2 = x2; Y2 = y2;}
      then
         printfn " Creating Line: {(%g, %g), (%g, %g)}\nLength: %g"
            this.X1 this.Y1 this.X2 this.Y2 this.Length

   member x.Length =
      let sqr x = x * x
      sqrt(sqr(x.X1 - x.X2) + sqr(x.Y1 - x.Y2) )
end
let aLine = new Line(1.0, 1.0, 4.0, 5.0)

プログラムをコンパイルして実行すると、次の出力が生成されます。

Creating Line: {(1, 1), (4, 5)}
Length: 5

バインディングをしましょう

クラス定義のletバインディングを使用すると、F#クラスのプライベートフィールドとプライベート関数を定義できます。

type Greetings(name) as gr =
   let data = name
   do
      gr.PrintMessage()
   member this.PrintMessage() =
      printf "Hello %s\n" data
let gtr = new Greetings("Zara")

プログラムをコンパイルして実行すると、次の出力が生成されます。

Hello Zara

Greetingsクラスでは自己識別子grを使用していることに注意してください。

F#の構造体は、値型のデータ型です。単一の変数を作成し、さまざまなデータ型の関連データを保持するのに役立ちます。ザ・struct キーワードは構造を作成するために使用されます。

構文

構造を定義するための構文は次のとおりです-

[ attributes ]
type [accessibility-modifier] type-name =
   struct
      type-definition-elements
   end
// or
[ attributes ]
[<StructAttribute>]
type [accessibility-modifier] type-name =
   type-definition-elements

2つの構文があります。最初の構文が主に使用されます。これは、struct そして end キーワード、あなたは省略できます StructAttribute 属性。

構造定義要素は-を提供します

  • メンバーの宣言と定義。
  • コンストラクターと可変および不変フィールド。
  • メンバーとインターフェースの実装。

クラスとは異なり、構造体は継承できず、letまたはdoバインディングを含めることはできません。なぜなら、構造にはletバインディングがないからです。を使用して構造体のフィールドを宣言する必要がありますval キーワード。

を使用してフィールドとそのタイプを定義する場合 valキーワードでは、フィールド値を初期化できません。代わりに、ゼロまたはnullに初期化されます。したがって、暗黙のコンストラクターを持つ構造の場合、val 宣言には注釈が付けられます DefaultValue 属性。

次のプログラムは、コンストラクターとともに行構造を作成します。プログラムは、構造体を使用して行の長さを計算します-

type Line = struct
   val X1 : float
   val Y1 : float
   val X2 : float
   val Y2 : float

   new (x1, y1, x2, y2) =
      {X1 = x1; Y1 = y1; X2 = x2; Y2 = y2;}
end
let calcLength(a : Line)=
   let sqr a = a * a
   sqrt(sqr(a.X1 - a.X2) + sqr(a.Y1 - a.Y2) )

let aLine = new Line(1.0, 1.0, 4.0, 5.0)
let length = calcLength aLine
printfn "Length of the Line: %g " length

プログラムをコンパイルして実行すると、次の出力が生成されます。

Length of the Line: 5

F#で使用できるほとんどの組み込み演算子を再定義またはオーバーロードできます。したがって、プログラマーはユーザー定義型の演算子も使用できます。

演算子は、角かっこで囲まれた特別な名前の関数です。それらは静的クラスメンバーとして定義する必要があります。他の関数と同様に、オーバーロードされた演算子には戻り値の型とパラメーターリストがあります。

次の例は、複素数の+演算子を示しています-

//overloading + operator
static member (+) (a : Complex, b: Complex) =
Complex(a.x + b.x, a.y + b.y)

上記の関数は、ユーザー定義クラスComplexの加算演算子(+)を実装します。2つのオブジェクトの属性を追加し、結果のComplexオブジェクトを返します。

演算子のオーバーロードの実装

次のプログラムは完全な実装を示しています-

//implementing a complex class with +, and - operators
//overloaded
type Complex(x: float, y : float) =
   member this.x = x
   member this.y = y
   //overloading + operator
   static member (+) (a : Complex, b: Complex) =
      Complex(a.x + b.x, a.y + b.y)

   //overloading - operator
   static member (-) (a : Complex, b: Complex) =
      Complex(a.x - b.x, a.y - b.y)

   // overriding the ToString method
   override this.ToString() =
      this.x.ToString() + " " + this.y.ToString()

//Creating two complex numbers
let c1 = Complex(7.0, 5.0)
let c2 = Complex(4.2, 3.1)

// addition and subtraction using the
//overloaded operators
let c3 = c1 + c2
let c4 = c1 - c2

//printing the complex numbers
printfn "%s" (c1.ToString())
printfn "%s" (c2.ToString())
printfn "%s" (c3.ToString())
printfn "%s" (c4.ToString())

プログラムをコンパイルして実行すると、次の出力が生成されます。

7 5
4.2 3.1
11.2 8.1
2.8 1.9

オブジェクト指向プログラミングで最も重要な概念の1つは、継承の概念です。継承により、別のクラスの観点からクラスを定義できるため、アプリケーションの作成と保守が容易になります。これは、コード機能と迅速な実装時間を再利用する機会も提供します。

クラスを作成するとき、プログラマーは、完全に新しいデータメンバーとメンバー関数を作成する代わりに、新しいクラスが既存のクラスのメンバーを継承するように指定できます。この既存のクラスは基本クラスと呼ばれ、新しいクラスは派生クラスと呼ばれます。

継承の概念は、IS-A関係を実装します。たとえば、哺乳類は動物であり、犬は哺乳類であり、したがって犬は動物であるなどです。

基本クラスとサブクラス

サブクラスは、すでに定義されている基本クラスから派生します。サブクラスは、基本クラスのメンバーを継承するだけでなく、独自のメンバーも持っています。

サブクラスは、 inherit 以下に示すキーワード-

type MyDerived(...) =
   inherit MyBase(...)

F#では、クラスは最大で1つの直接基本クラスを持つことができます。を使用して基本クラスを指定しない場合inherit キーワード、クラスは暗黙的にObjectから継承します。

注意してください-

  • 基本クラスのメソッドとメンバーは、派生クラスの直接メンバーと同様に、派生クラスのユーザーが使用できます。

  • バインディングとコンストラクターパラメーターはクラスに対してプライベートであるため、派生クラスからはアクセスできません。

  • キーワード base基本クラスインスタンスを参照します。自己識別子のように使用されます。

type Person(name) =
   member x.Name = name
   member x.Greet() = printfn "Hi, I'm %s" x.Name

type Student(name, studentID : int) =
   inherit Person(name)
   let mutable _GPA = 0.0
   member x.StudentID = studentID
   member x.GPA
      with get() = _GPA
      and set value = _GPA <- value

type Teacher(name, expertise : string) =
   inherit Person(name)

   let mutable _salary = 0.0
   member x.Salary
      with get() = _salary
      and set value = _salary <- value
   member x.Expertise = expertise

//using the subclasses
let p = new Person("Mohan")
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")

p.Greet()
st.Greet()
tr.Greet()

プログラムをコンパイルして実行すると、次の出力が生成されます。

Hi, I'm Mohan
Hi, I'm Zara
Hi, I'm Mariam

メソッドのオーバーライド

基本クラスメソッドのデフォルトの動作をオーバーライドして、サブクラスまたは派生クラスで異なる方法で実装できます。

F#のメソッドは、デフォルトではオーバーライドできません。

派生クラスのメソッドをオーバーライドするには、を使用してメソッドをオーバーライド可能として宣言する必要があります。 abstract そして default 次のようなキーワード-

type Person(name) =
   member x.Name = name
   abstract Greet : unit -> unit
   default x.Greet() = printfn "Hi, I'm %s" x.Name

これで、PersonクラスのGreetメソッドを派生クラスでオーバーライドできるようになりました。次の例はこれを示しています-

type Person(name) =
   member x.Name = name
   abstract Greet : unit -> unit
   default x.Greet() = printfn "Hi, I'm %s" x.Name

type Student(name, studentID : int) =
   inherit Person(name)

   let mutable _GPA = 0.0

   member x.StudentID = studentID
   member x.GPA
      with get() = _GPA
      and set value = _GPA <- value
   override x.Greet() = printfn "Student %s" x.Name

type Teacher(name, expertise : string) =
   inherit Person(name)
   let mutable _salary = 0.0
   member x.Salary
      with get() = _salary
      and set value = _salary <- value

   member x.Expertise = expertise
   override x.Greet() = printfn "Teacher %s." x.Name

//using the subclasses
let p = new Person("Mohan")
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")

//default Greet
p.Greet()

//Overriden Greet
st.Greet()
tr.Greet()

プログラムをコンパイルして実行すると、次の出力が生成されます。

Hi, I'm Mohan
Student Zara
Teacher Mariam.

抽象クラス

オブジェクトの不完全な実装を提供する必要がある場合がありますが、実際には実装すべきではありません。後で、他のプログラマーが抽象クラスのサブクラスを作成して完全な実装にする必要があります。

たとえば、Personクラスは学校管理システムでは必要ありません。ただし、StudentまたはTeacherクラスが必要になります。このような場合、Personクラスを抽象クラスとして宣言できます。

ザ・ AbstractClass 属性は、クラスにいくつかの抽象メンバーがあることをコンパイラーに通知します。

クラスが完全に実装されていないため、抽象クラスのインスタンスを作成することはできません。

次の例はこれを示しています-

[<AbstractClass>]
type Person(name) =
   member x.Name = name
   abstract Greet : unit -> unit

type Student(name, studentID : int) =
   inherit Person(name)
   let mutable _GPA = 0.0
   member x.StudentID = studentID
   member x.GPA
      with get() = _GPA
      and set value = _GPA <- value
   override x.Greet() = printfn "Student %s" x.Name

type Teacher(name, expertise : string) =
   inherit Person(name)
   let mutable _salary = 0.0
   member x.Salary
      with get() = _salary
      and set value = _salary <- value
   member x.Expertise = expertise
   override x.Greet() = printfn "Teacher %s." x.Name

let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")

//Overriden Greet
st.Greet()
tr.Greet()

プログラムをコンパイルして実行すると、次の出力が生成されます。

Student Zara
Teacher Mariam.

インターフェイスは、クラスの実装の詳細を記述する抽象的な方法を提供します。これは、クラスが実装して公開する必要のあるメソッドを宣言するテンプレートです。

構文

インターフェイスは、他のクラスが実装する関連メンバーのセットを指定します。次の構文があります-

// Interface declaration:
[ attributes ]
type interface-name =
   [ interface ]
      [ inherit base-interface-name ...]
      abstract member1 : [ argument-types1 -> ] return-type1
      abstract member2 : [ argument-types2 -> ] return-type2
      ...
   [ end ]
	
// Implementing, inside a class type definition:
interface interface-name with
   member self-identifier.member1 argument-list = method-body1
   member self-identifier.member2 argument-list = method-body2
// Implementing, by using an object expression:
[ attributes ]
let class-name (argument-list) =
   { new interface-name with
      member self-identifier.member1 argument-list = method-body1
      member self-identifier.member2 argument-list = method-body2
      [ base-interface-definitions ]
   }
member-list

注意してください-

  • インターフェイス宣言では、メンバーは実装されていません。

  • メンバーは抽象的であり、によって宣言されています abstractキーワード。ただし、を使用してデフォルトの実装を提供できますdefault キーワード。

  • オブジェクト式を使用するか、クラスタイプを使用して、インターフェイスを実装できます。

  • クラスまたはオブジェクトの実装では、インターフェイスの抽象メソッドのメソッド本体を提供する必要があります。

  • キーワード interface そして end, 定義の開始と終了をマークするものはオプションです。

例えば、

type IPerson =
   abstract Name : string
   abstract Enter : unit -> unit
   abstract Leave : unit -> unit

インターフェイスメソッドの呼び出し

インターフェイスメソッドは、クラスまたはタイプを実装するインターフェイスのインスタンスではなく、インターフェイスを介して呼び出されます。インターフェイスメソッドを呼び出すには、を使用してインターフェイスタイプにアップキャストします。:> 演算子(アップキャスト演算子)。

例えば、

(s :> IPerson).Enter()
(s :> IPerson).Leave()

次の例は、概念を示しています-

type IPerson =
   abstract Name : string
   abstract Enter : unit -> unit
   abstract Leave : unit -> unit

type Student(name : string, id : int) =
   member this.ID = id
   interface IPerson with
      member this.Name = name
      member this.Enter() = printfn "Student entering premises!"
      member this.Leave() = printfn "Student leaving premises!"

type StuffMember(name : string, id : int, salary : float) =
   let mutable _salary = salary

   member this.Salary
      with get() = _salary
      and set(value) = _salary <- value

   interface IPerson with
      member this.Name = name
      member this.Enter() = printfn "Stuff member entering premises!"
      member this.Leave() = printfn "Stuff member leaving premises!"

let s = new Student("Zara", 1234)
let st = new StuffMember("Rohit", 34, 50000.0)

(s :> IPerson).Enter()
(s :> IPerson).Leave()
(st :> IPerson).Enter()
(st :> IPerson).Leave()

プログラムをコンパイルして実行すると、次の出力が生成されます。

Student entering premises!
Student leaving premises!
Stuff member entering premises!
Stuff member leaving premises!

インターフェイスの継承

インターフェイスは、1つ以上の基本インターフェイスから継承できます。

次の例は、概念を示しています-

type Interface1 =
   abstract member doubleIt: int -> int

type Interface2 =
   abstract member tripleIt: int -> int

type Interface3 =
   inherit Interface1
   inherit Interface2
   abstract member printIt: int -> string

type multiplierClass() =
   interface Interface3 with
      member this.doubleIt(a) = 2 * a
      member this.tripleIt(a) = 3 * a
      member this.printIt(a) = a.ToString()

let ml = multiplierClass()
printfn "%d" ((ml:>Interface3).doubleIt(5))
printfn "%d" ((ml:>Interface3).tripleIt(5))
printfn "%s" ((ml:>Interface3).printIt(5))

プログラムをコンパイルして実行すると、次の出力が生成されます。

10
15
5

イベントを使用すると、クラスは相互にメッセージを送受信できます。

GUIでは、イベントは、キーの押下、クリック、マウスの動きなどのユーザーアクション、またはシステム生成の通知などの発生です。アプリケーションは、イベントが発生したときにイベントに応答する必要があります。たとえば、割り込み。イベントは、プロセス間通信に使用されます。

オブジェクトは、同期メッセージパッシングを介して相互に通信します。

イベントは他の関数に関連付けられています。オブジェクト登録callback イベントへの関数であり、これらのコールバックは、イベントが何らかのオブジェクトによってトリガーされたとき(およびその場合)に実行されます。

イベントクラスとイベントモジュール

Control.Event <'T>クラスは、監視可能なオブジェクトまたはイベントの作成に役立ちます。

イベントを操作するための次のインスタンスメンバーがあります-

メンバー 説明
公開する 観測値をファーストクラスの値として公開します。
引き金 指定されたパラメーターを使用して観測をトリガーします。

Control.Eventモジュールは、イベントストリームを管理するための関数を提供します-

説明
追加:( 'T→ユニット)→イベント<'デル、 'T>→ユニット 指定されたイベントがトリガーされるたびに、指定された関数を実行します。
選択:( 'T→' Uオプション)→IEvent <'Del、' T>→IEvent <'U> 元のイベントから選択したメッセージで発生する新しいイベントを返します。選択機能は、元のメッセージをオプションの新しいメッセージに変換します。
フィルタ:( 'T→bool)→IEvent <' Del、 'T>→IEvent <' T> 元のイベントをリッスンし、イベントの引数が指定された関数を通過した場合にのみ結果のイベントをトリガーする新しいイベントを返します。
マップ:( 'T→' U)→IEvent <'Del、' T>→IEvent <'U> 指定された関数によって変換された値を渡す新しいイベントを返します。
マージ:IEvent <'Del1、' T>→IEvent <'Del2、' T>→IEvent <'T> いずれかの入力イベントが発生すると、出力イベントが発生します。
ペアワイズ:IEvent <'Del、' T>→IEvent <'T *' T> 入力イベントの2回目以降のトリガーでトリガーされる新しいイベントを返します。ザ・Nth 入力イベントのトリガーは、からの引数を渡します N-1th そして Nthペアとしてトリガーします。に渡された引数N-1th トリガーは、 Nth トリガーが発生します。
パーティション:( 'T→bool)→IEvent <' Del、 'T>→IEvent <' T> * IEvent <'T> 元のイベントをリッスンし、イベント引数への述語の適用がtrueを返した場合は最初の結果のイベントをトリガーし、falseを返した場合は2番目のイベントをトリガーする新しいイベントを返します。
スキャン:( 'U→' T→ 'U)→' U→IEvent <'Del、' T>→IEvent <'U> 指定された累積関数を入力イベントでトリガーされた連続する値に適用した結果で構成される新しいイベントを返します。内部状態の項目は、状態パラメーターの現在の値を記録します。累積関数の実行中は内部状態がロックされないため、入力IEventが複数のスレッドによって同時にトリガーされないように注意する必要があります。
split :( 'T→Choice <' U1、 'U2>)→IEvent <' Del、 'T>→IEvent <' U1> * IEvent <'U2> 元のイベントをリッスンし、イベント引数への関数の適用がChoice1Of2を返した場合は最初の結果のイベントをトリガーし、Choice2Of2を返した場合は2番目のイベントをトリガーする新しいイベントを返します。

イベントの作成

イベントは、を通じて作成および使用されます Eventクラス。イベントコンストラクターは、イベントの作成に使用されます。

type Worker(name : string, shift : string) =
   let mutable _name = name;
   let mutable _shift = shift;
   let nameChanged = new Event<unit>() (* creates event *)
   let shiftChanged = new Event<unit>() (* creates event *)

   member this.Name
      with get() = _name
      and set(value) = _name <- value

   member this.Shift
      with get() = _shift
      and set(value) = _shift <- value

この後、nameChangedフィールドをパブリックメンバーとして公開する必要があります。これにより、リスナーはイベントにフックできます。 Publish イベントのプロパティ-

type Worker(name : string, shift : string) =
   let mutable _name = name;
   let mutable _shift = shift;

   let nameChanged = new Event<unit>() (* creates event *)
   let shiftChanged = new Event<unit>() (* creates event *)

   member this.NameChanged = nameChanged.Publish (* exposed event handler *)
   member this.ShiftChanged = shiftChanged.Publish (* exposed event handler *)

   member this.Name
      with get() = _name
      and set(value) = _name <- value
      nameChanged.Trigger() (* invokes event handler *)

   member this.Shift
      with get() = _shift
      and set(value) = _shift <- value
   shiftChanged.Trigger() (* invokes event handler *)

次に、イベントハンドラーにコールバックを追加します。各イベントハンドラーのタイプはIEvent <'T>で、いくつかのメソッドを提供します-

方法 説明
val Add:event :( 'T→unit)→unit リスナー関数をイベントに接続します。イベントが発生すると、リスナーが呼び出されます。
val AddHandler: 'del→unit ハンドラーデリゲートオブジェクトをイベントに接続します。ハンドラーは、後でRemoveHandlerを使用して削除できます。イベントが発生すると、リスナーが呼び出されます。
val RemoveHandler: 'del→unit イベントリスナーストアからリスナーデリゲートを削除します。

次のセクションでは、完全な例を示します。

次の例は、上記の概念と手法を示しています。

type Worker(name : string, shift : string) =
   let mutable _name = name;
   let mutable _shift = shift;

   let nameChanged = new Event<unit>() (* creates event *)
   let shiftChanged = new Event<unit>() (* creates event *)

   member this.NameChanged = nameChanged.Publish (* exposed event handler *)
   member this.ShiftChanged = shiftChanged.Publish (* exposed event handler *)

   member this.Name
      with get() = _name
      and set(value) = 
         _name <- value
         nameChanged.Trigger() (* invokes event handler *)

   member this.Shift
      with get() = _shift
      and set(value) = 
         _shift <- value
         shiftChanged.Trigger() (* invokes event handler *)

let wk = new Worker("Wilson", "Evening")
wk.NameChanged.Add(fun () -> printfn "Worker changed name! New name: %s" wk.Name)
wk.Name <- "William"
wk.NameChanged.Add(fun () -> printfn "-- Another handler attached to NameChanged!")
wk.Name <- "Bill"

wk.ShiftChanged.Add(fun () -> printfn "Worker changed shift! New shift: %s" wk.Shift)
wk.Shift <- "Morning"
wk.ShiftChanged.Add(fun () -> printfn "-- Another handler attached to ShiftChanged!")
wk.Shift <- "Night"

プログラムをコンパイルして実行すると、次の出力が生成されます。

Worker changed name! New name: William
Worker changed name! New name: Bill
-- Another handler attached to NameChanged!
Worker changed shift! New shift: Morning
Worker changed shift! New shift: Night
-- Another handler attached to ShiftChanged!

MSDNライブラリによると、F#モジュールは、型、値、関数値、doバインディング内のコードなどのF#コード構造のグループです。これは、静的メンバーのみを持つ共通言語ランタイム(CLR)クラスとして実装されます。

ファイル全体がモジュールに含まれるかどうかの状況に応じて、2種類のモジュール宣言があります-

  • トップレベルのモジュール宣言
  • ローカルモジュール宣言

トップレベルのモジュール宣言では、ファイル全体がモジュールに含まれます。この場合、ファイルの最初の宣言はモジュール宣言です。トップレベルモジュールで宣言をインデントする必要はありません。

ローカルモジュール宣言では、そのモジュール宣言の下にインデントされている宣言のみがモジュールの一部です。

構文

モジュール宣言の構文は次のとおりです-

// Top-level module declaration.
module [accessibility-modifier] [qualified-namespace.]module-name
   declarations
// Local module declaration.
module [accessibility-modifier] module-name =
   declarations

アクセシビリティ修飾子は、パブリック、プライベート、内部のいずれかになります。デフォルトはpublic

次の例は、概念を示しています-

例1

モジュールファイルArithmetic.fs−

module Arithmetic
let add x y =
   x + y

let sub x y =
   x - y
	
let mult x y =
   x * y
	
let div x y =
   x / y

プログラムファイルmain.fs−

// Fully qualify the function name.
open Arithmetic
let addRes = Arithmetic.add 25 9
let subRes = Arithmetic.sub 25 9
let multRes = Arithmetic.mult 25 9
let divRes = Arithmetic.div 25 9

printfn "%d" addRes
printfn "%d" subRes
printfn "%d" multRes
printfn "%d" divRes

プログラムをコンパイルして実行すると、次の出力が生成されます。

34
16
225
2
110
90
1000
10

例2

// Module1
module module1 =
   // Indent all program elements within modules that are declared with an equal sign.
   let value1 = 100
   let module1Function x =
      x + value1

// Module2
module module2 =
   let value2 = 200

   // Use a qualified name to access the function.
   // from module1.
   let module2Function x =
      x + (module1.module1Function value2)

let result = module1.module1Function 25
printfn "%d" result

let result2 = module2.module2Function 25
printfn "%d" result2

プログラムをコンパイルして実行すると、次の出力が生成されます。

125
325

A namespaceは、ある名前のセットを別の名前のセットから分離する方法を提供するために設計されています。ある名前空間で宣言されたクラス名は、別の名前空間で宣言された同じクラス名と競合しません。

MSDNライブラリによると、 namespace プログラム要素のグループに名前を付けることができるようにすることで、コードを関連する機能の領域に編成できます。

名前空間の宣言

コードを名前空間に編成するには、ファイルの最初の宣言として名前空間を宣言する必要があります。その後、ファイル全体の内容が名前空間の一部になります。

namespace [parent-namespaces.]identifier

次の例は、概念を示しています-

namespace testing

module testmodule1 =
   let testFunction x y =
      printfn "Values from Module1: %A %A" x y
module testmodule2 =
   let testFunction x y =
      printfn "Values from Module2: %A %A" x y

module usermodule =
   do
      testmodule1.testFunction ( "one", "two", "three" ) 150
      testmodule2.testFunction (seq { for i in 1 .. 10 do yield i * i }) 200

プログラムをコンパイルして実行すると、次の出力が生成されます。

Values from Module1: ("one", "two", "three") 150
Values from Module2: seq [1; 4; 9; 16; ...] 200