F # - Kurzanleitung

F # ist eine funktionale Programmiersprache. Um F # -Konstrukte zu verstehen, müssen Sie einige Zeilen über das genannte Programmierparadigma lesenFunctional Programming.

Die funktionale Programmierung behandelt Computerprogramme als mathematische Funktionen. Bei der funktionalen Programmierung würde der Fokus auf Konstanten und Funktionen anstelle von Variablen und Zuständen liegen. Weil Funktionen und Konstanten Dinge sind, die sich nicht ändern.

Bei der funktionalen Programmierung schreiben Sie modulare Programme, dh die Programme bestehen aus Funktionen, die andere Funktionen als Eingabe verwenden.

Programme, die in einer funktionalen Programmiersprache geschrieben sind, sind in der Regel prägnant.

Über F #

Im Folgenden finden Sie die grundlegenden Informationen zu F # -

  • Es wurde 2005 bei Microsoft Research entwickelt.
  • Es ist Teil der Microsoft-Familie der .NET-Sprache.
  • Es ist eine funktionale Programmiersprache.
  • Es basiert auf der funktionalen Programmiersprache OCaml.

Eigenschaften von F #

  • Es ist eine .NET-Implementierung von OCaml.

  • Es kompiliert .NET CLI-Bytecode (Common Language Interface) oder MSIL (Microsoft Intermediate Language), das auf CLR (Common Language Runtime) ausgeführt wird.

  • Es bietet Typinferenz.

  • Es bietet umfangreiche Mustervergleichskonstrukte.

  • Es verfügt über interaktive Skript- und Debugging-Funktionen.

  • Es ermöglicht das Schreiben von Funktionen höherer Ordnung.

  • Es bietet ein gut entwickeltes Objektmodell.

Verwendung von F #

F # wird normalerweise in den folgenden Bereichen verwendet -

  • Wissenschaftliches Modell machen
  • Mathematische Problemlösung
  • Forschungsarbeit zur künstlichen Intelligenz
  • Finanzmodellierung
  • Grafikdesign
  • CPU-Design
  • Compiler-Programmierung
  • Telecommunications

Es wird auch in CRUD-Apps, Webseiten, GUI-Spielen und anderen Allzweckprogrammen verwendet.

Die für die F # -Programmierung erforderlichen Tools werden in diesem Kapitel erläutert.

Integrierte Entwicklungsumgebung (IDE) für F #

Microsoft bietet Visual Studio 2013 für die F # -Programmierung an.

Die kostenlose Visual Studio 2013 Community Edition ist auf der offiziellen Website von Microsoft verfügbar. Visual Studio 2013 Community und höher wird mit den Visual F # -Tools geliefert. Installationsdetails finden Sie im Asp.net-Lernprogramm . Zu den Visual F # -Tools gehören der Befehlszeilen-Compiler (fsc.exe) und F # Interactive (fsi.exe).

Mit diesen Tools können Sie alle Arten von F # -Programmen schreiben, von einfachen Befehlszeilenanwendungen bis hin zu komplexeren Anwendungen. Sie können F # -Quellcodedateien auch mit einem einfachen Texteditor wie Notepad schreiben und den Code mithilfe des Befehlszeilen-Compilers in Assemblys kompilieren.

Sie können es von Microsoft Visual Studio herunterladen. Es wird automatisch in Ihrem Computer installiert.

Schreiben von F # -Programmen auf Links

Bitte besuchen Sie die offizielle F # Website, um die neuesten Anweisungen zu erhalten, wie Sie die Tools als Debian-Paket erhalten oder direkt aus der Quelle kompilieren können. https://fsharp.org/use/linux/.

F # ist eine funktionale Programmiersprache.

In F # funktionieren Funktionen wie Datentypen. Sie können eine Funktion wie jede andere Variable deklarieren und verwenden.

Im Allgemeinen hat eine F # -Anwendung keinen bestimmten Einstiegspunkt. Der Compiler führt alle Anweisungen der obersten Ebene in der Datei von oben nach unten aus.

Um dem prozeduralen Programmierstil zu folgen, behalten viele Anwendungen jedoch eine einzige Anweisung der obersten Ebene bei, die die Hauptschleife aufruft.

Der folgende Code zeigt ein einfaches F # -Programm -

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()

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

sign 5: positive

Bitte beachten Sie, dass -

  • Eine F # -Code-Datei kann mit einer Anzahl von beginnen open Anweisungen, die zum Importieren von Namespaces verwendet werden.

  • Der Hauptteil der Dateien enthält andere Funktionen, die die Geschäftslogik der Anwendung implementieren.

  • Die Hauptschleife enthält die obersten ausführbaren Anweisungen.

Sie haben die Grundstruktur eines F # -Programms gesehen, sodass andere Grundbausteine ​​der F # -Programmiersprache leicht zu verstehen sind.

Token in F #

Ein F # -Programm besteht aus verschiedenen Token. Ein Token kann ein Schlüsselwort, ein Bezeichner, eine Konstante, ein Zeichenfolgenliteral oder ein Symbol sein. Wir können F # -Token in zwei Typen einteilen -

  • Keywords
  • Symbol und Operatoren

F # Schlüsselwörter

Die folgende Tabelle zeigt die Schlüsselwörter und kurze Beschreibungen der Schlüsselwörter. Wir werden die Verwendung dieser Schlüsselwörter in den folgenden Kapiteln diskutieren.

Stichwort Beschreibung
abstract Gibt eine Methode an, die entweder keine Implementierung in dem Typ hat, in dem sie deklariert ist, oder die virtuell ist und eine Standardimplementierung hat.
and Wird in gegenseitig rekursiven Bindungen, in Eigenschaftsdeklarationen und mit mehreren Einschränkungen für generische Parameter verwendet.
as Wird verwendet, um dem aktuellen Klassenobjekt einen Objektnamen zu geben. Wird auch verwendet, um einem ganzen Muster innerhalb einer Musterübereinstimmung einen Namen zu geben.
assert Wird verwendet, um den Code während des Debuggens zu überprüfen.
base Wird als Name des Basisklassenobjekts verwendet.
begin Gibt in der ausführlichen Syntax den Beginn eines Codeblocks an.
class Gibt in der ausführlichen Syntax den Beginn einer Klassendefinition an.
default Gibt eine Implementierung einer abstrakten Methode an. Wird zusammen mit einer abstrakten Methodendeklaration verwendet, um eine virtuelle Methode zu erstellen.
delegate Wird verwendet, um einen Delegaten zu deklarieren.
do Wird in Schleifenkonstrukten oder zum Ausführen von imperativem Code verwendet.
done Gibt in der ausführlichen Syntax das Ende eines Codeblocks in einem Schleifenausdruck an.
downcast Wird verwendet, um in einen Typ zu konvertieren, der in der Vererbungskette niedriger ist.
downto In einem for Ausdruck, der beim umgekehrten Zählen verwendet wird.
elif Wird bei der bedingten Verzweigung verwendet. Eine Kurzform von sonst wenn.
else Wird bei der bedingten Verzweigung verwendet.
end

Gibt in Typdefinitionen und Typerweiterungen das Ende eines Abschnitts von Elementdefinitionen an.

In der ausführlichen Syntax wird das Ende eines Codeblocks angegeben, der mit dem Schlüsselwort begin beginnt.

exception Wird verwendet, um einen Ausnahmetyp zu deklarieren.
extern Gibt an, dass ein deklariertes Programmelement in einer anderen Binärdatei oder Assembly definiert ist.
false Wird als Boolesches Literal verwendet.
finally Wird zusammen mit dem Versuch verwendet, einen Codeblock einzuführen, der unabhängig davon ausgeführt wird, ob eine Ausnahme auftritt.
for Wird in Schleifenkonstrukten verwendet.
fun Wird in Lambda-Ausdrücken verwendet, die auch als anonyme Funktionen bezeichnet werden.
function Wird als kürzere Alternative zum Schlüsselwort fun und als Übereinstimmungsausdruck in einem Lambda-Ausdruck verwendet, dessen Muster für ein einzelnes Argument übereinstimmt.
global Wird verwendet, um auf den .NET-Namespace der obersten Ebene zu verweisen.
if Wird in bedingten Verzweigungskonstrukten verwendet.
in Wird für Sequenzausdrücke und in ausführlicher Syntax zum Trennen von Ausdrücken von Bindungen verwendet.
inherit Wird verwendet, um eine Basisklasse oder eine Basisschnittstelle anzugeben.
inline Wird verwendet, um eine Funktion anzugeben, die direkt in den Code des Anrufers integriert werden soll.
interface Wird zum Deklarieren und Implementieren von Schnittstellen verwendet.
internal Wird verwendet, um anzugeben, dass ein Element innerhalb einer Baugruppe sichtbar ist, jedoch nicht außerhalb.
lazy Wird verwendet, um eine Berechnung anzugeben, die nur ausgeführt werden soll, wenn ein Ergebnis benötigt wird.
let Wird verwendet, um einen Namen einem Wert oder einer Funktion zuzuordnen oder zu binden.
let! Wird in asynchronen Workflows verwendet, um einen Namen an das Ergebnis einer asynchronen Berechnung zu binden, oder in anderen Berechnungsausdrücken, um einen Namen an ein Ergebnis zu binden, das vom Berechnungstyp ist.
match Wird zum Verzweigen verwendet, indem ein Wert mit einem Muster verglichen wird.
member Wird verwendet, um eine Eigenschaft oder Methode in einem Objekttyp zu deklarieren.
module Wird verwendet, um einen Namen einer Gruppe verwandter Typen, Werte und Funktionen zuzuordnen und ihn logisch von anderem Code zu trennen.
mutable Wird verwendet, um eine Variable zu deklarieren, dh einen Wert, der geändert werden kann.
namespace Wird verwendet, um einen Namen einer Gruppe verwandter Typen und Module zuzuordnen und ihn logisch von anderem Code zu trennen.
new

Wird verwendet, um einen Konstruktor zu deklarieren, zu definieren oder aufzurufen, der ein Objekt erstellt oder erstellen kann.

Wird auch in allgemeinen Parametereinschränkungen verwendet, um anzugeben, dass ein Typ einen bestimmten Konstruktor haben muss.

not Eigentlich kein Schlüsselwort. Nicht Struktur in Kombination wird jedoch als generische Parametereinschränkung verwendet.
null

Zeigt das Fehlen eines Objekts an.

Wird auch in allgemeinen Parametereinschränkungen verwendet.

of Wird in diskriminierten Gewerkschaften verwendet, um die Art der Wertekategorien anzugeben, sowie in Delegierten- und Ausnahmeerklärungen.
open Wird verwendet, um den Inhalt eines Namespace oder Moduls ohne Einschränkung verfügbar zu machen.
or

Wird mit Booleschen Bedingungen als Boolescher Wert oder Operator verwendet. Entspricht ||.

Wird auch in Elementeinschränkungen verwendet.

override Wird verwendet, um eine Version einer abstrakten oder virtuellen Methode zu implementieren, die sich von der Basisversion unterscheidet.
private Beschränkt den Zugriff auf ein Mitglied auf Code im selben Typ oder Modul.
public Ermöglicht den Zugriff auf ein Mitglied von außerhalb des Typs.
rec Wird verwendet, um anzuzeigen, dass eine Funktion rekursiv ist.
return Wird verwendet, um einen Wert anzugeben, der als Ergebnis eines Berechnungsausdrucks bereitgestellt werden soll.
return! Wird verwendet, um einen Berechnungsausdruck anzugeben, der bei Auswertung das Ergebnis des enthaltenen Berechnungsausdrucks liefert.
select Wird in Abfrageausdrücken verwendet, um anzugeben, welche Felder oder Spalten extrahiert werden sollen. Beachten Sie, dass dies ein kontextbezogenes Schlüsselwort ist. Dies bedeutet, dass es sich nicht um ein reserviertes Wort handelt und sich nur in einem geeigneten Kontext wie ein Schlüsselwort verhält.
static Wird verwendet, um eine Methode oder Eigenschaft anzugeben, die ohne eine Instanz eines Typs oder ein Wertelement aufgerufen werden kann, das von allen Instanzen eines Typs gemeinsam genutzt wird.
struct

Wird verwendet, um einen Strukturtyp zu deklarieren.

Wird auch in allgemeinen Parametereinschränkungen verwendet.

Wird aus Gründen der OCaml-Kompatibilität in Moduldefinitionen verwendet.

then

Wird in bedingten Ausdrücken verwendet.

Wird auch verwendet, um Nebenwirkungen nach der Objektkonstruktion auszuführen.

to Wird in for-Schleifen verwendet, um einen Bereich anzugeben.
true Wird als Boolesches Literal verwendet.
try Wird verwendet, um einen Codeblock einzuführen, der möglicherweise eine Ausnahme generiert. Wird zusammen mit oder schließlich verwendet.
type Wird verwendet, um eine Klasse, einen Datensatz, eine Struktur, eine diskriminierte Vereinigung, einen Aufzählungstyp, eine Maßeinheit oder eine Typabkürzung zu deklarieren.
upcast Wird verwendet, um in einen Typ zu konvertieren, der in der Vererbungskette höher ist.
use Wird anstelle von let für Werte verwendet, für die Dispose aufgerufen werden muss, um Ressourcen freizugeben.
use! Gebraucht statt vermieten! in asynchronen Workflows und anderen Berechnungsausdrücken für Werte, für die Dispose aufgerufen werden muss, um Ressourcen freizugeben.
val Wird in einer Signatur verwendet, um einen Wert anzugeben, oder in einem Typ, um ein Mitglied in bestimmten Situationen zu deklarieren.
void Gibt den .NET-Leertyp an. Wird bei der Interaktion mit anderen .NET-Sprachen verwendet.
when Wird für boolesche Bedingungen (wenn Wachen) für Musterübereinstimmungen und zum Einführen einer Einschränkungsklausel für einen generischen Typparameter verwendet.
while Führt ein Schleifenkonstrukt ein.
with Wird zusammen mit dem Schlüsselwort match in Mustervergleichsausdrücken verwendet. Wird auch in Objektausdrücken, Datensatzkopierausdrücken und Typerweiterungen verwendet, um Elementdefinitionen und Ausnahmebehandlungsroutinen einzuführen.
yield Wird in einem Sequenzausdruck verwendet, um einen Wert für eine Sequenz zu erzeugen.
yield! Wird in einem Berechnungsausdruck verwendet, um das Ergebnis eines bestimmten Berechnungsausdrucks an eine Sammlung von Ergebnissen für den enthaltenen Berechnungsausdruck anzuhängen.

Einige reservierte Schlüsselwörter stammen aus der OCaml-Sprache -

asr Land lor lsl lsr lxor mod sig

Einige andere reservierte Schlüsselwörter werden für die zukünftige Erweiterung von F # beibehalten.

atomar Unterbrechung überprüft Komponente const Zwang 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

EIN tupleist eine durch Kommas getrennte Sammlung von Werten. Diese werden zum Erstellen von Ad-hoc-Datenstrukturen verwendet, in denen verwandte Werte zusammengefasst werden.

Beispiel: ("Zara Ali", "Hyderabad", 10) ist ein 3-Tupel mit zwei Zeichenfolgenwerten und einem int-Wert. Es hat den Typ (Zeichenfolge * Zeichenfolge * int).

Tupel können Paare, Tripel usw. vom gleichen oder unterschiedlichen Typ sein.

Einige Beispiele finden Sie hier -

// 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)

Beispiel

Dieses Programm hat eine Funktion, die ein Tupel von vier Gleitkommawerten verwendet und den Durchschnitt zurückgibt -

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Avg of four numbers: 7.275000

Zugriff auf einzelne Tupelmitglieder

Die einzelnen Mitglieder eines Tupels konnten unter Verwendung eines Mustervergleichs bewertet und gedruckt werden.

Das folgende Beispiel veranschaulicht das Konzept -

Beispiel

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

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Detail Info: "Zara Ali" "Hyderabad" 10

F # hat zwei eingebaute Funktionen, fst und snd, die das erste und zweite Element in einem 2-Tupel zurückgeben.

Das folgende Beispiel veranschaulicht das Konzept -

Beispiel

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)

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

EIN recordähnelt einem Tupel, enthält jedoch benannte Felder. Zum Beispiel,

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

Datensatz definieren

Ein Datensatz wird als Typ mit dem definiert type Schlüsselwort und die Felder des Datensatzes werden als durch Semikolons getrennte Liste definiert.

Die Syntax zum Definieren eines Datensatzes lautet -

type recordName =
   { [ fieldName : dataType ] + }

Datensatz erstellen

Sie können einen Datensatz erstellen, indem Sie die Felder des Datensatzes angeben. Lassen Sie uns zum Beispiel einen Website- Datensatz mit dem Namen homepage erstellen -

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

Die folgenden Beispiele erläutern die Konzepte -

Beispiel 1

Dieses Programm definiert einen Datensatztyp mit dem Namen website. Anschließend werden einige Datensätze vom Typ Website erstellt und die Datensätze gedruckt.

(* 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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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"

Beispiel 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()

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

In F # ist eine Liste eine geordnete, unveränderliche Reihe von Elementen desselben Typs. Es entspricht in gewissem Maße einer verknüpften Listendatenstruktur.

Das F # -Modul, Microsoft.FSharp.Collections.List,hat die allgemeinen Operationen auf Listen. F # importiert dieses Modul jedoch automatisch und macht es für jede F # -Anwendung zugänglich.

Erstellen und Initialisieren einer Liste

Im Folgenden finden Sie die verschiedenen Möglichkeiten zum Erstellen von Listen:

  • Liste verwenden literals.

  • Verwenden von cons (::) Operator.

  • Verwendung der List.init Methode des Listenmoduls.

  • Mit etwas syntactic constructs namens List Comprehensions.

Literale auflisten

Bei dieser Methode geben Sie einfach eine durch Semikolons getrennte Folge von Werten in eckigen Klammern an. Zum Beispiel -

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

Die Nachteile (: :) Operator

Mit dieser Methode können Sie einige Werte hinzufügen, indem Sie oder voranstellen cons-inges mit dem Operator :: in eine vorhandene Liste. Zum Beispiel -

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

[] bezeichnet eine leere Liste.

List init Methode

Die List.init-Methode des List-Moduls wird häufig zum Erstellen von Listen verwendet. Diese Methode hat den Typ -

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

Das erste Argument ist die gewünschte Länge der neuen Liste, und das zweite Argument ist eine Initialisierungsfunktion, die Elemente in der Liste generiert.

Zum Beispiel,

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

Hier generiert die Indexfunktion die Liste.

Listenverständnisse

Listenverständnis sind spezielle syntaktische Konstrukte, die zum Generieren von Listen verwendet werden.

Die Syntax des F # -Listenverständnisses gibt es in zwei Formen - Bereiche und Generatoren.

Bereiche haben die Konstrukte - [Start .. Ende] und [Start .. Schritt .. Ende]

Zum Beispiel,

let list3 = [1 .. 10]

Generatoren haben das Konstrukt - [für x in Sammlung do ... Ausbeute Ausdruck]

Zum Beispiel,

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

Als die yield Schlüsselwort schiebt einen einzelnen Wert in eine Liste, das Schlüsselwort, yield!, schiebt eine Sammlung von Werten in die Liste.

Die folgende Funktion demonstriert die oben genannten Methoden -

Beispiel

(* 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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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]

Eigenschaften des Listendatentyps

Die folgende Tabelle zeigt verschiedene Eigenschaften des Listendatentyps -

Eigentum Art Beschreibung
Kopf 'T. Das erste Element.
Leer 'T Liste Eine statische Eigenschaft, die eine leere Liste des entsprechenden Typs zurückgibt.
Ist leer Bool true wenn die Liste keine Elemente enthält.
Artikel 'T. Das Element am angegebenen Index (nullbasiert).
Länge int Die Anzahl der Elemente.
Schwanz 'T Liste Die Liste ohne das erste Element.

Das folgende Beispiel zeigt die Verwendung dieser Eigenschaften -

Beispiel

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))

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Grundlegende Operatoren auf Liste

Die folgende Tabelle zeigt die grundlegenden Operationen für den Listendatentyp -

Wert Beschreibung
anhängen: 'T-Liste →' T-Liste → 'T-Liste Gibt eine neue Liste zurück, die die Elemente der ersten Liste gefolgt von den Elementen der zweiten Liste enthält.
Durchschnitt: 'T Liste → ^ T. Gibt den Durchschnitt der Elemente in der Liste zurück.
Durchschnitt durch: ('T → ^ U) →' T Liste → ^ U. Gibt den Durchschnitt der Elemente zurück, die durch Anwenden der Funktion auf jedes Element der Liste generiert wurden.
Wählen Sie: (Option 'T →' U) → 'T-Liste →' U-Liste Wendet die angegebene Funktion auf jedes Element der Liste an. Gibt die Liste mit den Ergebnissen für jedes Element zurück, bei dem die Funktion zurückgegeben wirdSome.
sammeln: ('T →' U-Liste) → 'T-Liste →' U-Liste Wendet für jedes Element der Liste die angegebene Funktion an. Verkettet alle Ergebnisse und gibt die kombinierte Liste zurück.
concat: seq <'T-Liste> →' T-Liste Gibt eine neue Liste zurück, die die Elemente der einzelnen Listen in der angegebenen Reihenfolge enthält.
leer: 'T Liste Gibt eine leere Liste des angegebenen Typs zurück.
existiert: ('T → bool) →' T Liste → bool Testet, ob ein Element der Liste das angegebene Prädikat erfüllt.
existiert2: ('T1 →' T2 → Bool) → 'T1-Liste →' T2-Liste → Bool Testet, ob ein Paar entsprechender Elemente der Listen das angegebene Prädikat erfüllt.
Filter: ('T → bool) →' T-Liste → 'T-Liste Gibt eine neue Sammlung zurück, die nur die Elemente der Sammlung enthält, für die das angegebene Prädikat zurückgegeben wird true.
find: ('T → bool) →' T list → 'T. Gibt das erste Element zurück, für das die angegebene Funktion zurückgegeben wird true.
findIndex: ('T → bool) →' T list → int Gibt den Index des ersten Elements in der Liste zurück, das das angegebene Prädikat erfüllt.
Falz: ('Zustand →' T → 'Zustand) →' Zustand → 'T-Liste →' Zustand Wendet eine Funktion auf jedes Element der Sammlung an und führt ein Akkumulatorargument durch die Berechnung. Diese Funktion nimmt das zweite Argument und wendet die Funktion auf es und das erste Element der Liste an. Dann übergibt es dieses Ergebnis zusammen mit dem zweiten Element an die Funktion und so weiter. Schließlich wird das Endergebnis zurückgegeben. Wenn die Eingabefunktion f ist und die Elemente i0 ... iN sind, berechnet diese Funktion f (... (fs i0) i1 ...) iN.
fold2: ('Status →' T1 → 'T2 →' Status) → 'Status →' T1-Liste → 'T2-Liste →' Status Wendet eine Funktion auf entsprechende Elemente von zwei Sammlungen an und führt ein Akkumulatorargument durch die Berechnung. Die Sammlungen müssen identische Größen haben. Wenn die Eingabefunktion f ist und die Elemente i0 ... iN und j0 ... jN sind, berechnet diese Funktion f (... (fs i0 j0) ...) iN jN.
foldBack: ('T →' Status → 'Status) →' T-Liste → 'Status →' Status Wendet eine Funktion auf jedes Element der Sammlung an und führt ein Akkumulatorargument durch die Berechnung. Wenn die Eingabefunktion isf ist und die Elemente i0 ... iN sind, wird f i0 (... (f iN s)) berechnet.
foldBack2: ('T1 →' T2 → 'Status →' Status) → 'T1-Liste →' T2-Liste → 'Status →' Status Wendet eine Funktion auf entsprechende Elemente von zwei Sammlungen an und führt ein Akkumulatorargument durch die Berechnung. Die Sammlungen müssen identische Größen haben. Wenn die Eingabefunktion f ist und die Elemente i0 ... iN und j0 ... jN sind, berechnet diese Funktion f i0 j0 (... (f iN jN s)).
forall: ('T → bool) →' T list → bool Testet, ob alle Elemente der Sammlung das angegebene Prädikat erfüllen.
forall2: ('T1 →' T2 → Bool) → 'T1-Liste →' T2-Liste → Bool Testet, ob alle entsprechenden Elemente der Sammlung das angegebene Prädikat paarweise erfüllen.
Kopf: 'T Liste →' T. Gibt das erste Element der Liste zurück.
init: int → (int → 'T) →' T Liste Erstellt eine Liste, indem der angegebene Generator für jeden Index aufgerufen wird.
isEmpty: 'T list → bool Kehrt zurück true Wenn die Liste keine Elemente enthält, false Andernfalls.
iter: ('T → Einheit) →' T Liste → Einheit Wendet die angegebene Funktion auf jedes Element der Sammlung an.
iter2: ('T1 →' T2 → Einheit) → 'T1-Liste →' T2-Liste → Einheit Wendet die angegebene Funktion gleichzeitig auf zwei Sammlungen an. Die Sammlungen müssen identisch groß sein.
iteri: (int → 'T → Einheit) →' T Liste → Einheit Wendet die angegebene Funktion auf jedes Element der Sammlung an. Die an die Funktion übergebene Ganzzahl gibt den Index des Elements an.
iteri2: (int → 'T1 →' T2 → Einheit) → 'T1-Liste →' T2-Liste → Einheit Wendet die angegebene Funktion gleichzeitig auf zwei Sammlungen an. Die Sammlungen müssen identisch groß sein. Die an die Funktion übergebene Ganzzahl gibt den Index des Elements an.
Länge: 'T Liste → int Gibt die Länge der Liste zurück.
Karte: ('T →' U) → 'T-Liste →' U-Liste Erstellt eine neue Sammlung, deren Elemente das Ergebnis der Anwendung der angegebenen Funktion auf jedes der Elemente der Sammlung sind.
map2: ('T1 →' T2 → 'U) →' T1-Liste → 'T2-Liste →' U-Liste Erstellt eine neue Sammlung, deren Elemente das Ergebnis der paarweisen Anwendung der angegebenen Funktion auf die entsprechenden Elemente der beiden Sammlungen sind.
map3: ('T1 →' T2 → 'T3 →' U) → 'T1-Liste →' T2-Liste → 'T3-Liste →' U-Liste Erstellt eine neue Sammlung, deren Elemente das Ergebnis der gleichzeitigen Anwendung der angegebenen Funktion auf die entsprechenden Elemente der drei Sammlungen sind.
mapi: (int → 'T →' U) → 'T-Liste →' U-Liste Erstellt eine neue Sammlung, deren Elemente das Ergebnis der Anwendung der angegebenen Funktion auf jedes der Elemente der Sammlung sind. Der an die Funktion übergebene Ganzzahlindex gibt den Index (von 0) des zu transformierenden Elements an.
mapi2: (int → 'T1 →' T2 → 'U) →' T1-Liste → 'T2-Liste →' U-Liste Wie List.mapi, jedoch Zuordnung entsprechender Elemente aus zwei gleich langen Listen.
max: 'T Liste →' T. Gibt das größte aller Elemente der Liste zurück, verglichen mit Operators.max.
maxBy: ('T →' U) → 'T-Liste →' T. Gibt das größte aller Elemente der Liste zurück, verglichen mit Operators.max für das Funktionsergebnis.
min: 'T Liste →' T. Gibt das niedrigste aller Elemente der Liste zurück, verglichen mit Operators.min.
minBy: ('T →' U) → 'T-Liste →' T. Gibt das niedrigste aller Elemente der Liste zurück, verglichen mit Operators.min für das Funktionsergebnis
n.: 'T-Liste → int →' T. Indizes in die Liste. Das erste Element hat den Index 0.
ofArray: 'T [] →' T Liste Erstellt eine Liste aus dem angegebenen Array.
ofSeq: seq <'T> →' T Liste Erstellt eine neue Liste aus dem angegebenen aufzählbaren Objekt.
Partition: ('T → bool) →' T-Liste * 'T-Liste Teilt die Sammlung in zwei Sammlungen auf, die die Elemente enthalten, für die das angegebene Prädikat zurückgegeben wird true und false beziehungsweise.
permute: (int → int) → 'T-Liste →' T-Liste Gibt eine Liste mit allen Elementen zurück, die gemäß der angegebenen Permutation permutiert wurden.
Wählen Sie: (Option 'T →' U) → 'T-Liste →' U. Wendet die angegebene Funktion auf aufeinanderfolgende Elemente an und gibt das erste Ergebnis zurück, bei dem die Funktion zurückgegeben wird Some für einen Wert.
reduzieren: ('T →' T → 'T) →' T Liste → 'T. Wendet eine Funktion auf jedes Element der Sammlung an und führt ein Akkumulatorargument durch die Berechnung. Diese Funktion wendet die angegebene Funktion auf die ersten beiden Elemente der Liste an. Dieses Ergebnis wird dann zusammen mit dem dritten Element an die Funktion übergeben und so weiter. Schließlich wird das Endergebnis zurückgegeben. Wenn die Eingabefunktion f ist und die Elemente i0 ... iN sind, berechnet diese Funktion f (... (f i0 i1) i2 ...) iN.
reduBack: ('T →' T → 'T) →' T-Liste → 'T. Wendet eine Funktion auf jedes Element der Sammlung an und führt ein Akkumulatorargument durch die Berechnung. Wenn die Eingabefunktion isf ist und die Elemente i0 ... iN sind, berechnet diese Funktion f i0 (... (f iN-1 iN)).
replizieren: (int → 'T →' T Liste) Erstellt eine Liste, indem der angegebene Generator für jeden Index aufgerufen wird.
rev: 'T-Liste →' T-Liste Gibt eine neue Liste mit den Elementen in umgekehrter Reihenfolge zurück.
Scan: ('Status →' T → 'Status) →' Status → 'T-Liste →' Statusliste Wendet eine Funktion auf jedes Element der Sammlung an und führt ein Akkumulatorargument durch die Berechnung. Diese Funktion verwendet das zweite Argument und wendet die angegebene Funktion auf sie und das erste Element der Liste an. Dann übergibt es dieses Ergebnis zusammen mit dem zweiten Element an die Funktion und so weiter. Schließlich wird die Liste der Zwischenergebnisse und das Endergebnis zurückgegeben.
scanBack: ('T →' Status → 'Status) →' T-Liste → 'Status →' Statusliste Wie foldBack, gibt jedoch sowohl das Zwischen- als auch das Endergebnis zurück
sort: 'T-Liste →' T-Liste Sortiert die angegebene Liste mit Operators.compare.
sortBy : ('T → 'Key) → 'T list → 'T list Sorts the given list using keys given by the given projection. Keys are compared using Operators.compare.
sortWith : ('T → 'T → int) → 'T list → 'T list Sorts the given list using the given comparison function.
sum : ^T list → ^T Returns the sum of the elements in the list.
sumBy : ('T → ^U) → 'T list → ^U Returns the sum of the results generated by applying the function to each element of the list.
tail : 'T list → 'T list Returns the input list without the first element.
toArray : 'T list → 'T [] Creates an array from the given list.
toSeq : 'T list → seq<'T> Views the given list as a sequence.
tryFind : ('T → bool) → 'T list → 'T option Returns the first element for which the given function returns true. Return None if no such element exists.
tryFindIndex : ('T → bool) → 'T list → int option Returns the index of the first element in the list that satisfies the given predicate. Return None if no such element exists.
tryPick : ('T → 'U option) → 'T list → 'U option Applies the given function to successive elements, returning the first result where function returns Some for some value. If no such element exists then return None.
unzip : ('T1 * 'T2) list → 'T1 list * 'T2 list Splits a list of pairs into two lists.
unzip3 : ('T1 * 'T2 * 'T3) list → 'T1 list * 'T2 list * 'T3 list Splits a list of triples into three lists.
zip : 'T1 list → 'T2 list → ('T1 * 'T2) list Combines the two lists into a list of pairs. The two lists must have equal lengths.
zip3 : 'T1 list → 'T2 list → 'T3 list → ('T1 * 'T2 * 'T3) list Combines the three lists into a list of triples. The lists must have equal lengths.

The following examples demonstrate the uses of the above functionalities −

Example 1

This program shows reversing a list recursively −

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)

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

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

However, you can use the rev function of the module for the same purpose −

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

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

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

Example 2

This program shows filtering a list using the List.filter method −

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

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

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

Example 3

The List.map method maps a list from one type to another −

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

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

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"]

Example 4

The List.append method and the @ operator appends one list to another −

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

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

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']

Example 5

The List.sort method sorts a list. The List.sum method gives the sum of elements in the list and the List.average method gives the average of elements in the list −

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

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

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

A "fold" operation applies a function to each element in a list, aggregates the result of the function in an accumulator variable, and returns the accumulator as the result of the fold operation.

Example 6

The List.fold method applies a function to each element from left to right, while List.foldBack applies a function to each element from right to left.

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 ])

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

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

Sequences, like lists also represent an ordered collection of values. However, the elements in a sequence or sequence expression are computed when required. They are not computed at once, and for this reason they are used to represent infinite data structures.

Defining Sequences

Sequences are defined using the following syntax −

seq { expr }

For example,

let seq1 = seq { 1 .. 10 }

Creating Sequences and Sequences Expressions

Similar to lists, you can create sequences using ranges and comprehensions.

Sequence expressions are the expressions you can write for creating sequences. These can be done −

  • By specifying the range.
  • By specifying the range with increment or decrement.
  • By using the yield keyword to produce values that become part of the sequence.
  • By using the → operator.

The following examples demonstrate the concept −

Example 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

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

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); ...]

Example 2

The following program prints the prime numbers from 1 to 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

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

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

Basic Operations on Sequence

The following table shows the basic operations on sequence data type −

Value Description
append : seq<'T> → seq<'T> → seq<'T> Wraps the two given enumerations as a single concatenated enumeration.
average : seq<^T> → ^T Returns the average of the elements in the sequence.
averageBy : ('T → ^U) → seq<'T> → ^U Returns the average of the results generated by applying the function to each element of the sequence.
cache : seq<'T> → seq<'T> Returns a sequence that corresponds to a cached version of the input sequence.
cast : IEnumerable → seq<'T> Wraps a loosely-typed System. Collections sequence as a typed sequence.
choose : ('T → 'U option) → seq<'T> → seq<'U> Applies the given function to each element of the list. Return the list comprised of the results for each element where the function returns Some.
collect : ('T → 'Collection) → seq<'T> → seq<'U> Applies the given function to each element of the sequence and concatenates all the results.
compareWith : ('T → 'T → int) → seq<'T> → seq<'T> → int Compares two sequences using the given comparison function, element by element.
concat : seq<'Collection> → seq<'T> Combines the given enumeration-of-enumerations as a single concatenated enumeration.
countBy : ('T → 'Key) → seq<'T> → seq<'Key * int> Applies a key-generating function to each element of a sequence and return a sequence yielding unique keys and their number of occurrences in the original sequence.
delay : (unit → seq<'T>) → seq<'T> Returns a sequence that is built from the given delayed specification of a sequence.
distinct : seq<'T> → seq<'T> Returns a sequence that contains no duplicate entries according to generic hash and equality comparisons on the entries. If an element occurs multiple times in the sequence then the later occurrences are discarded.
distinctBy : ('T → 'Key) → seq<'T> → seq<'T> Returns a sequence that contains no duplicate entries according to the generic hash and equality comparisons on the keys returned by the given key-generating function. If an element occurs multiple times in the sequence then the later occurrences are discarded.
empty : seq<'T> Creates an empty sequence.
exactlyOne : seq<'T> → 'T Returns the only element of the sequence.
exists : ('T → bool) → seq<'T> → bool Tests if any element of the sequence satisfies the given predicate.
exists2 : ('T1 → 'T2 → bool) → seq<'T1> → seq<'T2> → bool Tests if any pair of corresponding elements of the input sequences satisfies the given predicate.
filter : ('T → bool) → seq<'T> → seq<'T> Returns a new collection containing only the elements of the collection for which the given predicate returns true.
find : ('T → bool) → seq<'T> → 'T Returns the first element for which the given function returns true.
findIndex : ('T → bool) → seq<'T> → int Returns the index of the first element for which the given function returns true.
fold : ('State → 'T → 'State) → 'State → seq<'T> → 'State Applies a function to each element of the collection, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN, then this function computes f (... (f s i0)...) iN.
forall : ('T → bool) → seq<'T> → bool Tests if all elements of the sequence satisfy the given predicate.
forall2 : ('T1 → 'T2 → bool) → seq<'T1> → seq<'T2> → bool Tests the all pairs of elements drawn from the two sequences satisfy the given predicate. If one sequence is shorter than the other then the remaining elements of the longer sequence are ignored.
groupBy : ('T → 'Key) → seq<'T> → seq<'Key * seq<'T>> Applies a key-generating function to each element of a sequence and yields a sequence of unique keys. Each unique key has also contains a sequence of all elements that match to this key.
head : seq<'T> → 'T Returns the first element of the sequence.
init : int → (int → 'T) → seq<'T> Generates a new sequence which, when iterated, returns successive elements by calling the given function, up to the given count. The results of calling the function are not saved, that is, the function is reapplied as necessary to regenerate the elements. The function is passed the index of the item being generated.
initInfinite : (int → 'T) → seq<'T> Generates a new sequence which, when iterated, will return successive elements by calling the given function. The results of calling the function are not saved, that is, the function will be reapplied as necessary to regenerate the elements. The function is passed the index of the item being generated.
isEmpty : seq<'T> → bool Tests whether a sequence has any elements.
iter : ('T → unit) → seq<'T> → unit Applies the given function to each element of the collection.
iter2 : ('T1 → 'T2 → unit) → seq<'T1> → seq<'T2> → unit Applies the given function to two collections simultaneously. If one sequence is shorter than the other then the remaining elements of the longer sequence are ignored.
iteri : (int → 'T → unit) → seq<'T> → unit Applies the given function to each element of the collection. The integer passed to the function indicates the index of element.
last : seq<'T> → 'T Returns the last element of the sequence.
length : seq<'T> → int Returns the length of the sequence.
map : ('T → 'U) → seq<'T> → seq<'U> Creates a new collection whose elements are the results of applying the given function to each of the elements of the collection. The given function will be applied as elements are demanded using the MoveNext method on enumerators retrieved from the object.
map2 : ('T1 → 'T2 → 'U) → seq<'T1> → seq<'T2> → seq<'U> Creates a new collection whose elements are the results of applying the given function to the corresponding pairs of elements from the two sequences. If one input sequence is shorter than the other then the remaining elements of the longer sequence are ignored.
mapi : (int → 'T → 'U) → seq<'T> → seq<'U> Creates a new collection whose elements are the results of applying the given function to each of the elements of the collection. The integer index passed to the function indicates the index (from 0) of element being transformed.
max : seq<'T> → 'T Returns the greatest of all elements of the sequence, compared by using Operators.max.
maxBy : ('T → 'U) → seq<'T> → 'T Returns the greatest of all elements of the sequence, compared by using Operators.max on the function result.
min : seq<'T> → 'T Returns the lowest of all elements of the sequence, compared by using Operators.min.
minBy : ('T → 'U) → seq<'T> → 'T Returns the lowest of all elements of the sequence, compared by using Operators.min on the function result.
nth : int → seq<'T> → 'T Computes the nth element in the collection.
ofArray : 'T array → seq<'T> Views the given array as a sequence.
ofList : 'T list → seq<'T> Views the given list as a sequence.
pairwise : seq<'T> → seq<'T * 'T> Returns a sequence of each element in the input sequence and its predecessor, with the exception of the first element which is only returned as the predecessor of the second element.
pick : ('T → 'U option) → seq<'T> → 'U Applies the given function to successive elements, returning the first value where the function returns a Some value.
readonly : seq<'T> → seq<'T> Creates a new sequence object that delegates to the given sequence object. This ensures the original sequence cannot be rediscovered and mutated by a type cast. For example, if given an array the returned sequence will return the elements of the array, but you cannot cast the returned sequence object to an array.
reduce : ('T → 'T → 'T) → seq<'T> → 'T Applies a function to each element of the sequence, threading an accumulator argument through the computation. Begin by applying the function to the first two elements. Then feed this result into the function along with the third element and so on. Return the final result.
scan : ('State → 'T → 'State) → 'State → seq<'T> → seq<'State> Like Seq.fold, but computes on-demand and returns the sequence of intermediary and final results.
singleton : 'T → seq<'T> Returns a sequence that yields one item only.
skip : int → seq<'T> → seq<'T> Returns a sequence that skips a specified number of elements of the underlying sequence and then yields the remaining elements of the sequence.
skipWhile : ('T → bool) → seq<'T> → seq<'T> Returns a sequence that, when iterated, skips elements of the underlying sequence while the given predicate returns true, and then yields the remaining elements of the sequence.
sort : seq<'T> → seq<'T> Yields a sequence ordered by keys.
sortBy : ('T → 'Key) → seq<'T> → seq<'T> Applies a key-generating function to each element of a sequence and yield a sequence ordered by keys. The keys are compared using generic comparison as implemented by Operators.compare.
sum : seq<^T> → ^T Returns the sum of the elements in the sequence.
sumBy Returns the sum of the results generated by applying the function to each element of the sequence.
take : int → seq<'T> → seq<'T> Returns the first elements of the sequence up to a specified count.
takeWhile : ('T → bool) → seq<'T> → seq<'T> Returns a sequence that, when iterated, yields elements of the underlying sequence while the given predicate returns true, and then returns no further elements.
toArray : seq<'T> → 'T[] Creates an array from the given collection.
toList : seq<'T> → 'T list Creates a list from the given collection.
truncate : int → seq<'T> → seq<'T> Returns a sequence that when enumerated returns no more than a specified number of elements.
tryFind : ('T → bool) → seq<'T> → 'T option Returns the first element for which the given function returns true, or None if no such element exists.
tryFindIndex : ('T → bool) → seq<'T> → int option Returns the index of the first element in the sequence that satisfies the given predicate, or None if no such element exists.
tryPick : ('T → 'U option) → seq<'T> → 'U option Applies the given function to successive elements, returning the first value where the function returns a Some value.
unfold : ('State → 'T * 'State option) → 'State → seq<'T> Returns a sequence that contains the elements generated by the given computation.
where : ('T → bool) → seq<'T> → seq<'T> Returns a new collection containing only the elements of the collection for which the given predicate returns true. A synonym for Seq.filter.
windowed : int → seq<'T> → seq<'T []> Returns a sequence that yields sliding windows of containing elements drawn from the input sequence. Each window is returned as a fresh array.
zip : seq<'T1> → seq<'T2> → seq<'T1 * 'T2> Combines the two sequences into a list of pairs. The two sequences need not have equal lengths − when one sequence is exhausted any remaining elements in the other sequence are ignored.
zip3 : seq<'T1> → seq<'T2> → seq<'T3> → seq<'T1 * 'T2 * 'T3> Combines the three sequences into a list of triples. The sequences need not have equal lengths − when one sequence is exhausted any remaining elements in the other sequences are ignored.

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

Example 1

This program creates an empty sequence and fills it up later −

(* 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""

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

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

Please note that −

  • The Seq.empty method creates an empty sequence.

  • The Seq.singleton method creates a sequence of just one specified element.

  • The Seq.init method creates a sequence for which the elements are created by using a given function.

  • The Seq.ofArray and Seq.ofList<'T> methods create sequences from arrays and lists.

  • The Seq.iter method allows iterating through a sequence.

Beispiel 2

Die Seq.unfold-Methode generiert eine Sequenz aus einer Berechnungsfunktion, die einen Zustand annimmt und ihn transformiert, um jedes nachfolgende Element in der Sequenz zu erzeugen.

Die folgende Funktion erzeugt die ersten 20 natürlichen Zahlen -

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" "

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Beispiel 3

Die Methode Seq.truncate erstellt eine Sequenz aus einer anderen Sequenz, beschränkt die Sequenz jedoch auf eine bestimmte Anzahl von Elementen.

Die Seq.take-Methode erstellt eine neue Sequenz, die ab dem Beginn einer Sequenz eine bestimmte Anzahl von Elementen enthält.

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""

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Ein Satz in F # ist eine Datenstruktur, die als Sammlung von Elementen fungiert, ohne die Reihenfolge beizubehalten, in der Elemente eingefügt werden. Mit Sets können keine doppelten Einträge in die Sammlung eingefügt werden.

Sets erstellen

Sets können auf folgende Arten erstellt werden:

  • Durch Erstellen eines leeren Satzes mit Set.empty und Hinzufügen von Elementen mit der Funktion add.
  • Konvertieren von Sequenzen und Listen in Sets.

Das folgende Programm demonstriert die Techniken -

(* 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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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]

Grundlegende Operationen an Sets

Die folgende Tabelle zeigt die grundlegenden Operationen an Sets -

Wert Beschreibung
hinzufügen: 'T → Setze <' T> → Setze <'T> Gibt eine neue Menge mit einem Element zurück, das der Menge hinzugefügt wurde. Es wird keine Ausnahme ausgelöst, wenn die Menge bereits das angegebene Element enthält.
enthält: 'T → Set <' T> → bool Evaluiert zu true wenn sich das angegebene Element in der angegebenen Menge befindet.
count: Setze <'T> → int Gibt die Anzahl der Elemente in der Menge zurück.
Unterschied: Setze <'T> → Setze <' T> → Setze <'T> Gibt eine neue Menge zurück, wobei die Elemente der zweiten Menge aus der ersten entfernt wurden.
leer: Setze <'T> Der leere Satz für den angegebenen Typ.
existiert: ('T → bool) → Setze <' T> → bool Testet, ob ein Element der Sammlung das angegebene Prädikat erfüllt. Wenn die Eingabefunktion ein Prädikat ist und die Elemente i0 ... iN sind, berechnet diese Funktion das Prädikat i0 oder ... oder das Prädikat iN.
Filter: ('T → bool) → Setze <' T> → Setze <'T> Gibt eine neue Sammlung zurück, die nur die Elemente der Sammlung enthält, für die das angegebene Prädikat zurückgegeben wird true.
fold: ('State →' T → 'State) →' State → Set <'T> →' State Wendet die angegebene Akkumulationsfunktion auf alle Elemente der Menge an.
foldBack: ('T →' Status → 'Status) → <' T> → 'Status →' Status setzen Wendet die angegebene Akkumulationsfunktion auf alle Elemente der Menge an.
forall: ('T → bool) → Setze <' T> → bool Testet, ob alle Elemente der Sammlung das angegebene Prädikat erfüllen. Wenn die Eingabefunktion p ist und die Elemente i0 ... iN sind, berechnet diese Funktion p i0 && ... && p iN.
überschneiden: Setze <'T> → Setze <' T> → Setze <'T> Berechnet den Schnittpunkt der beiden Mengen.
intersectMany: seq <Set <'T >> → Set <' T> Berechnet den Schnittpunkt einer Folge von Mengen. Die Sequenz darf nicht leer sein.
isEmpty: Setze <'T> → bool Kehrt zurück true wenn das Set leer ist.
isProperSubset: Setze <'T> → Setze <' T> → bool Evaluiert zu true wenn sich alle Elemente des ersten Satzes im zweiten befinden und mindestens ein Element des zweiten Satzes nicht im ersten ist.
isProperSuperset: Setze <'T> → Setze <' T> → bool Evaluiert zu true wenn sich alle Elemente der zweiten Menge in der ersten befinden und mindestens ein Element der ersten nicht in der zweiten ist.
isSubset: Setze <'T> → Setze <' T> → bool Evaluiert zu true wenn sich alle Elemente des ersten Satzes im zweiten befinden.
isSuperset: Setze <'T> → Setze <' T> → bool Evaluiert zu true wenn sich alle Elemente des zweiten Satzes im ersten befinden.
iter: ('T → Einheit) → Setze <' T> → Einheit Wendet die angegebene Funktion in der Reihenfolge der Vergleichsfunktion auf jedes Element der Menge an.
Karte: ('T →' U) → Setze <'T> → Setze <' U> Gibt eine neue Sammlung zurück, die die Ergebnisse der Anwendung der angegebenen Funktion auf jedes Element des Eingabesatzes enthält.
maxElement: Setze <'T> →' T. Gibt das höchste Element in der Menge gemäß der für die Menge verwendeten Reihenfolge zurück.
minElement: Setze <'T> →' T. Gibt das niedrigste Element in der Menge gemäß der für die Menge verwendeten Reihenfolge zurück.
ofArray: 'T-Array → Setze <' T> Erstellt eine Menge, die dieselben Elemente wie das angegebene Array enthält.
ofList: 'T-Liste → Setze <' T> Erstellt eine Menge, die dieselben Elemente wie die angegebene Liste enthält.
ofSeq: seq <'T> → Setze <' T> Erstellt eine neue Sammlung aus dem angegebenen aufzählbaren Objekt.
Partition: ('T → bool) → Setze <' T> → Setze <'T> * Setze <' T> Teilt die Menge in zwei Mengen auf, die die Elemente enthalten, für die das angegebene Prädikat true bzw. false zurückgibt.
entfernen: 'T → Setze <' T> → Setze <'T> Gibt eine neue Menge zurück, bei der das angegebene Element entfernt wurde. Es wird keine Ausnahme ausgelöst, wenn die Menge das angegebene Element nicht enthält.
Singleton: 'T → Setze <' T> Die Menge, die das angegebene Element enthält.
toArray: Setze <'T> →' T Array Erstellt ein Array, das die Elemente der Menge in der angegebenen Reihenfolge enthält.
toList: Setze <'T> →' T Liste Erstellt eine Liste, die die Elemente des Satzes der Reihe nach enthält.
toSeq: Setze <'T> → seq <' T> Gibt eine geordnete Ansicht der Sammlung als aufzählbares Objekt zurück.
Vereinigung: Setze <'T> → Setze <' T> → Setze <'T> Berechnet die Vereinigung der beiden Mengen.
unionMany: seq <Set <'T >> → Set <' T> Berechnet die Vereinigung einer Folge von Mengen.

Das folgende Beispiel zeigt die Verwendung einiger der oben genannten Funktionen -

Beispiel

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""

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

In F # ist eine Karte eine spezielle Art von Menge, die die Werte mit dem Schlüssel verknüpft. Eine Karte wird auf ähnliche Weise erstellt wie Sets.

Karten erstellen

Karten werden erstellt, indem mit Map.empty eine leere Karte erstellt und mit der Funktion Hinzufügen Elemente hinzugefügt werden. Das folgende Beispiel zeigt dies -

Beispiel

(* 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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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")]

Mit dem Schlüssel können Sie auf einzelne Elemente in der Karte zugreifen.

Beispiel

(* 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"]

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Grundlegende Operationen auf Karten

Modulnamen hinzufügen

Die folgende Tabelle zeigt die grundlegenden Operationen auf Karten -

Mitglied Beschreibung
Hinzufügen Gibt eine neue Karte mit der Bindung zurück, die der angegebenen Karte hinzugefügt wurde.
Enthält Schlüssel Testet, ob sich ein Element in der Domäne der Karte befindet.
Anzahl Die Anzahl der Bindungen in der Karte.
Ist leer Gibt true zurück, wenn die Karte keine Bindungen enthält.
Artikel Suchen Sie ein Element in der Karte. Löst eine KeyNotFoundException aus, wenn in der Map keine Bindung vorhanden ist.
Entfernen Entfernt ein Element aus der Domäne der Karte. Es wird keine Ausnahme ausgelöst, wenn das Element nicht vorhanden ist.
TryFind Suchen Sie ein Element in der Karte und geben Sie a zurück Some Wert, wenn sich das Element in der Domäne der Karte befindet und None wenn nicht.

Das folgende Beispiel zeigt die Verwendung einiger der oben genannten Funktionen -

Beispiel

(* 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."

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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.

Mit Gewerkschaften oder diskriminierten Gewerkschaften können Sie komplexe Datenstrukturen aufbauen, die genau definierte Auswahlmöglichkeiten darstellen. Beispielsweise müssen Sie eine Implementierung einer Auswahlvariablen erstellen , die zwei Werte hat: Ja und Nein. Mit dem Tool "Gewerkschaften" können Sie dies entwerfen.

Syntax

Diskriminierte Gewerkschaften werden mit der folgenden Syntax definiert:

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

Unsere einfache Implementierung von, choice, sieht wie folgt aus:

type choice =
   | Yes
   | No

Im folgenden Beispiel wird die Typauswahl verwendet -

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()

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

x: Yes
y: No

Beispiel 1

Das folgende Beispiel zeigt die Implementierung der Spannungszustände, die ein bisschen auf hoch oder niedrig setzen -

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()

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Beispiel 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)

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Variablen in F # sind immutable,Das heißt, sobald eine Variable an einen Wert gebunden ist, kann sie nicht mehr geändert werden. Sie werden tatsächlich als statische schreibgeschützte Eigenschaften kompiliert.

Das folgende Beispiel zeigt dies.

Beispiel

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Fehlermeldung angezeigt:

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

Veränderbare Variablen

Manchmal müssen Sie die in einer Variablen gespeicherten Werte ändern. Um anzugeben, dass sich der Wert einer deklarierten und zugewiesenen Variablen in einem späteren Teil eines Programms ändern kann, stellt F # die bereitmutableStichwort. Mit diesem Schlüsselwort können Sie veränderbare Variablen deklarieren und zuweisen, deren Werte Sie ändern werden.

Das mutable Mit dem Schlüsselwort können Sie Werte in einer veränderlichen Variablen deklarieren und zuweisen.

Sie können einer veränderlichen Variablen mit der Taste einen Anfangswert zuweisen letStichwort. Um ihm jedoch einen neuen nachfolgenden Wert zuzuweisen, müssen Sie den verwenden<- Operator.

Zum Beispiel,

let mutable x = 10
x <- 15

Das folgende Beispiel verdeutlicht das Konzept -

Beispiel

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Verwendung veränderlicher Daten

Veränderbare Daten werden häufig benötigt und in der Datenverarbeitung verwendet, insbesondere bei der Datensatzdatenstruktur. Das folgende Beispiel zeigt dies -

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()

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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";}

Arrays sind auf Null basierende, veränderbare Sammlungen aufeinanderfolgender Datenelemente mit fester Größe, die alle vom gleichen Typ sind.

Arrays erstellen

Sie können Arrays mit verschiedenen Syntaxen und Methoden oder mithilfe der Funktionen des Array-Moduls erstellen. In diesem Abschnitt wird das Erstellen von Arrays ohne Verwendung der Modulfunktionen erläutert.

Es gibt drei syntaktische Möglichkeiten, Arrays ohne Funktionen zu erstellen:

  • Durch Auflisten aufeinanderfolgender Werte zwischen [| und |] und durch Semikolons getrennt.
  • Indem Sie jedes Element in eine separate Zeile setzen. In diesem Fall ist das Semikolon-Trennzeichen optional.
  • Durch Verwendung von Sequenzausdrücken.

Sie können auf Array-Elemente zugreifen, indem Sie einen Punktoperator (.) Und Klammern ([und]) verwenden.

Das folgende Beispiel zeigt das Erstellen von Arrays -

//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" "

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Grundlegende Operationen auf Arrays

Das Bibliotheksmodul Microsoft.FSharp.Collections.Array unterstützt Operationen an eindimensionalen Arrays.

Die folgende Tabelle zeigt die grundlegenden Operationen für Arrays -

Wert Beschreibung
anhängen: 'T [] →' T [] → 'T [] Erstellt ein Array, das die Elemente eines Arrays gefolgt von den Elementen eines anderen Arrays enthält.
Durchschnitt: ^ T [] → ^ T. Gibt den Durchschnitt der Elemente in einem Array zurück.
Durchschnitt durch: ('T → ^ U) →' T [] → ^ U. Gibt den Durchschnitt der Elemente zurück, die durch Anwenden einer Funktion auf jedes Element eines Arrays generiert wurden.
blit: 'T [] → int →' T [] → int → int → Einheit Liest eine Reihe von Elementen aus einem Array und schreibt sie in ein anderes.
Wählen Sie: (Option 'T → U) →' T [] → 'U [] Wendet eine bereitgestellte Funktion auf jedes Element eines Arrays an. Gibt ein Array zurück, das die Ergebnisse x für jedes Element enthält, für das die Funktion Some (x) zurückgibt.
sammle: ('T →' U []) → T [] → 'U [] Wendet die bereitgestellte Funktion auf jedes Element eines Arrays an, verkettet die Ergebnisse und gibt das kombinierte Array zurück.
concat: seq <'T []> →' T [] Erstellt ein Array, das die Elemente jeder der angegebenen Array-Sequenzen enthält.
Kopie: 'T →' T [] Erstellt ein Array, das die Elemente des bereitgestellten Arrays enthält.
create: int → 'T →' T [] Erstellt ein Array, dessen Elemente anfänglich alle der angegebene Wert sind.
leer: 'T [] Gibt ein leeres Array des angegebenen Typs zurück.
existiert: ('T → bool) →' T [] → bool Testet, ob ein Element eines Arrays das angegebene Prädikat erfüllt.
existiert2: ('T1 →' T2 → Bool) → 'T1 [] →' T2 [] → Bool Testet, ob ein Paar entsprechender Elemente von zwei Arrays die angegebene Bedingung erfüllt.
füllen: 'T [] → int → int →' T → Einheit Füllt einen Bereich von Elementen eines Arrays mit dem angegebenen Wert.
Filter: ('T → bool) →' T [] → 'T [] Gibt eine Sammlung zurück, die nur die Elemente des angegebenen Arrays enthält, für die die angegebene Bedingung zurückgegeben wird true.
find: ('T → bool) →' T [] → 'T. Gibt das erste Element zurück, für das die angegebene Funktion zurückgegeben wird true. Löst eine KeyNotFoundException aus, wenn kein solches Element vorhanden ist.
findIndex: ('T → bool) →' T [] → int Gibt den Index des ersten Elements in einem Array zurück, das die angegebene Bedingung erfüllt. Löst eine KeyNotFoundException aus, wenn keines der Elemente die Bedingung erfüllt.
Falz: ('Zustand →' T → 'Zustand) →' Zustand → 'T [] →' Zustand Wendet eine Funktion auf jedes Element eines Arrays an und führt ein Akkumulatorargument durch die Berechnung. Wenn die Eingabefunktion f ist und die Array-Elemente i0 ... iN sind, berechnet diese Funktion f (... (fs i0) ...) iN.
fold2: ('Zustand →' T1 → 'T2 →' Zustand) → 'Zustand →' T1 [] → 'T2 [] →' Zustand Wendet eine Funktion auf Elementpaare aus zwei bereitgestellten Arrays von links nach rechts an, die ein Akkumulatorargument durch die Berechnung führen. Die beiden Eingabearrays müssen gleich lang sein. Andernfalls wird ArgumentException ausgelöst.
foldBack: ('T →' State → 'State) →' T [] → 'State →' State Wendet eine Funktion auf jedes Element eines Arrays an und führt ein Akkumulatorargument durch die Berechnung. Wenn die Eingabefunktion f ist und die Array-Elemente i0 ... iN sind, berechnet diese Funktion f i0 (... (f iN s)).
foldBack2: ('T1 →' T2 → 'Status →' Status) → 'T1 [] →' T2 [] → 'Status →' Status Wendet eine Funktion auf Elementpaare aus zwei bereitgestellten Arrays von rechts nach links an, die ein Akkumulatorargument durch die Berechnung führen. Die beiden Eingabearrays müssen gleich lang sein. Andernfalls wird ArgumentException ausgelöst.
forall: ('T → bool) →' T [] → bool Testet, ob alle Elemente eines Arrays die angegebene Bedingung erfüllen.
forall2: ('T1 →' T2 → bool) → 'T1 [] →' T2 [] → bool Testet, ob alle entsprechenden Elemente von zwei gelieferten Arrays eine gelieferte Bedingung erfüllen.
get: 'T [] → int →' T. Ruft ein Element aus einem Array ab.
init: int → (int → 'T) →' T [] Verwendet eine bereitgestellte Funktion, um ein Array der angegebenen Dimension zu erstellen.
isEmpty: 'T [] → bool Testet, ob ein Array Elemente enthält.
iter: ('T → Einheit) →' T [] → Einheit Wendet die bereitgestellte Funktion auf jedes Element eines Arrays an.
iter2: ('T1 →' T2 → Einheit) → 'T1 [] →' T2 [] → Einheit) Wendet die bereitgestellte Funktion auf ein Elementpaar aus übereinstimmenden Indizes in zwei Arrays an. Die beiden Arrays müssen gleich lang sein. Andernfalls wird ArgumentException ausgelöst.
iteri: (int → 'T → Einheit) →' T [] → Einheit Wendet die bereitgestellte Funktion auf jedes Element eines Arrays an. Die an die Funktion übergebene Ganzzahl gibt den Index des Elements an.
iteri2: (int → 'T1 →' T2 → Einheit) → 'T1 [] →' T2 [] → Einheit Wendet die bereitgestellte Funktion auf ein Elementpaar aus übereinstimmenden Indizes in zwei Arrays an und übergibt auch den Index der Elemente. Die beiden Arrays müssen gleich lang sein. Andernfalls wird eine ArgumentException ausgelöst.
Länge: 'T [] → int Gibt die Länge eines Arrays zurück. Die Length-Eigenschaft macht dasselbe.
Karte: ('T →' U) → 'T [] →' U [] Erstellt ein Array, dessen Elemente das Ergebnis der Anwendung der angegebenen Funktion auf jedes der Elemente eines bereitgestellten Arrays sind.
map2: ('T1 →' T2 → 'U) →' T1 [] → 'T2 [] →' U [] Erstellt ein Array, dessen Elemente das Ergebnis der Anwendung der angegebenen Funktion auf die entsprechenden Elemente von zwei bereitgestellten Arrays sind. Die beiden Eingabearrays müssen gleich lang sein. Andernfalls wird ArgumentException ausgelöst.
mapi: (int → 'T →' U) → 'T [] →' U [] Erstellt ein Array, dessen Elemente das Ergebnis der Anwendung der angegebenen Funktion auf jedes der Elemente eines bereitgestellten Arrays sind. Ein an die Funktion übergebener ganzzahliger Index gibt den Index des zu transformierenden Elements an.
mapi2: (int → 'T1 →' T2 → 'U) →' T1 [] → 'T2 [] →' U [] Erstellt ein Array, dessen Elemente das Ergebnis der paarweisen Anwendung der angegebenen Funktion auf die entsprechenden Elemente der beiden Sammlungen sind, wobei auch der Index der Elemente übergeben wird. Die beiden Eingabearrays müssen gleich lang sein. Andernfalls wird ArgumentException ausgelöst.
max: 'T [] →' T. Gibt das größte aller Elemente eines Arrays zurück. Mit Operators.max werden die Elemente verglichen.
maxBy: ('T →' U) → 'T [] →' T. Gibt das größte aller Elemente eines Arrays zurück, verglichen mit Operators.max für das Funktionsergebnis.
min: ('T [] →' T. Gibt das kleinste aller Elemente eines Arrays zurück. Mit Operators.min werden die Elemente verglichen.
minBy: ('T →' U) → 'T [] →' T. Gibt das kleinste aller Elemente eines Arrays zurück. Mit Operators.min werden die Elemente verglichen.
ofList: 'T Liste →' T [] Erstellt ein Array aus der bereitgestellten Liste.
ofSeq: seq <'T> →' T [] Erstellt ein Array aus dem angegebenen aufzählbaren Objekt.
Partition: ('T → bool) →' T [] → 'T [] *' T [] Teilt ein Array in zwei Arrays auf, von denen eines die Elemente enthält, für die die angegebene Bedingung zurückgegeben wird true, und die andere enthält diejenigen, für die es zurückkehrt false.
permutieren: (int → int) → 'T [] →' T [] Permutiert die Elemente eines Arrays gemäß der angegebenen Permutation.
Wählen Sie: (Option 'T →' U) → 'T [] →' U. Wendet die bereitgestellte Funktion auf aufeinanderfolgende Elemente eines bereitgestellten Arrays an und gibt das erste Ergebnis zurück, wobei die Funktion Some (x) für some x zurückgibt. Wenn die Funktion niemals Some (x) zurückgibt, wird KeyNotFoundException ausgelöst.
reduzieren: ('T →' T → 'T) →' T [] → 'T. Wendet eine Funktion auf jedes Element eines Arrays an und führt ein Akkumulatorargument durch die Berechnung. Wenn die Eingabefunktion f ist und die Array-Elemente i0 ... iN sind, berechnet diese Funktion f (... (f i0 i1) ...) iN. Wenn das Array die Größe Null hat, wird ArgumentException ausgelöst.
reduBack: ('T →' T → 'T) →' T [] → 'T. Wendet eine Funktion auf jedes Element eines Arrays an und führt ein Akkumulatorargument durch die Berechnung. Wenn die Eingabefunktion f ist und die Elemente i0 ... iN sind, berechnet diese Funktion f i0 (... (f iN-1 iN)). Wenn das Array die Größe Null hat, wird ArgumentException ausgelöst.
rev: 'T [] →' T [] Kehrt die Reihenfolge der Elemente in einem bereitgestellten Array um.
Scan: ('Status →' T → 'Status) →' Status → 'T [] →' Status []) Benimmt sich wie Fold, gibt aber die Zwischenergebnisse zusammen mit den Endergebnissen zurück.
scanBack: ('T →' Status → 'Status) →' T [] → 'Status →' Status [] Verhält sich wie foldBack, gibt jedoch die Zwischenergebnisse zusammen mit den Endergebnissen zurück.
set: 'T [] → int →' T → Einheit Legt ein Element eines Arrays fest.
sort: 'T [] →' T [] Sortiert die Elemente eines Arrays und gibt ein neues Array zurück. Mit Operators.compare werden die Elemente verglichen.
sortBy: ('T →' Taste) → 'T [] →' T [] Sortiert die Elemente eines Arrays mithilfe der angegebenen Funktion, um die Elemente in den Typ zu transformieren, auf dem die Sortieroperation basiert, und gibt ein neues Array zurück. Mit Operators.compare werden die Elemente verglichen.
sortInPlace: 'T [] → Einheit Sortiert die Elemente eines Arrays, indem das Array mithilfe der mitgelieferten Vergleichsfunktion geändert wird. Mit Operators.compare werden die Elemente verglichen.
sortInPlaceBy: ('T →' Taste) → 'T [] → Einheit Sortiert die Elemente eines Arrays, indem das Array mithilfe der mitgelieferten Projektion für die Schlüssel geändert wird. Mit Operators.compare werden die Elemente verglichen.
sortInPlaceWith: ('T →' T → int) → 'T [] → Einheit Sortiert die Elemente eines Arrays mithilfe der mitgelieferten Vergleichsfunktion, um das Array an Ort und Stelle zu ändern.
sortWith: ('T →' T → int) → 'T [] →' T [] Sortiert die Elemente eines Arrays mithilfe der bereitgestellten Vergleichsfunktion und gibt ein neues Array zurück.
sub: 'T [] → int → int →' T [] Erstellt ein Array, das den angegebenen Unterbereich enthält, der durch Startindex und Länge angegeben wird.
Summe: 'T [] → ^ T. Gibt die Summe der Elemente im Array zurück.
sumBy: ('T → ^ U) →' T [] → ^ U. Gibt die Summe der Ergebnisse zurück, die durch Anwenden einer Funktion auf jedes Element eines Arrays generiert wurden.
toList: 'T [] →' T Liste Konvertiert das bereitgestellte Array in eine Liste.
toSeq: 'T [] → seq <' T> Zeigt das bereitgestellte Array als Sequenz an.
tryFind: ('T → bool) →' T [] → 'T Option Gibt das erste Element im angegebenen Array zurück, für das die angegebene Funktion zurückgegeben wird true. Kehrt zurückNone wenn kein solches Element vorhanden ist.
tryFindIndex: (Option 'T → bool) →' T [] → int Gibt den Index des ersten Elements in einem Array zurück, das die angegebene Bedingung erfüllt.
tryPick: (Option 'T →' U) → Option 'T [] →' U Wendet die angegebene Funktion auf aufeinanderfolgende Elemente des bereitgestellten Arrays an und gibt das erste Ergebnis zurück, wobei die Funktion Some (x) für some x zurückgibt. Wenn die Funktion niemals Some (x) zurückgibt,None ist zurück gekommen.
entpacken: ('T1 *' T2) [] → 'T1 [] *' T2 [] Teilt ein Array von Tupelpaaren in ein Tupel von zwei Arrays auf.
unzip3: ('T1 *' T2 * 'T3) [] →' T1 [] * 'T2 [] *' T3 [] Teilt ein Array von Tupeln mit drei Elementen in ein Tupel mit drei Arrays auf.
zeroCreate: int → 'T [] Erstellt ein Array, dessen Elemente anfänglich auf den Standardwert Unchecked.defaultof <'T> gesetzt sind.
zip: 'T1 [] →' T2 [] → ('T1 *' T2) [] Kombiniert zwei Arrays zu einem Array von Tupeln mit zwei Elementen. Die beiden Arrays müssen gleich lang sein. Andernfalls wird ArgumentException ausgelöst.
zip3: 'T1 [] →' T2 [] → 'T3 [] → (' T1 * 'T2 * 113' T3) [] Kombiniert drei Arrays zu einem Array von Tupeln mit drei Elementen. Die drei Arrays müssen gleich lang sein. Andernfalls wird ArgumentException ausgelöst.

Im folgenden Abschnitt werden wir die Verwendung einiger dieser Funktionen sehen.

Erstellen von Arrays mithilfe von Funktionen

Das Array-Modul bietet verschiedene Funktionen, mit denen ein Array von Grund auf neu erstellt wird.

  • Das Array.empty Funktion erstellt ein neues leeres Array.

  • Das Array.create Die Funktion erstellt ein Array mit einer bestimmten Größe und setzt alle Elemente auf bestimmte Werte.

  • Das Array.init Funktion erstellt ein Array mit einer Dimension und einer Funktion zum Generieren der Elemente.

  • Das Array.zeroCreate Funktion erstellt ein Array, in dem alle Elemente auf den Nullwert initialisiert werden.

  • Das Array.copy Die Funktion erstellt ein neues Array, das Elemente enthält, die aus einem vorhandenen Array kopiert werden.

  • Das Array.sub Die Funktion generiert ein neues Array aus einem Unterbereich eines Arrays.

  • Das Array.append Die Funktion erstellt ein neues Array, indem zwei vorhandene Arrays kombiniert werden.

  • Das Array.choose Die Funktion wählt Elemente eines Arrays aus, die in ein neues Array aufgenommen werden sollen.

  • Das Array.collect function führt eine angegebene Funktion für jedes Array-Element eines vorhandenen Arrays aus und sammelt dann die von der Funktion generierten Elemente und kombiniert sie zu einem neuen Array.

  • Das Array.concat Die Funktion nimmt eine Folge von Arrays und kombiniert sie zu einem einzigen Array.

  • Das Array.filter Die Funktion verwendet eine boolesche Bedingungsfunktion und generiert ein neues Array, das nur die Elemente aus dem Eingabearray enthält, für die die Bedingung erfüllt ist.

  • Das Array.rev Die Funktion generiert ein neues Array, indem sie die Reihenfolge eines vorhandenen Arrays umkehrt.

Die folgenden Beispiele veranschaulichen diese Funktionen -

Beispiel 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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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|]

Beispiel 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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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|]

Arrays suchen

Das Array.find Die Funktion verwendet eine Boolesche Funktion und gibt das erste Element zurück, für das die Funktion true zurückgibt. Andernfalls wird eine KeyNotFoundException ausgelöst.

Das Array.findIndex Die Funktion funktioniert ähnlich, außer dass sie den Index des Elements anstelle des Elements selbst zurückgibt.

Das folgende Beispiel zeigt dies.

Microsoft bietet dieses interessante Programmbeispiel, bei dem das erste Element im Bereich einer bestimmten Zahl gefunden wird, das sowohl ein perfektes Quadrat als auch ein perfekter Würfel ist.

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Das List<'T> Klasse repräsentiert eine stark typisierte Liste von Objekten, auf die über den Index zugegriffen werden kann.

Es ist ein veränderliches Gegenstück zur List-Klasse. Es ähnelt Arrays, da über einen Index darauf zugegriffen werden kann. Im Gegensatz zu Arrays können Listen jedoch in der Größe geändert werden. Daher müssen Sie bei der Deklaration keine Größe angeben.

Erstellen einer veränderlichen Liste

Listen werden mit dem erstellt newSchlüsselwort und Aufruf des Konstruktors der Liste. Das folgende Beispiel zeigt dies -

(* 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])

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Die List (T) -Klasse

Die Klasse List (T) repräsentiert eine stark typisierte Liste von Objekten, auf die über den Index zugegriffen werden kann. Es bietet Methoden zum Suchen, Sortieren und Bearbeiten von Listen.

Die folgenden Tabellen enthalten die Eigenschaften, Konstruktoren und Methoden der List (T) -Klasse -

Eigenschaften

Eigentum Beschreibung
Kapazität Ruft die Gesamtzahl der Elemente ab, die die interne Datenstruktur ohne Größenänderung enthalten kann, oder legt diese fest.
Anzahl Ruft die Anzahl der in der Liste (T) enthaltenen Elemente ab.
Artikel Ruft das Element ab oder setzt es auf den angegebenen Index.

Konstruktoren

Konstrukteur Beschreibung
Liste (T) () Initialisiert eine neue Instanz der List (T) -Klasse, die leer ist und die Standard-Anfangskapazität hat.
Liste (T) (IEnumerable (T)) Initialisiert eine neue Instanz der List (T) -Klasse, die Elemente enthält, die aus der angegebenen Sammlung kopiert wurden, und über eine ausreichende Kapazität verfügt, um die Anzahl der kopierten Elemente aufzunehmen.
Liste (T) (Int32) Initialisiert eine neue Instanz der List (T) -Klasse, die leer ist und die angegebene Anfangskapazität hat.

Methode

Methoden Beschreibung
Hinzufügen Fügt am Ende der Liste ein Objekt hinzu (T).
AddRange Fügt die Elemente der angegebenen Sammlung am Ende der Liste hinzu (T).
AsReadOnly Gibt einen schreibgeschützten IList (T) -Wrapper für die aktuelle Sammlung zurück.
BinarySearch (T) Durchsucht die gesamte sortierte Liste (T) mit dem Standardvergleich nach einem Element und gibt den auf Null basierenden Index des Elements zurück.
BinarySearch (T, IComparer (T)) Durchsucht die gesamte sortierte Liste (T) nach einem Element unter Verwendung des angegebenen Vergleichers und gibt den auf Null basierenden Index des Elements zurück.
BinarySearch (Int32, Int32, T, IComparer (T)) Durchsucht einen Bereich von Elementen in der sortierten Liste (T) nach einem Element unter Verwendung des angegebenen Vergleichers und gibt den auf Null basierenden Index des Elements zurück.
klar Entfernt alle Elemente aus der Liste (T).
Enthält Bestimmt, ob sich ein Element in der Liste befindet (T).
ConvertAll (TOutput) Konvertiert die Elemente in der aktuellen Liste (T) in einen anderen Typ und gibt eine Liste mit den konvertierten Elementen zurück.
CopyTo (T []) Kopiert die gesamte Liste (T) in ein kompatibles eindimensionales Array, beginnend am Anfang des Zielarrays.
CopyTo (T [], Int32) Kopiert die gesamte Liste (T) in ein kompatibles eindimensionales Array, beginnend mit dem angegebenen Index des Zielarrays.
CopyTo (Int32, T [], Int32, Int32) Kopiert eine Reihe von Elementen aus der Liste (T) in ein kompatibles eindimensionales Array, beginnend mit dem angegebenen Index des Zielarrays.
Gleich (Objekt) Legt fest, ob das angegebene Objekt dem aktuellen Objekt entspricht. (Vom Objekt geerbt.)
Existiert Legt fest, ob die Liste (T) Elemente enthält, die den durch das angegebene Prädikat definierten Bedingungen entsprechen.
Finalisieren Ermöglicht einem Objekt, Ressourcen freizugeben und andere Bereinigungsvorgänge auszuführen, bevor es von der Speicherbereinigung (von Objekt geerbt) zurückgefordert wird.
Finden Sucht nach einem Element, das den durch das angegebene Prädikat definierten Bedingungen entspricht, und gibt das erste Vorkommen in der gesamten Liste (T) zurück.
Finde alle Ruft alle Elemente ab, die den durch das angegebene Prädikat definierten Bedingungen entsprechen.
FindIndex (Prädikat (T)) Sucht nach einem Element, das den durch das angegebene Prädikat definierten Bedingungen entspricht, und gibt den auf Null basierenden Index des ersten Vorkommens in der gesamten Liste (T) zurück.
FindIndex (Int32, Prädikat (T)) Sucht nach einem Element, das den durch das angegebene Prädikat definierten Bedingungen entspricht, und gibt den auf Null basierenden Index des ersten Vorkommens innerhalb des Elementbereichs in der Liste (T) zurück, der sich vom angegebenen Index bis zum letzten Element erstreckt.
FindIndex (Int32, Int32, Prädikat (T)) Sucht nach einem Element, das den durch das angegebene Prädikat definierten Bedingungen entspricht, und gibt den auf Null basierenden Index des ersten Auftretens innerhalb des Elementbereichs in der Liste (T) zurück, der am angegebenen Index beginnt und die angegebene Anzahl von Elementen enthält.
FindLast Sucht nach einem Element, das den durch das angegebene Prädikat definierten Bedingungen entspricht, und gibt das letzte Vorkommen in der gesamten Liste (T) zurück.
FindLastIndex (Prädikat (T)) Sucht nach einem Element, das den durch das angegebene Prädikat definierten Bedingungen entspricht, und gibt den auf Null basierenden Index des letzten Vorkommens in der gesamten Liste (T) zurück.
FindLastIndex (Int32, Prädikat (T)) Sucht nach einem Element, das den durch das angegebene Prädikat definierten Bedingungen entspricht, und gibt den auf Null basierenden Index des letzten Vorkommens innerhalb des Elementbereichs in der Liste (T) zurück, der sich vom ersten Element bis zum angegebenen Index erstreckt.
FindLastIndex (Int32, Int32, Prädikat (T)) Sucht nach einem Element, das den durch das angegebene Prädikat definierten Bedingungen entspricht, und gibt den auf Null basierenden Index des letzten Vorkommens innerhalb des Elementbereichs in der Liste (T) zurück, der die angegebene Anzahl von Elementen enthält und am angegebenen Index endet.
Für jeden Führt die angegebene Aktion für jedes Element der Liste aus (T).
GetEnumerator Gibt einen Enumerator zurück, der die Liste (T) durchläuft.
GetHashCode Dient als Standard-Hash-Funktion. (Vom Objekt geerbt.)
GetRange Erstellt eine flache Kopie einer Reihe von Elementen in der Quellliste (T).
GetType Ruft den Typ der aktuellen Instanz ab. (Vom Objekt geerbt.)
IndexOf (T) Sucht nach dem angegebenen Objekt und gibt den auf Null basierenden Index des ersten Vorkommens in der gesamten Liste (T) zurück.
IndexOf (T, Int32) Sucht nach dem angegebenen Objekt und gibt den auf Null basierenden Index des ersten Vorkommens innerhalb des Elementbereichs in der Liste (T) zurück, der sich vom angegebenen Index bis zum letzten Element erstreckt.
IndexOf (T, Int32, Int32) Sucht nach dem angegebenen Objekt und gibt den auf Null basierenden Index des ersten Vorkommens innerhalb des Elementbereichs in der Liste (T) zurück, der am angegebenen Index beginnt und die angegebene Anzahl von Elementen enthält.
Einfügen Fügt ein Element am angegebenen Index in die Liste (T) ein.
InsertRange Fügt die Elemente einer Sammlung am angegebenen Index in die Liste (T) ein.
LastIndexOf (T) Sucht nach dem angegebenen Objekt und gibt den auf Null basierenden Index des letzten Vorkommens in der gesamten Liste (T) zurück.
LastIndexOf (T, Int32) Sucht nach dem angegebenen Objekt und gibt den auf Null basierenden Index des letzten Vorkommens innerhalb des Elementbereichs in der Liste (T) zurück, der sich vom ersten Element bis zum angegebenen Index erstreckt.
LastIndexOf (T, Int32, Int32) Sucht nach dem angegebenen Objekt und gibt den auf Null basierenden Index des letzten Vorkommens innerhalb des Elementbereichs in der Liste (T) zurück, der die angegebene Anzahl von Elementen enthält und am angegebenen Index endet.
MemberwiseClone Erstellt eine flache Kopie des aktuellen Objekts. (Vom Objekt geerbt.)
Entfernen Entfernt das erste Auftreten eines bestimmten Objekts aus der Liste (T).
Alles entfernen Entfernt alle Elemente, die den durch das angegebene Prädikat definierten Bedingungen entsprechen.
RemoveAt Entfernt das Element am angegebenen Index der Liste (T).
RemoveRange Entfernt eine Reihe von Elementen aus der Liste (T).
Umkehren() Kehrt die Reihenfolge der Elemente in der gesamten Liste um (T).
Rückwärts (Int32, Int32) Kehrt die Reihenfolge der Elemente im angegebenen Bereich um.
Sortieren() Sortiert die Elemente in der gesamten Liste (T) mit dem Standardvergleicher.
Sortieren (Vergleich (T)) Sortiert die Elemente in der gesamten Liste (T) unter Verwendung des angegebenen Systems. Vergleich (T).
Sortieren (IComparer (T)) Sortiert die Elemente in der gesamten Liste (T) mit dem angegebenen Vergleicher.
Sortieren (Int32, Int32, IComparer (T)) Sortiert die Elemente in einer Reihe von Elementen in Liste (T) unter Verwendung des angegebenen Vergleichers.
ToArray Kopiert die Elemente der Liste (T) in ein neues Array.
ToString Gibt eine Zeichenfolge zurück, die das aktuelle Objekt darstellt. (Vom Objekt geerbt.)
TrimExcess Legt die Kapazität auf die tatsächliche Anzahl der Elemente in der Liste (T) fest, wenn diese Anzahl unter einem Schwellenwert liegt.
TrueForAll Legt fest, ob jedes Element in der Liste (T) den durch das angegebene Prädikat definierten Bedingungen entspricht.

Beispiel

(* 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])

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Das Dictionary<'TKey, 'TValue> Klasse ist das veränderbare Analogon der F # -Kartendatenstruktur und enthält viele der gleichen Funktionen.

In Anlehnung an das Kapitel "Karte" in F # ist eine Karte eine spezielle Art von Menge, die die Werte mit dem Schlüssel verknüpft.

Erstellen eines veränderlichen Wörterbuchs

Veränderbare Wörterbücher werden mit dem erstellt newSchlüsselwort und Aufruf des Konstruktors der Liste. Das folgende Beispiel zeigt dies -

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Die Wörterbuchklasse (TKey, TValue)

Die Dictionary-Klasse (TKey, TValue) repräsentiert eine Sammlung von Schlüsseln und Werten.

Die folgenden Tabellen enthalten die Eigenschaften, Konstruktoren und Methoden der List (T) -Klasse -

Eigenschaften

Eigentum Beschreibung
Vergleicher Ruft den IEqualityComparer (T) ab, mit dem die Schlüsselgleichheit für das Wörterbuch bestimmt wird.
Anzahl Ruft die Anzahl der im Wörterbuch enthaltenen Schlüssel / Wert-Paare ab (TKey, TValue).
Artikel Ruft den dem angegebenen Schlüssel zugeordneten Wert ab oder legt diesen fest.
Schlüssel Ruft eine Sammlung mit den Schlüsseln im Wörterbuch ab (TKey, TValue).
Werte Ruft eine Sammlung mit den Werten im Wörterbuch ab (TKey, TValue).

Konstruktoren

Konstruktoren Beschreibung
Wörterbuch (TKey, TValue) () Initialisiert eine neue Instanz von Dictionary(TKey, TValue) Klasse, die leer ist, die anfängliche Standardkapazität hat und den Standardgleichheitsvergleich für den Schlüsseltyp verwendet.
Wörterbuch (TKey, TValue) (IDictionary (TKey, TValue)) Initialisiert eine neue Instanz von Dictionary(TKey, TValue) Klasse, die Elemente enthält, die aus dem angegebenen kopiert wurden IDictionary(TKey, TValue) und verwendet den Standardgleichheitsvergleich für den Schlüsseltyp.
Wörterbuch (TKey, TValue) (IEqualityComparer (TKey)) Initialisiert eine neue Instanz von Dictionary(TKey, TValue) Klasse, die leer ist, die Standard-Anfangskapazität hat und die angegebene verwendet IEqualityComparer(T).
Wörterbuch (TKey, TValue) (Int32) Initialisiert eine neue Instanz von Dictionary(TKey, TValue) Klasse, die leer ist, die angegebene Anfangskapazität hat und den Standardgleichheitsvergleich für den Schlüsseltyp verwendet.
Wörterbuch (TKey, TValue) (IDictionary (TKey, TValue), IEqualityComparer (TKey)) Initialisiert eine neue Instanz von Dictionary(TKey, TValue) Klasse, die Elemente enthält, die aus dem angegebenen kopiert wurden IDictionary(TKey, TValue) und verwendet die angegebenen IEqualityComparer(T).
Wörterbuch (TKey, TValue) (Int32, IEqualityComparer (TKey)) Initialisiert eine neue Instanz von Dictionary(TKey, TValue) Klasse, die leer ist, die angegebene Anfangskapazität hat und die angegebene verwendet IEqualityComparer(T).
Wörterbuch (TKey, TValue) (SerializationInfo, StreamingContext) Initialisiert eine neue Instanz von ictionary(TKey, TValue) Klasse mit serialisierten Daten.

Methoden

Methode Beschreibung
Hinzufügen Fügt dem Wörterbuch den angegebenen Schlüssel und Wert hinzu.
klar Entfernt alle Schlüssel und Werte aus dem Wörterbuch (TKey, TValue).
Enthält Schlüssel Legt fest, ob das Wörterbuch (TKey, TValue) den angegebenen Schlüssel enthält.
Enthält Wert Legt fest, ob das Wörterbuch (TKey, TValue) einen bestimmten Wert enthält.
Gleich (Objekt) Legt fest, ob das angegebene Objekt dem aktuellen Objekt entspricht. (Vom Objekt geerbt.)
Finalisieren Ermöglicht einem Objekt, Ressourcen freizugeben und andere Bereinigungsvorgänge auszuführen, bevor es von der Garbage Collection zurückgefordert wird. (Vom Objekt geerbt.)
GetEnumerator Gibt einen Enumerator zurück, der das Wörterbuch durchläuft (TKey, TValue).
GetHashCode Dient als Standard-Hash-Funktion. (Vom Objekt geerbt.)
GetObjectData Implementiert die System.Runtime.Serialization.ISerializable-Schnittstelle und gibt die Daten zurück, die zum Serialisieren der Dictionary-Instanz (TKey, TValue) erforderlich sind.
GetType Ruft den Typ der aktuellen Instanz ab. (Vom Objekt geerbt.)
MemberwiseClone Erstellt eine flache Kopie des aktuellen Objekts. (Vom Objekt geerbt.)
OnDeserialization Implementiert die System.Runtime.Serialization.ISerializable-Schnittstelle und löst das Deserialisierungsereignis aus, wenn die Deserialisierung abgeschlossen ist.
Entfernen Entfernt den Wert mit dem angegebenen Schlüssel aus dem Wörterbuch (TKey, TValue).
ToString Gibt eine Zeichenfolge zurück, die das aktuelle Objekt darstellt. (Vom Objekt geerbt.)
TryGetValue Ruft den dem angegebenen Schlüssel zugeordneten Wert ab.

Beispiel

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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"]

Grundlegende Eingabe Ausgabe umfasst -

  • Lesen von und Schreiben in die Konsole.
  • Lesen aus und Schreiben in eine Datei.

Core.Printf-Modul

Wir haben die Funktionen printf und printfn zum Schreiben in die Konsole verwendet. In diesem Abschnitt werden wir uns mit den Details derPrintf Modul von F #.

Abgesehen von den oben genannten Funktionen verfügt das Core.Printf- Modul von F # über verschiedene andere Methoden zum Drucken und Formatieren unter Verwendung von% -Markierungen als Platzhalter. Die folgende Tabelle zeigt die Methoden mit kurzer Beschreibung -

Wert Beschreibung
bprintf: StringBuilder → BuilderFormat <'T> →' T. Druckt in einen StringBuilder.
eprintf: TextWriterFormat <'T> →' T. Druckt die formatierte Ausgabe an stderr.
eprintfn: TextWriterFormat <'T> →' T. Druckt die formatierte Ausgabe nach stderr und fügt eine neue Zeile hinzu.
failwithf: StringFormat <'T,' Ergebnis> → 'T. Druckt in einen Zeichenfolgenpuffer und löst mit dem angegebenen Ergebnis eine Ausnahme aus.
fprintf: TextWriter → TextWriterFormat <'T> →' T. Druckt auf einem Textschreiber.
fprintfn: TextWriter → TextWriterFormat <'T> →' T. Druckt auf einem Textschreiber und fügt eine neue Zeile hinzu.
kbprintf: (Einheit → 'Ergebnis) → StringBuilder → BuilderFormat <' T, 'Ergebnis> →' T. Wie bprintf, ruft jedoch die angegebene Funktion auf, um das Ergebnis zu generieren.
kfprintf: (Einheit → 'Ergebnis) → TextWriter → TextWriterFormat <' T, 'Ergebnis> →' T. Wie fprintf, ruft jedoch die angegebene Funktion auf, um das Ergebnis zu generieren.
kprintf: (string → 'Ergebnis) → StringFormat <' T, 'Ergebnis> →' T. Wie printf, ruft jedoch die angegebene Funktion auf, um das Ergebnis zu generieren. Diese lassen den Druck beispielsweise eine Spülung erzwingen, nachdem alle Ausgaben in den Kanal eingegeben wurden, jedoch nicht vorher.
ksprintf: (string → 'Ergebnis) → StringFormat <' T, 'Ergebnis> →' T. Wie sprintf, ruft jedoch die angegebene Funktion auf, um das Ergebnis zu generieren.
printf: TextWriterFormat <'T> →' T. Druckt die formatierte Ausgabe auf stdout.
printfn: TextWriterFormat <'T> →' T. Druckt die formatierte Ausgabe in stdout und fügt eine neue Zeile hinzu.
sprintf: StringFormat <'T> →' T. Druckt unter Verwendung eines internen Zeichenfolgenpuffers in eine Zeichenfolge und gibt das Ergebnis als Zeichenfolge zurück.

Formatspezifikationen

Formatspezifikationen werden zum Formatieren der Eingabe oder Ausgabe verwendet, je nach Bedarf der Programmierer.

Dies sind Zeichenfolgen mit% -Markierungen, die Platzhalter für das Format angeben.

Die Syntax eines Format-Platzhalters lautet -

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

Das type wird interpretiert als -

Art Beschreibung
% b Formate a bool, formatiert als true oder false.
% c Formatiert ein Zeichen.
% s Formate a string, als Inhalt formatiert, ohne Escapezeichen zu interpretieren.
% d,% i Formatiert jeden Basis-Integer-Typ, der als Dezimal-Integer formatiert ist und signiert ist, wenn der Basic-Integer-Typ signiert ist.
% u Formatiert jeden einfachen Ganzzahltyp, der als vorzeichenlose Dezimalzahl formatiert ist.
% x Formatiert jeden einfachen Ganzzahltyp, der als vorzeichenlose hexadezimale Ganzzahl formatiert ist, wobei Kleinbuchstaben a bis f verwendet werden.
% X. Formatiert jeden einfachen Ganzzahltyp, der als vorzeichenlose hexadezimale Ganzzahl formatiert ist, wobei Großbuchstaben A bis F verwendet werden.
Formatiert jeden einfachen Ganzzahltyp, der als vorzeichenlose oktale Ganzzahl formatiert ist.
% e,% E,% f,% F,% g,% G. Formatiert jeden grundlegenden Gleitkommatyp (float, float32) Formatiert mit einem Gleitkommaformat im C-Stil.
% e,% E. Formatiert einen vorzeichenbehafteten Wert mit der Form [-] d.dddde [Vorzeichen] ddd, wobei d eine einzelne Dezimalstelle ist, dddd eine oder mehrere Dezimalstellen ist, ddd genau drei Dezimalstellen ist und das Vorzeichen + oder - ist.
% f Formatiert einen vorzeichenbehafteten Wert mit der Form [-] dddd.dddd, wobei dddd eine oder mehrere Dezimalstellen ist. Die Anzahl der Stellen vor dem Dezimalpunkt hängt von der Größe der Zahl ab, und die Anzahl der Stellen nach dem Dezimalpunkt hängt von der angeforderten Genauigkeit ab.
% g,% G. Formatiert einen signierten Wert, der im f- oder e-Format gedruckt wird, je nachdem, welcher Wert für den angegebenen Wert und die angegebene Genauigkeit kompakter ist.
% M. Formatiert einen Dezimalwert.
Formatiert jeden Wert, der gedruckt wird, indem das Objekt eingerahmt und verwendet wird ToString Methode.
% A,% + A. Formatiert einen beliebigen Wert, der mit den Standardlayouteinstellungen gedruckt wird. Verwenden Sie% + A, um die Struktur diskriminierter Gewerkschaften mit internen und privaten Vertretungen zu drucken.
%ein

Ein allgemeiner Formatbezeichner erfordert zwei Argumente. Das erste Argument ist eine Funktion, die zwei Argumente akzeptiert: erstens einen Kontextparameter des entsprechenden Typs für die angegebene Formatierungsfunktion (z. B. einen TextWriter) und zweitens einen zu druckenden Wert, der den entsprechenden Text entweder ausgibt oder zurückgibt.

Das zweite Argument ist der bestimmte Wert, der gedruckt werden soll.

% t Ein allgemeiner Formatbezeichner erfordert ein Argument: eine Funktion, die einen Kontextparameter des entsprechenden Typs für die angegebene Formatierungsfunktion (aTextWriter) akzeptiert und den entsprechenden Text entweder ausgibt oder zurückgibt. Grundlegende Ganzzahltypen sindbyte, sbyte, int16, uint16, int32, uint32, int64, uint64, nativeint, und unativeint. Grundlegende Gleitkommatypen sind float und float32.

Das widthist ein optionaler Parameter. Es ist eine Ganzzahl, die die minimale Breite des Ergebnisses angibt. Beispielsweise druckt% 5d eine Ganzzahl mit mindestens 5 Zeichen.

Gültig flags werden in der folgenden Tabelle beschrieben -

Wert Beschreibung
0 Gibt an, dass anstelle von Leerzeichen Nullen hinzugefügt werden sollen, um die erforderliche Breite zu erhalten.
- - Gibt an, dass das Ergebnis innerhalb der angegebenen Breite linksbündig ausgerichtet werden soll.
+ Gibt an, dass ein + -Zeichen hinzugefügt werden soll, wenn die Zahl positiv ist (um mit einem Vorzeichen für negative Zahlen übereinzustimmen).
' ' (Raum) Gibt an, dass ein zusätzliches Leerzeichen hinzugefügt werden soll, wenn die Zahl positiv ist (um mit einem Vorzeichen für negative Zahlen übereinzustimmen).
# Ungültig.

Beispiel

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Die Konsolenklasse

Diese Klasse ist Teil des .NET Frameworks. Es repräsentiert die Standardeingabe-, Ausgabe- und Fehlerströme für Konsolenanwendungen.

Es bietet verschiedene Methoden zum Lesen und Schreiben in die Konsole. Die folgende Tabelle zeigt die Methoden -

Methode Beschreibung
Piep() Spielt den Signalton über den Konsolenlautsprecher ab.
Piepton (Int32, Int32) Spielt den Ton eines Pieptons einer bestimmten Frequenz und Dauer über den Konsolenlautsprecher ab.
klar Löscht den Konsolenpuffer und das entsprechende Konsolenfenster mit Anzeigeinformationen.
MoveBufferArea (Int32, Int32, Int32, Int32, Int32, Int32) Kopiert einen angegebenen Quellbereich des Bildschirmpuffers in einen angegebenen Zielbereich.
MoveBufferArea (Int32, Int32, Int32, Int32, Int32, Int32, Char, ConsoleColor, ConsoleColor) Kopiert einen angegebenen Quellbereich des Bildschirmpuffers in einen angegebenen Zielbereich.
OpenStandardError () Erfasst den Standardfehlerstrom.
OpenStandardError (Int32) Ermittelt den Standardfehlerstrom, der auf eine angegebene Puffergröße festgelegt ist.
OpenStandardInput () Erfasst den Standardeingabestream.
OpenStandardInput (Int32) Erfasst den Standardeingabestream, der auf eine angegebene Puffergröße festgelegt ist.
OpenStandardOutput () Erfasst den Standardausgabestream.
OpenStandardOutput (Int32) Erfasst den Standardausgabestream, der auf eine angegebene Puffergröße festgelegt ist.
Lesen Liest das nächste Zeichen aus dem Standardeingabestream.
Schlüssel einlesen() Erhält das nächste vom Benutzer gedrückte Zeichen oder die nächste Funktionstaste. Die gedrückte Taste wird im Konsolenfenster angezeigt.
ReadKey (Boolean) Erhält das nächste vom Benutzer gedrückte Zeichen oder die nächste Funktionstaste. Die gedrückte Taste wird optional im Konsolenfenster angezeigt.
Zeile lesen Liest die nächste Zeichenzeile aus dem Standardeingabestream.
ResetColor Setzt die Farben der Vordergrund- und Hintergrundkonsole auf ihre Standardeinstellungen.
SetBufferSize Legt die Höhe und Breite des Bildschirmpufferbereichs auf die angegebenen Werte fest.
SetCursorPosition Legt die Position des Cursors fest.
SetError Legt die Error-Eigenschaft auf das angegebene TextWriter- Objekt fest.
SetIn Legt die In-Eigenschaft auf das angegebene TextReader- Objekt fest.
SetOut Legt die Out-Eigenschaft auf das angegebene TextWriter- Objekt fest.
SetWindowPosition Legt die Position des Konsolenfensters relativ zum Bildschirmpuffer fest.
SetWindowSize Legt die Höhe und Breite des Konsolenfensters auf die angegebenen Werte fest.
Schreiben (Boolescher Wert) Schreibt die Textdarstellung des angegebenen Booleschen Werts in den Standardausgabestream.
Schreiben Sie (Char) Schreibt den angegebenen Unicode-Zeichenwert in den Standardausgabestream.
Schreiben Sie (Char []) Schreibt das angegebene Array von Unicode-Zeichen in den Standardausgabestream.
Schreiben (dezimal) Schreibt die Textdarstellung des angegebenen Dezimalwerts in den Standardausgabestream.
Schreiben (doppelt) Schreibt die Textdarstellung des angegebenen Gleitkommawerts mit doppelter Genauigkeit in den Standardausgabestream.
Schreiben (Int32) Schreibt die Textdarstellung des angegebenen 32-Bit-Ganzzahlwerts mit Vorzeichen in den Standardausgabestream.
Schreiben (Int64) Schreibt die Textdarstellung des angegebenen 64-Bit-Ganzzahlwerts mit Vorzeichen in den Standardausgabestream.
Schreiben (Objekt) Schreibt die Textdarstellung des angegebenen Objekts in den Standardausgabestream.
Schreiben (Single) Schreibt die Textdarstellung des angegebenen Gleitkommawerts mit einfacher Genauigkeit in den Standardausgabestream.
Schreiben (String) Schreibt den angegebenen Zeichenfolgenwert in den Standardausgabestream.
Schreiben (UInt32) Schreibt die Textdarstellung des angegebenen 32-Bit-Ganzzahlwerts ohne Vorzeichen in den Standardausgabestream.
Schreiben (UInt64) Schreibt die Textdarstellung des angegebenen 64-Bit-Ganzzahlwerts ohne Vorzeichen in den Standardausgabestream.
Schreiben (String, Objekt) Schreibt die Textdarstellung des angegebenen Objekts unter Verwendung der angegebenen Formatinformationen in den Standardausgabestream.
Schreiben (String, Object []) Schreibt die Textdarstellung des angegebenen Array von Objekten unter Verwendung der angegebenen Formatinformationen in den Standardausgabestream.
Schreiben (Char [], Int32, Int32) Schreibt das angegebene Unterarray von Unicode-Zeichen in den Standardausgabestream.
Schreiben (String, Objekt, Objekt) Schreibt die Textdarstellung der angegebenen Objekte unter Verwendung der angegebenen Formatinformationen in den Standardausgabestream.
Schreiben (String, Objekt, Objekt, Objekt) Schreibt die Textdarstellung der angegebenen Objekte unter Verwendung der angegebenen Formatinformationen in den Standardausgabestream.
Schreiben (String, Objekt, Objekt, Objekt, Objekt) Schreibt die Textdarstellung der angegebenen Objekte und der Parameterliste mit variabler Länge unter Verwendung der angegebenen Formatinformationen in den Standardausgabestream.
WriteLine () Schreibt den aktuellen Zeilenabschluss in den Standardausgabestream.
WriteLine (Boolean) Schreibt die Textdarstellung des angegebenen Booleschen Werts, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (Char) Schreibt das angegebene Unicode-Zeichen, gefolgt vom aktuellen Zeilenabschlusswert, in den Standardausgabestream.
WriteLine (Char []) Schreibt das angegebene Array von Unicode-Zeichen, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (dezimal) Schreibt die Textdarstellung des angegebenen Dezimalwerts, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (Double) Schreibt die Textdarstellung des angegebenen Gleitkommawerts mit doppelter Genauigkeit, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (Int32) Schreibt die Textdarstellung des angegebenen 32-Bit-Ganzzahlwerts mit Vorzeichen, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (Int64) Schreibt die Textdarstellung des angegebenen 64-Bit-Ganzzahlwerts mit Vorzeichen, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (Objekt) Schreibt die Textdarstellung des angegebenen Objekts, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (Single) Schreibt die Textdarstellung des angegebenen Gleitkommawerts mit einfacher Genauigkeit, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (String) Schreibt den angegebenen Zeichenfolgenwert gefolgt vom aktuellen Zeilenabschluss in den Standardausgabestream.
WriteLine (UInt32) Schreibt die Textdarstellung des angegebenen 32-Bit-Ganzzahlwerts ohne Vorzeichen, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (UInt64) Schreibt die Textdarstellung des angegebenen 64-Bit-Ganzzahlwerts ohne Vorzeichen, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (String, Objekt) Schreibt die Textdarstellung des angegebenen Objekts, gefolgt vom aktuellen Zeilenabschluss, unter Verwendung der angegebenen Formatinformationen in den Standardausgabestream.
WriteLine (String, Object []) Schreibt die Textdarstellung des angegebenen Array von Objekten, gefolgt vom aktuellen Zeilenabschluss, unter Verwendung der angegebenen Formatinformationen in den Standardausgabestream.
WriteLine (Char [], Int32, Int32) Schreibt das angegebene Unterarray von Unicode-Zeichen, gefolgt vom aktuellen Zeilenabschluss, in den Standardausgabestream.
WriteLine (String, Objekt, Objekt) Schreibt die Textdarstellung der angegebenen Objekte, gefolgt vom aktuellen Zeilenabschluss, unter Verwendung der angegebenen Formatinformationen in den Standardausgabestream.
WriteLine (String, Objekt, Objekt, Objekt) Schreibt die Textdarstellung der angegebenen Objekte, gefolgt vom aktuellen Zeilenabschluss, unter Verwendung der angegebenen Formatinformationen in den Standardausgabestream.
WriteLine (String, Objekt, Objekt, Objekt, Objekt) Schreibt die Textdarstellung der angegebenen Objekte und der Parameterliste mit variabler Länge, gefolgt vom aktuellen Zeilenabschluss, unter Verwendung der angegebenen Formatinformationen in den Standardausgabestream.

Das folgende Beispiel zeigt das Lesen von der Konsole und das Schreiben in die Konsole.

Beispiel

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()

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Der System.IO-Namespace

Der System.IO-Namespace enthält eine Vielzahl nützlicher Klassen für die Ausführung grundlegender E / A.

Es enthält Typen oder Klassen, die das Lesen und Schreiben in Dateien und Datenströme ermöglichen, sowie Typen, die grundlegende Unterstützung für Dateien und Verzeichnisse bieten.

Klassen, die für die Arbeit mit dem Dateisystem nützlich sind -

  • Die System.IO.File-Klasse wird zum Erstellen, Anhängen und Löschen von Dateien verwendet.
  • Die System.IO.Directory-Klasse wird zum Erstellen, Verschieben und Löschen von Verzeichnissen verwendet.
  • Die System.IO.Path-Klasse führt Operationen an Zeichenfolgen aus, die Dateipfade darstellen.
  • Mit der System.IO.FileSystemWatcher-Klasse können Benutzer ein Verzeichnis auf Änderungen überwachen.

Klassen, die für die Arbeit mit den Streams nützlich sind (Folge von Bytes) -

  • Die System.IO.StreamReader-Klasse wird zum Lesen von Zeichen aus einem Stream verwendet.
  • Die System.IO.StreamWriter-Klasse wird zum Schreiben von Zeichen in einen Stream verwendet.
  • Die System.IO.MemoryStream-Klasse erstellt einen speicherinternen Bytestrom.

Die folgende Tabelle zeigt alle im Namespace bereitgestellten Klassen zusammen mit einer kurzen Beschreibung -

Klasse Beschreibung
BinaryReader Liest primitive Datentypen als Binärwerte in einer bestimmten Codierung.
BinaryWriter Schreibt primitive Typen in Binärform in einen Stream und unterstützt das Schreiben von Zeichenfolgen in einer bestimmten Codierung.
BufferedStream Fügt eine Pufferschicht zum Lesen und Schreiben von Operationen in einem anderen Stream hinzu.
Verzeichnis Zeigt statische Methoden zum Erstellen, Verschieben und Auflisten in Verzeichnissen und Unterverzeichnissen an.
DirectoryInfo Macht Instanzmethoden zum Erstellen, Verschieben und Auflisten durch Verzeichnisse und Unterverzeichnisse verfügbar.
DirectoryNotFoundException Die Ausnahme, die ausgelöst wird, wenn ein Teil einer Datei oder eines Verzeichnisses nicht gefunden werden kann.
DriveInfo Bietet Zugriff auf Informationen auf einem Laufwerk.
DriveNotFoundException Die Ausnahme, die ausgelöst wird, wenn versucht wird, auf ein Laufwerk oder eine Freigabe zuzugreifen, die nicht verfügbar ist.
EndOfStreamException Die Ausnahme, die beim Lesen ausgelöst wird, wird nach dem Ende eines Streams versucht.
ErrorEventArgs Stellt Daten für das FileSystemWatcher.Error-Ereignis bereit.
Datei Bietet statische Methoden zum Erstellen, Kopieren, Löschen, Verschieben und Öffnen einer einzelnen Datei und hilft beim Erstellen von FileStream-Objekten.
FileFormatException Die Ausnahme, die ausgelöst wird, wenn eine Eingabedatei oder ein Datenstrom, der einer bestimmten Dateiformatspezifikation entsprechen soll, fehlerhaft ist.
Dateiinformation Bietet Eigenschaften und Instanzmethoden zum Erstellen, Kopieren, Löschen, Verschieben und Öffnen von Dateien und hilft beim Erstellen von FileStream-Objekten.
FileLoadException Die Ausnahme, die ausgelöst wird, wenn eine verwaltete Assembly gefunden, aber nicht geladen werden kann.
FileNotFoundException Die Ausnahme, die ausgelöst wird, wenn ein Versuch, auf eine Datei zuzugreifen, die nicht auf der Festplatte vorhanden ist, fehlschlägt.
Datenfluss Macht einen Stream um eine Datei verfügbar und unterstützt sowohl synchrone als auch asynchrone Lese- und Schreibvorgänge.
FileSystemEventArgs Stellt Daten für die Verzeichnisereignisse bereit - Geändert, Erstellt, Gelöscht.
FileSystemInfo Stellt die Basisklasse für FileInfo- und DirectoryInfo-Objekte bereit.
FileSystemWatcher Hört die Änderungsbenachrichtigungen des Dateisystems ab und löst Ereignisse aus, wenn sich ein Verzeichnis oder eine Datei in einem Verzeichnis ändert.
InternalBufferOverflowException Die Ausnahme, die ausgelöst wird, wenn der interne Puffer überläuft.
InvalidDataException Die Ausnahme, die ausgelöst wird, wenn ein Datenstrom in einem ungültigen Format vorliegt.
IODescriptionAttribute Legt die Beschreibung fest, die visuelle Designer anzeigen können, wenn sie auf ein Ereignis, einen Extender oder eine Eigenschaft verweisen.
IOException Die Ausnahme, die ausgelöst wird, wenn ein E / A-Fehler auftritt.
MemoryStream Erstellt einen Stream, dessen Hintergrundspeicher Speicher ist.
Pfad Führt Operationen an Zeichenfolgeninstanzen aus, die Datei- oder Verzeichnispfadinformationen enthalten. Diese Vorgänge werden plattformübergreifend ausgeführt.
PathTooLongException Die Ausnahme, die ausgelöst wird, wenn ein Pfad oder Dateiname länger als die vom System definierte maximale Länge ist.
PipeException Wird ausgelöst, wenn ein Fehler in einer Named Pipe auftritt.
Umbenannt in EventArgs Stellt Daten für das umbenannte Ereignis bereit.
Strom Bietet eine allgemeine Ansicht einer Folge von Bytes. Dies ist eine abstrakte Klasse.
StreamReader Implementiert einen TextReader, der Zeichen aus einem Bytestream in einer bestimmten Codierung liest.
StreamWriter Implementiert einen TextWriter zum Schreiben von Zeichen in einen Stream in einer bestimmten Codierung. Informationen zum Durchsuchen des .NET Framework-Quellcodes nach diesem Typ finden Sie in der Referenzquelle.
StringReader Implementiert einen TextReader, der aus einer Zeichenfolge liest.
StringWriter Implementiert einen TextWriter zum Schreiben von Informationen in eine Zeichenfolge. Die Informationen werden in einem zugrunde liegenden StringBuilder gespeichert.
TextReader Stellt einen Leser dar, der eine fortlaufende Reihe von Zeichen lesen kann.
TextWriter Stellt einen Schreiber dar, der eine sequentielle Reihe von Zeichen schreiben kann. Diese Klasse ist abstrakt.
UnmanagedMemoryAccessor Bietet zufälligen Zugriff auf nicht verwaltete Speicherblöcke aus verwaltetem Code.
UnmanagedMemoryStream Bietet Zugriff auf nicht verwaltete Speicherblöcke aus verwaltetem Code.
WindowsRuntimeStorageExtensions Enthält Erweiterungsmethoden für die Schnittstellen IStorageFile und IStorageFolder in der Windows Runtime bei der Entwicklung von Windows Store-Apps.
WindowsRuntimeStreamExtensions Enthält Erweiterungsmethoden zum Konvertieren zwischen Streams in Windows Runtime und verwalteten Streams in .NET für Windows Store-Apps.

Beispiel

Im folgenden Beispiel wird eine Datei mit dem Namen test.txt erstellt, dort eine Nachricht geschrieben, der Text aus der Datei gelesen und auf der Konsole gedruckt.

Note - Die Menge an Code, die dazu benötigt wird, ist überraschend geringer!

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Hello There
Welcome to:
Tutorials Point

Mit Generics können Sie die Angabe des Datentyps von Programmierelementen in einer Klasse oder Methode verzögern, bis er tatsächlich im Programm verwendet wird. Mit anderen Worten, mit Generika können Sie eine Klasse oder Methode schreiben, die mit jedem Datentyp arbeiten kann.

Sie schreiben die Spezifikationen für die Klasse oder die Methode mit Ersatzparametern für Datentypen. Wenn der Compiler auf einen Konstruktor für die Klasse oder einen Funktionsaufruf für die Methode stößt, generiert er Code für den spezifischen Datentyp.

In F # können Funktionswerte, Methoden, Eigenschaften und Aggregattypen wie Klassen, Datensätze und diskriminierte Vereinigungen generisch sein.

Generische Konstrukte enthalten mindestens einen Typparameter. Mit generischen Funktionen und Typen können Sie Code schreiben, der mit einer Vielzahl von Typen funktioniert, ohne den Code für jeden Typ zu wiederholen.

Syntax

Die Syntax zum Schreiben eines generischen Konstrukts lautet wie folgt:

// 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

Beispiele

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

printFunc<float> 10.0 20.0

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

10.0, 20.0

Sie können eine Funktion auch generisch erstellen, indem Sie die einfache Anführungszeichen-Syntax verwenden.

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

printFunction 10.0 20.0

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

10.0 20.0

Beachten Sie, dass Sie bei Verwendung generischer Funktionen oder Methoden möglicherweise keine Typargumente angeben müssen. Im Falle einer Mehrdeutigkeit können Sie jedoch Typargumente in spitzen Klammern angeben, wie im ersten Beispiel.

Wenn Sie mehr als einen Typ haben, trennen Sie mehrere Typargumente durch Kommas.

Generische Klasse

Wie generische Funktionen können Sie auch generische Klassen schreiben. Das folgende Beispiel zeigt dies -

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) } )

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Ein Delegat ist eine Referenztypvariable, die den Verweis auf eine Methode enthält. Die Referenz kann zur Laufzeit geändert werden. F # -Delegierte ähneln Zeigern auf Funktionen in C oder C ++.

Delegierte erklären

Die Delegatendeklaration bestimmt die Methoden, auf die der Delegat verweisen kann. Ein Delegat kann auf eine Methode verweisen, die dieselbe Signatur wie die des Delegaten hat.

Die Syntax für die Delegatendeklaration lautet -

type delegate-typename = delegate of type1 -> type2

Betrachten Sie zum Beispiel die Delegierten -

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

Sowohl die Delegierten können verwendet werden , um eine Methode zu verweisen , die zwei hat int Parameter und gibt einen int Typ Variable.

In der Syntax -

  • type1 repräsentiert den / die Argumenttyp (e).

  • type2 repräsentiert den Rückgabetyp.

Bitte beachten Sie -

  • Die Argumenttypen werden automatisch überprüft.

  • Delegaten können an Funktionswerte sowie statische oder Instanzmethoden angehängt werden.

  • F # -Funktionswerte können direkt als Argumente an delegierte Konstruktoren übergeben werden.

  • Bei einer statischen Methode wird der Delegat unter Verwendung des Namens der Klasse und der Methode aufgerufen. Für eine Instanzmethode wird der Name der Objektinstanz und -methode verwendet.

  • Die Invoke-Methode für den Delegatentyp ruft die gekapselte Funktion auf.

  • Delegaten können auch als Funktionswerte übergeben werden, indem auf den Namen der Invoke-Methode ohne Klammern verwiesen wird.

Das folgende Beispiel zeigt das Konzept -

Beispiel

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)

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Eine Aufzählung ist eine Menge benannter Ganzzahlkonstanten.

In F #, enumerations, auch bekannt als enums,sind ganzzahlige Typen, bei denen einer Teilmenge der Werte Beschriftungen zugewiesen werden. Sie können sie anstelle von Literalen verwenden, um den Code lesbarer und wartbarer zu machen.

Aufzählungen deklarieren

Die allgemeine Syntax zum Deklarieren einer Aufzählung lautet -

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

Das folgende Beispiel zeigt die Verwendung von Aufzählungen -

Beispiel

// 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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Monday: Mon
Saturday: Sat
Sunday: Sun

Mit dem Mustervergleich können Sie „Daten mit einer oder mehreren logischen Strukturen vergleichen, Daten in Bestandteile zerlegen oder Informationen auf verschiedene Weise aus Daten extrahieren“.

Mit anderen Worten, es bietet eine flexiblere und leistungsfähigere Möglichkeit, Daten anhand einer Reihe von Bedingungen zu testen und einige Berechnungen basierend auf der erfüllten Bedingung durchzuführen.

Konzeptionell ist es wie eine Reihe von if… then-Aussagen.

Syntax

Auf hoher Ebene folgt der Pattern Matching dieser Syntax in F # -

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

Wo,

  • Jeder | Symbol definiert eine Bedingung.
  • Das Symbol -> bedeutet "Wenn die Bedingung erfüllt ist, geben Sie diesen Wert zurück ...".
  • Das _-Symbol stellt das Standardmuster bereit, was bedeutet, dass es mit allen anderen Dingen wie einem Platzhalter übereinstimmt.

Beispiel 1

Im folgenden Beispiel werden die Fibonacci-Zahlen mithilfe der Mustervergleichssyntax berechnet.

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)

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Sie können auch mehrere Bedingungen miteinander verketten, die denselben Wert zurückgeben. Zum Beispiel -

Beispiel 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"

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Winter
Spring
Autumn
Rainy

Pattern Matching-Funktionen

Mit F # können Sie Mustervergleichsfunktionen mit der Taste schreiben function Schlüsselwort -

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")

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

10
20.5
21
8.75
15

Hinzufügen von Filtern oder Schutzvorrichtungen zu Mustern

Sie können Muster oder Schutzvorrichtungen zu Mustern hinzufügen, indem Sie das verwenden when Stichwort.

Beispiel 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)

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

-1
1
0

Beispiel 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)

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Musterübereinstimmung mit Tupeln

Das folgende Beispiel zeigt den Mustervergleich mit Tupeln -

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"))

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Musterabgleich mit Datensätzen

Das folgende Beispiel zeigt den Mustervergleich mit Datensätzen -

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 }

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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).

Eine Ausnahme ist ein Problem, das während der Ausführung eines Programms auftritt. Eine F # -Ausnahme ist eine Reaktion auf einen außergewöhnlichen Umstand, der während der Ausführung eines Programms auftritt, z. B. den Versuch, durch Null zu teilen.

Ausnahmen bieten eine Möglichkeit, die Kontrolle von einem Teil eines Programms auf einen anderen zu übertragen. Die Behandlung von F # -Ausnahmen bietet die folgenden Konstrukte:

Bauen Beschreibung
erhöhen expr Löst die angegebene Ausnahme aus.
scheitern mit expr Erhöht die System.Exception Ausnahme.
versuche es mit Regeln Fängt Ausdrücke ab, die den Musterregeln entsprechen.
versuchen Sie es endlich mit Ausdruck Ausführung der finally Ausdruck sowohl bei erfolgreicher Berechnung als auch bei Auslösung einer Ausnahme.
| :? ArgumentException Eine Regel, die dem angegebenen .NET-Ausnahmetyp entspricht.
| :? ArgumentException als e Eine Regel, die dem angegebenen .NET-Ausnahmetyp entspricht und den Namen bindet e auf den Ausnahmeobjektwert.
| Fehler (msg) → Ausdruck Eine Regel, die mit der angegebenen datenführenden F # -Ausnahme übereinstimmt.
| exn → expr Eine Regel, die mit einer Ausnahme übereinstimmt und den Namen bindet exn auf den Ausnahmeobjektwert.
| exn wenn expr → expr Eine Regel, die unter der angegebenen Bedingung mit der Ausnahme übereinstimmt und den Namen bindet exn auf den Ausnahmeobjektwert.

Beginnen wir mit der grundlegenden Syntax der Ausnahmebehandlung.

Syntax

Die grundlegende Syntax für den F # -Ausnahmebehandlungsblock lautet -

exception exception-type of argument-type

Wo,

  • exception-type ist der Name eines neuen F # -Ausnahmetyps.

  • argument-type stellt den Typ eines Arguments dar, das angegeben werden kann, wenn Sie eine Ausnahme dieses Typs auslösen.

  • Mithilfe eines Tupeltyps für den Argumenttyp können mehrere Argumente angegeben werden.

Das try...with Ausdruck wird für die Ausnahmebehandlung in der Sprache F # verwendet.

Syntax für den Versuch… mit Ausdruck ist -

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

Das try...finally Mit expression können Sie Bereinigungscode ausführen, auch wenn ein Codeblock eine Ausnahme auslöst.

Syntax für den Versuch ... endlich ist der Ausdruck -

try
   expression1
finally
   expression2

Das raiseDie Funktion zeigt an, dass ein Fehler oder eine Ausnahmebedingung aufgetreten ist. Außerdem werden die Informationen zum Fehler in einem Ausnahmeobjekt erfasst.

Die Syntax für die Raise-Funktion lautet -

raise (expression)

Das failwith Funktion erzeugt eine F # -Ausnahme.

Die Syntax für die Failwith-Funktion lautet -

failwith error-message-string

Das invalidArg Funktion generiert eine Argumentausnahme.

invalidArg parameter-name error-message-string

Beispiel für die Ausnahmebehandlung

Beispiel 1

Das folgende Programm zeigt die grundlegende Ausnahmebehandlung mit einem einfachen Versuch… mit Block -

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

let result1 = divisionprog 100 0

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Division by zero!

Beispiel 2

F # bietet eine exceptionTyp zum Deklarieren von Ausnahmen. Sie können einen Ausnahmetyp direkt in den Filtern in a verwendentry...with Ausdruck.

Das folgende Beispiel zeigt dies -

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Error2 Error Not detected 100
Error1 Equal Number Error

Beispiel 3

Das folgende Beispiel zeigt die Behandlung verschachtelter Ausnahmen -

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Beispiel 4

Die folgende Funktion demonstriert die failwith Funktion -

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Divisor cannot be zero.
0
25

Beispiel 5

Das invalidArgFunktion generiert eine Argumentausnahme. Das folgende Programm demonstriert dies -

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)

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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

Abhängig vom System werden auch einige andere Informationen zu der Datei und der Variablen angezeigt, die Fehler im System verursachen.

Klassen sind Typen, die Objekte darstellen, die Eigenschaften, Methoden und Ereignisse haben können. "Sie werden verwendet, um Aktionen, Prozesse und konzeptionelle Entitäten in Anwendungen zu modellieren."

Syntax

Die Syntax zum Definieren eines Klassentyps lautet wie folgt:

// 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 ...
...

Wo,

  • Das type-nameist eine gültige Kennung. Der Standardzugriffsmodifikator hierfür istpublic.

  • Das type-params beschreibt optionale generische Typparameter.

  • Das parameter-listbeschreibt Konstruktorparameter. Der Standardzugriffsmodifikator für den Primärkonstruktor istpublic.

  • Das identifier verwendet mit dem optionalen as Das Schlüsselwort gibt der Instanzvariablen einen Namen oder self-identifier, Dies kann in der Typdefinition verwendet werden, um auf die Instanz des Typs zu verweisen.

  • Das inherit Mit dem Schlüsselwort können Sie die Basisklasse für eine Klasse angeben.

  • Das let Mit Bindungen können Sie Felder oder Funktionswerte lokal für die Klasse deklarieren.

  • Das do-bindings Der Abschnitt enthält Code, der bei der Objektkonstruktion ausgeführt werden soll.

  • Das member-list besteht aus zusätzlichen Konstruktoren, Instanz- und statischen Methodendeklarationen, Schnittstellendeklarationen, abstrakten Bindungen sowie Eigenschafts- und Ereignisdeklarationen.

  • Die Schlüsselwörter class und end Diese Markierungen für den Beginn und das Ende der Definition sind optional.

Konstruktor einer Klasse

Der Konstruktor ist Code, der eine Instanz des Klassentyps erstellt.

In F # arbeiten Konstruktoren kaum anders als andere .NET-Sprachen. In der Klassendefinition werden die Argumente des Primärkonstruktors als Parameterliste beschrieben.

Der Körper des Konstruktors besteht aus dem let und do Bindungen.

Sie können zusätzliche Konstruktoren hinzufügen, indem Sie das neue Schlüsselwort verwenden, um ein Mitglied hinzuzufügen.

new (argument-list) = constructor-body

Das folgende Beispiel veranschaulicht das Konzept -

Beispiel

Das folgende Programm erstellt eine Linienklasse zusammen mit einem Konstruktor, der die Länge der Linie berechnet, während ein Objekt der Klasse erstellt wird.

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)

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Creating Line: {(1, 1), (4, 5)}
Length: 5

Bindungen binden lassen

Mit den Let-Bindungen in einer Klassendefinition können Sie private Felder und private Funktionen für F # -Klassen definieren.

type Greetings(name) as gr =
   let data = name
   do
      gr.PrintMessage()
   member this.PrintMessage() =
      printf "Hello %s\n" data
let gtr = new Greetings("Zara")

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Hello Zara

Bitte beachten Sie die Verwendung der Selbstkennung gr für die Greetings- Klasse.

Eine Struktur in F # ist ein Datentyp vom Werttyp. Es hilft Ihnen, eine einzelne Variable zu erstellen und verwandte Daten verschiedener Datentypen zu speichern. Dasstruct Das Schlüsselwort wird zum Erstellen einer Struktur verwendet.

Syntax

Die Syntax zum Definieren einer Struktur lautet wie folgt:

[ attributes ]
type [accessibility-modifier] type-name =
   struct
      type-definition-elements
   end
// or
[ attributes ]
[<StructAttribute>]
type [accessibility-modifier] type-name =
   type-definition-elements

Es gibt zwei Syntaxen. Die erste Syntax wird meistens verwendet, denn wenn Sie die verwendenstruct und end Schlüsselwörter können Sie weglassen StructAttribute Attribut.

Die Strukturdefinitionselemente bieten -

  • Erklärungen und Definitionen der Mitglieder.
  • Konstruktoren und veränderbare und unveränderliche Felder.
  • Mitglieder und Schnittstellenimplementierungen.

Im Gegensatz zu Klassen können Strukturen nicht vererbt werden und keine let- oder do-Bindungen enthalten. Da Strukturen keine Bindungen gelassen haben; Sie müssen Felder in Strukturen mit dem deklarierenval Stichwort.

Wenn Sie ein Feld und seinen Typ mit definieren valSchlüsselwort, Sie können den Feldwert nicht initialisieren, stattdessen werden sie auf Null oder Null initialisiert. Für eine Struktur mit einem impliziten Konstruktor ist dieval Erklärungen sind mit dem zu kommentieren DefaultValue Attribut.

Beispiel

Das folgende Programm erstellt eine Linienstruktur zusammen mit einem Konstruktor. Das Programm berechnet die Länge einer Linie anhand der Struktur -

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Length of the Line: 5

Sie können die meisten in F # verfügbaren integrierten Operatoren neu definieren oder überladen. Somit kann ein Programmierer auch Operatoren mit benutzerdefinierten Typen verwenden.

Operatoren sind Funktionen mit speziellen Namen, die in Klammern eingeschlossen sind. Sie müssen als statische Klassenmitglieder definiert werden. Wie jede andere Funktion verfügt ein überladener Operator über einen Rückgabetyp und eine Parameterliste.

Das folgende Beispiel zeigt einen + -Operator für komplexe Zahlen -

//overloading + operator
static member (+) (a : Complex, b: Complex) =
Complex(a.x + b.x, a.y + b.y)

Die obige Funktion implementiert den Additionsoperator (+) für eine benutzerdefinierte Klasse Complex. Es fügt die Attribute von zwei Objekten hinzu und gibt das resultierende komplexe Objekt zurück.

Implementierung der Operatorüberladung

Das folgende Programm zeigt die vollständige Implementierung -

//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())

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

7 5
4.2 3.1
11.2 8.1
2.8 1.9

Eines der wichtigsten Konzepte in der objektorientierten Programmierung ist das der Vererbung. Durch Vererbung können wir eine Klasse in Bezug auf eine andere Klasse definieren, was das Erstellen und Verwalten einer Anwendung erleichtert. Dies bietet auch die Möglichkeit, die Codefunktionalität und die schnelle Implementierungszeit wiederzuverwenden.

Beim Erstellen einer Klasse kann der Programmierer festlegen, dass die neue Klasse die Mitglieder einer vorhandenen Klasse erben soll, anstatt vollständig neue Datenelemente und Elementfunktionen zu schreiben. Diese vorhandene Klasse wird als Basisklasse bezeichnet, und die neue Klasse wird als abgeleitete Klasse bezeichnet.

Die Idee der Vererbung implementiert die IS-A-Beziehung. Zum Beispiel ist Säugetier IS A-Tier, Hund IS-A-Säugetier, daher auch Hund IS-A-Tier und so weiter.

Basisklasse und Unterklasse

Eine Unterklasse wird von einer bereits definierten Basisklasse abgeleitet. Eine Unterklasse erbt die Mitglieder der Basisklasse und hat ihre eigenen Mitglieder.

Eine Unterklasse wird mit dem definiert inherit Schlüsselwort wie unten gezeigt -

type MyDerived(...) =
   inherit MyBase(...)

In F # kann eine Klasse höchstens eine direkte Basisklasse haben. Wenn Sie keine Basisklasse angeben, verwenden Sie dieinherit Schlüsselwort, erbt die Klasse implizit von Object.

Bitte beachten Sie -

  • Die Methoden und Mitglieder der Basisklasse stehen Benutzern der abgeleiteten Klasse wie den direkten Mitgliedern der abgeleiteten Klasse zur Verfügung.

  • Lassen Sie Bindungen und Konstruktorparameter für eine Klasse privat sein und können daher nicht von abgeleiteten Klassen aus zugegriffen werden.

  • Das Schlüsselwort basebezieht sich auf die Basisklasseninstanz. Es wird wie die Selbstkennung verwendet.

Beispiel

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()

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Hi, I'm Mohan
Hi, I'm Zara
Hi, I'm Mariam

Methoden überschreiben

Sie können ein Standardverhalten einer Basisklassenmethode überschreiben und in der Unterklasse oder der abgeleiteten Klasse anders implementieren.

Methoden in F # können standardmäßig nicht überschrieben werden.

Um Methoden in einer abgeleiteten Klasse zu überschreiben, müssen Sie Ihre Methode mit der Option als überschreibbar deklarieren abstract und default Schlüsselwörter wie folgt -

type Person(name) =
   member x.Name = name
   abstract Greet : unit -> unit
   default x.Greet() = printfn "Hi, I'm %s" x.Name

Jetzt kann die Greet- Methode der Person-Klasse in abgeleiteten Klassen überschrieben werden. Das folgende Beispiel zeigt dies -

Beispiel

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()

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Hi, I'm Mohan
Student Zara
Teacher Mariam.

Abstrakte Klasse

Manchmal müssen Sie eine unvollständige Implementierung eines Objekts bereitstellen, die in der Realität nicht implementiert werden sollte. Später sollte ein anderer Programmierer Unterklassen der abstrakten Klasse für eine vollständige Implementierung erstellen.

Beispielsweise wird die Personenklasse in einem Schulverwaltungssystem nicht benötigt. Es wird jedoch die Schüler- oder Lehrerklasse benötigt. In solchen Fällen können Sie die Person-Klasse als abstrakte Klasse deklarieren.

Das AbstractClass Das Attribut teilt dem Compiler mit, dass die Klasse einige abstrakte Mitglieder hat.

Sie können keine Instanz einer abstrakten Klasse erstellen, da die Klasse nicht vollständig implementiert ist.

Das folgende Beispiel zeigt dies -

Beispiel

[<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()

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Student Zara
Teacher Mariam.

Schnittstellen bieten eine abstrakte Möglichkeit, die Implementierungsdetails einer Klasse aufzuschreiben. Es ist eine Vorlage, die die Methoden deklariert, die die Klasse implementieren und öffentlich verfügbar machen muss.

Syntax

Eine Schnittstelle gibt die Gruppen verwandter Mitglieder an, die andere Klassen implementieren. Es hat die folgende Syntax -

// 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

Bitte beachten Sie -

  • In einer Schnittstellendeklaration sind die Mitglieder nicht implementiert.

  • Die Mitglieder sind abstrakt, deklariert von der abstractStichwort. Sie können jedoch eine Standardimplementierung mithilfe von bereitstellendefault Stichwort.

  • Sie können Schnittstellen entweder mithilfe von Objektausdrücken oder mithilfe von Klassentypen implementieren.

  • Bei der Klassen- oder Objektimplementierung müssen Sie Methodenkörper für abstrakte Methoden der Schnittstelle bereitstellen.

  • Die Schlüsselwörter interface und end, welche den Anfang und das Ende der Definition markieren, sind optional.

Zum Beispiel,

type IPerson =
   abstract Name : string
   abstract Enter : unit -> unit
   abstract Leave : unit -> unit

Aufrufen von Schnittstellenmethoden

Schnittstellenmethoden werden über die Schnittstelle aufgerufen, nicht über die Instanz der Klasse oder des Typs, der die Schnittstelle implementiert. Um eine Schnittstellenmethode aufzurufen, können Sie mithilfe von:> Operator (Upcast-Operator).

Zum Beispiel,

(s :> IPerson).Enter()
(s :> IPerson).Leave()

Das folgende Beispiel veranschaulicht das Konzept -

Beispiel

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()

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Student entering premises!
Student leaving premises!
Stuff member entering premises!
Stuff member leaving premises!

Vererbung der Schnittstelle

Schnittstellen können von einer oder mehreren Basisschnittstellen erben.

Das folgende Beispiel zeigt das Konzept -

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))

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

10
15
5

Mit Ereignissen können Klassen Nachrichten untereinander senden und empfangen.

In der GUI sind Ereignisse Benutzeraktionen wie Tastendruck, Klicks, Mausbewegungen usw. oder ein Ereignis wie vom System generierte Benachrichtigungen. Anwendungen müssen auf Ereignisse reagieren, wenn sie auftreten. Zum Beispiel Interrupts. Ereignisse werden für die Kommunikation zwischen Prozessen verwendet.

Objekte kommunizieren durch synchrones Weiterleiten von Nachrichten miteinander.

Ereignisse sind mit anderen Funktionen verbunden. Objekte registrierencallback Funktionen für ein Ereignis, und diese Rückrufe werden ausgeführt, wenn (und wenn) das Ereignis von einem Objekt ausgelöst wird.

Die Ereignisklasse und das Ereignismodul

Die Control.Event <'T> -Klasse hilft beim Erstellen eines beobachtbaren Objekts oder Ereignisses.

Es hat die folgenden Instanzmitglieder, um mit den Ereignissen zu arbeiten -

Mitglied Beschreibung
Veröffentlichen Veröffentlicht eine Beobachtung als erstklassigen Wert.
Auslösen Löst eine Beobachtung mit den angegebenen Parametern aus.

Das Control.Event-Modul bietet Funktionen zum Verwalten von Ereignisströmen -

Wert Beschreibung
hinzufügen: ('T → Einheit) → Ereignis <' Entf, 'T> → Einheit Führt die angegebene Funktion jedes Mal aus, wenn das angegebene Ereignis ausgelöst wird.
Wählen Sie: (Option 'T →' U) → IEvent <'Del,' T> → IEvent <'U> Gibt ein neues Ereignis zurück, das bei einer Auswahl von Nachrichten aus dem ursprünglichen Ereignis ausgelöst wird. Die Auswahlfunktion wandelt eine ursprüngliche Nachricht in eine optionale neue Nachricht um.
Filter: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> Gibt ein neues Ereignis zurück, das das ursprüngliche Ereignis abhört und das resultierende Ereignis nur auslöst, wenn das Argument für das Ereignis die angegebene Funktion übergibt.
Karte: ('T →' U) → IEvent <'Del,' T> → IEvent <'U> Gibt ein neues Ereignis zurück, das von der angegebenen Funktion transformierte Werte übergibt.
Zusammenführen: IEvent <'Del1,' T> → IEvent <'Del2,' T> → IEvent <'T> Löst das Ausgabeereignis aus, wenn eines der Eingabeereignisse ausgelöst wird.
paarweise: IEvent <'Del,' T> → IEvent <'T *' T> Gibt ein neues Ereignis zurück, das beim zweiten und nachfolgenden Auslösen des Eingabeereignisses ausgelöst wird. DasNth Das Auslösen des Eingabeereignisses übergibt die Argumente aus dem N-1th und Nthals Paar auslösen. Das Argument ging an dieN-1th Die Auslösung wird bis zum Nth Auslösung erfolgt.
Partition: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> * IEvent <'T> Gibt ein neues Ereignis zurück, das das ursprüngliche Ereignis abhört und das erste resultierende Ereignis auslöst, wenn die Anwendung des Prädikats auf die Ereignisargumente true zurückgibt, und das zweite Ereignis, wenn es false zurückgibt.
Scan: ('U →' T → 'U) →' U → IEvent <'Del,' T> → IEvent <'U> Gibt ein neues Ereignis zurück, das aus den Ergebnissen der Anwendung der angegebenen Akkumulationsfunktion auf aufeinanderfolgende Werte besteht, die für das Eingabeereignis ausgelöst wurden. Ein Element des internen Status zeichnet den aktuellen Wert des Statusparameters auf. Der interne Status ist während der Ausführung der Akkumulationsfunktion nicht gesperrt. Daher sollte darauf geachtet werden, dass das Eingabe-IEvent nicht von mehreren Threads gleichzeitig ausgelöst wird.
Aufteilung: ('T → Auswahl <' U1, 'U2>) → IEvent <' Entf, 'T> → IEvent <' U1> * IEvent <'U2> Gibt ein neues Ereignis zurück, das das ursprüngliche Ereignis abhört und das erste resultierende Ereignis auslöst, wenn die Anwendung der Funktion auf die Ereignisargumente ein Choice1Of2 zurückgibt, und das zweite Ereignis, wenn es ein Choice2Of2 zurückgibt.

Ereignisse erstellen

Ereignisse werden über das erstellt und verwendet EventKlasse. Der Ereigniskonstruktor wird zum Erstellen eines Ereignisses verwendet.

Beispiel

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

Danach müssen Sie das Feld nameChanged als öffentliches Mitglied verfügbar machen, damit die Listener sich an das Ereignis anschließen können, für das Sie das verwenden Publish Eigentum der Veranstaltung -

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 *)

Als Nächstes fügen Sie Ereignishandlern Rückrufe hinzu. Jeder Ereignishandler hat den Typ IEvent <'T>, der verschiedene Methoden bereitstellt -

Methode Beschreibung
val Add: event :( 'T → unit) → unit Verbindet eine Listener-Funktion mit dem Ereignis. Der Listener wird aufgerufen, wenn das Ereignis ausgelöst wird.
val AddHandler: 'del → unit Verbindet ein Handler-Delegatenobjekt mit dem Ereignis. Ein Handler kann später mit RemoveHandler entfernt werden. Der Listener wird aufgerufen, wenn das Ereignis ausgelöst wird.
val RemoveHandler: 'del → unit Entfernt einen Listener-Delegaten aus einem Ereignis-Listener-Speicher.

Der folgende Abschnitt enthält ein vollständiges Beispiel.

Beispiel

Das folgende Beispiel zeigt das oben diskutierte Konzept und die Techniken -

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"

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

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!

Gemäß der MSDN-Bibliothek ist ein F # -Modul eine Gruppierung von F # -Codekonstrukten wie Typen, Werten, Funktionswerten und Code in do-Bindungen. Es wird als CLR-Klasse (Common Language Runtime) implementiert, die nur statische Elemente enthält.

Abhängig von der Situation, ob die gesamte Datei im Modul enthalten ist, gibt es zwei Arten von Moduldeklarationen:

  • Moduldeklaration der obersten Ebene
  • Lokale Moduldeklaration

In einer Moduldeklaration der obersten Ebene ist die gesamte Datei im Modul enthalten. In diesem Fall ist die erste Deklaration in der Datei die Moduldeklaration. Sie müssen Deklarationen in einem Modul der obersten Ebene nicht einrücken.

In einer lokalen Moduldeklaration sind nur die Deklarationen, die unter dieser Moduldeklaration eingerückt sind, Teil des Moduls.

Syntax

Die Syntax für die Moduldeklaration lautet wie folgt:

// Top-level module declaration.
module [accessibility-modifier] [qualified-namespace.]module-name
   declarations
// Local module declaration.
module [accessibility-modifier] module-name =
   declarations

Bitte beachten Sie, dass der Eingabehilfen-Modifikator einer der folgenden sein kann - öffentlich, privat, intern. Der Standardwert istpublic.

Die folgenden Beispiele veranschaulichen die Konzepte -

Beispiel 1

Die Moduldatei 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

Die Programmdatei 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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

34
16
225
2
110
90
1000
10

Beispiel 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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

125
325

EIN namespacewurde entwickelt, um eine Möglichkeit zu bieten, einen Satz von Namen von einem anderen zu trennen. Die in einem Namespace deklarierten Klassennamen stehen nicht in Konflikt mit denselben in einem anderen deklarierten Klassennamen.

Gemäß der MSDN-Bibliothek a namespace Mit dieser Option können Sie Code in Bereiche verwandter Funktionen organisieren, indem Sie einer Gruppe von Programmelementen einen Namen hinzufügen.

Namespace deklarieren

Um Ihren Code in einem Namespace zu organisieren, müssen Sie den Namespace als erste Deklaration in der Datei deklarieren. Der Inhalt der gesamten Datei wird dann Teil des Namespace.

namespace [parent-namespaces.]identifier

Das folgende Beispiel veranschaulicht das Konzept -

Beispiel

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

Wenn Sie das Programm kompilieren und ausführen, wird die folgende Ausgabe ausgegeben:

Values from Module1: ("one", "two", "three") 150
Values from Module2: seq [1; 4; 9; 16; ...] 200