F # - Guida rapida

F # è un linguaggio di programmazione funzionale. Per comprendere i costrutti F #, è necessario leggere un paio di righe sul paradigma di programmazione denominatoFunctional Programming.

La programmazione funzionale tratta i programmi per computer come funzioni matematiche. Nella programmazione funzionale, l'attenzione si concentrerebbe su costanti e funzioni, invece che su variabili e stati. Perché le funzioni e le costanti sono cose che non cambiano.

Nella programmazione funzionale, scriverete programmi modulari, cioè i programmi sarebbero costituiti da funzioni che prenderanno altre funzioni come input.

I programmi scritti in un linguaggio di programmazione funzionale tendono ad essere concisi.

Informazioni su F #

Di seguito sono riportate le informazioni di base su F # -

  • È stato sviluppato nel 2005 presso Microsoft Research.
  • Fa parte della famiglia Microsoft del linguaggio .Net.
  • È un linguaggio di programmazione funzionale.
  • Si basa sul linguaggio di programmazione funzionale OCaml.

Caratteristiche di F #

  • È l'implementazione .Net di OCaml.

  • Compila il codice byte .Net CLI (Common Language Interface) o MSIL (Microsoft Intermediate Language) che gira su CLR (Common Language Runtime).

  • Fornisce inferenza di tipo.

  • Fornisce ricchi costrutti di corrispondenza dei modelli.

  • Ha funzionalità di scripting e debugging interattive.

  • Consente di scrivere funzioni di ordine superiore.

  • Fornisce un modello a oggetti ben sviluppato.

Uso di F #

F # viene normalmente utilizzato nelle seguenti aree:

  • Fare modello scientifico
  • Risoluzione di problemi matematici
  • Lavoro di ricerca sull'intelligenza artificiale
  • Modellazione finanziaria
  • Disegno grafico
  • Design della CPU
  • Programmazione del compilatore
  • Telecommunications

Viene anche utilizzato nelle app CRUD, nelle pagine Web, nei giochi GUI e in altri programmi generici.

Gli strumenti necessari per la programmazione F # sono discussi in questo capitolo.

Ambiente di sviluppo integrato (IDE) per F #

Microsoft fornisce Visual Studio 2013 per la programmazione F #.

La versione gratuita di Visual Studio 2013 Community Edition è disponibile sul sito Web ufficiale di Microsoft. La community di Visual Studio 2013 e versioni successive include gli strumenti di Visual F #. Dettagli di installazione disponibili in Asp.net Tutorial . Gli strumenti di Visual F # includono il compilatore della riga di comando (fsc.exe) e F # Interactive (fsi.exe).

Utilizzando questi strumenti, è possibile scrivere tutti i tipi di programmi F # da semplici applicazioni della riga di comando ad applicazioni più complesse. Puoi anche scrivere file di codice sorgente F # usando un editor di testo di base, come Blocco note, e compilare il codice in assembly usando il compilatore della riga di comando.

Puoi scaricarlo da Microsoft Visual Studio. Viene installato automaticamente nella tua macchina.

Scrittura di programmi F # sui collegamenti

Visitare il sito Web ufficiale di F # per le ultime istruzioni su come ottenere gli strumenti come pacchetto Debian o compilarli direttamente dai sorgenti - https://fsharp.org/use/linux/.

F # è un linguaggio di programmazione funzionale.

In F #, le funzioni funzionano come i tipi di dati. Puoi dichiarare e utilizzare una funzione allo stesso modo di qualsiasi altra variabile.

In generale, un'applicazione F # non dispone di alcun punto di ingresso specifico. Il compilatore esegue tutte le istruzioni di primo livello nel file dall'alto verso il basso.

Tuttavia, per seguire lo stile di programmazione procedurale, molte applicazioni mantengono un'unica istruzione di primo livello che richiama il ciclo principale.

Il codice seguente mostra un semplice programma F # -

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

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

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

main()

Quando compili ed esegui il programma, restituisce il seguente output:

sign 5: positive

Si prega di notare che -

  • Un file di codice F # potrebbe iniziare con un numero di open istruzioni utilizzate per importare gli spazi dei nomi.

  • Il corpo dei file include altre funzioni che implementano la logica di business dell'applicazione.

  • Il ciclo principale contiene le prime istruzioni eseguibili.

Hai visto la struttura di base di un programma F #, quindi sarà facile capire altri elementi costitutivi di base del linguaggio di programmazione F #.

Gettoni in F #

Un programma F # è costituito da vari token. Un token può essere una parola chiave, un identificatore, una costante, una stringa letterale o un simbolo. Possiamo classificare i token F # in due tipi:

  • Keywords
  • Simbolo e operatori

Parole chiave F #

La tabella seguente mostra le parole chiave e una breve descrizione delle parole chiave. Discuteremo l'uso di queste parole chiave nei capitoli successivi.

Parola chiave Descrizione
abstract Indica un metodo che non ha implementazione nel tipo in cui è dichiarato o che è virtuale e ha un'implementazione predefinita.
and Utilizzato in associazioni reciprocamente ricorsive, nelle dichiarazioni di proprietà e con più vincoli su parametri generici.
as Usato per dare all'oggetto classe corrente un nome oggetto. Utilizzato anche per dare un nome a un intero pattern all'interno di una corrispondenza di pattern.
assert Utilizzato per verificare il codice durante il debug.
base Utilizzato come nome dell'oggetto della classe di base.
begin Nella sintassi dettagliata, indica l'inizio di un blocco di codice.
class Nella sintassi dettagliata, indica l'inizio di una definizione di classe.
default Indica un'implementazione di un metodo astratto; utilizzato insieme a una dichiarazione di metodo astratto per creare un metodo virtuale.
delegate Utilizzato per dichiarare un delegato.
do Utilizzato nei costrutti di ciclo o per eseguire codice imperativo.
done Nella sintassi dettagliata, indica la fine di un blocco di codice in un'espressione a ciclo continuo.
downcast Utilizzato per convertire in un tipo inferiore nella catena di ereditarietà.
downto In un for espressione, usata quando si conta al contrario.
elif Utilizzato nella ramificazione condizionale. Una forma breve di else if.
else Utilizzato nella ramificazione condizionale.
end

Nelle definizioni dei tipi e nelle estensioni dei tipi, indica la fine di una sezione delle definizioni dei membri.

Nella sintassi dettagliata, utilizzato per specificare la fine di un blocco di codice che inizia con la parola chiave begin.

exception Utilizzato per dichiarare un tipo di eccezione.
extern Indica che un elemento di programma dichiarato è definito in un altro binario o assembly.
false Usato come valore letterale booleano.
finally Utilizzato insieme al tentativo di introdurre un blocco di codice che viene eseguito indipendentemente dal fatto che si verifichi un'eccezione.
for Utilizzato nei costrutti di ciclo.
fun Utilizzato nelle espressioni lambda, note anche come funzioni anonime.
function Utilizzato come un'alternativa più breve alla parola chiave fun e un'espressione di corrispondenza in un'espressione lambda che ha la corrispondenza del modello su un singolo argomento.
global Utilizzato per fare riferimento allo spazio dei nomi .NET di primo livello.
if Utilizzato nei costrutti di ramificazione condizionale.
in Utilizzato per le espressioni di sequenza e, nella sintassi dettagliata, per separare le espressioni dalle associazioni.
inherit Utilizzato per specificare una classe di base o un'interfaccia di base.
inline Utilizzato per indicare una funzione che dovrebbe essere integrata direttamente nel codice del chiamante.
interface Utilizzato per dichiarare e implementare le interfacce.
internal Utilizzato per specificare che un membro è visibile all'interno di un assieme ma non all'esterno.
lazy Utilizzato per specificare un calcolo che deve essere eseguito solo quando è necessario un risultato.
let Utilizzato per associare o legare un nome a un valore o una funzione.
let! Utilizzato nei flussi di lavoro asincroni per associare un nome al risultato di un calcolo asincrono o, in altre espressioni di calcolo, utilizzato per associare un nome a un risultato, che è del tipo di calcolo.
match Utilizzato per ramificare confrontando un valore con un modello.
member Utilizzato per dichiarare una proprietà o un metodo in un tipo di oggetto.
module Utilizzato per associare un nome a un gruppo di tipi, valori e funzioni correlati, per separarlo logicamente da altro codice.
mutable Utilizzato per dichiarare una variabile, ovvero un valore che può essere modificato.
namespace Utilizzato per associare un nome a un gruppo di tipi e moduli correlati, per separarlo logicamente da altro codice.
new

Utilizzato per dichiarare, definire o richiamare un costruttore che crea o che può creare un oggetto.

Utilizzato anche nei vincoli di parametri generici per indicare che un tipo deve avere un determinato costruttore.

not Non in realtà una parola chiave. Tuttavia, non struct in combinazione viene utilizzato come vincolo di parametro generico.
null

Indica l'assenza di un oggetto.

Utilizzato anche in vincoli di parametri generici.

of Utilizzato nelle unioni discriminate per indicare il tipo di categorie di valori e nelle dichiarazioni di delega e di eccezione.
open Utilizzato per rendere disponibile il contenuto di uno spazio dei nomi o di un modulo senza qualificazione.
or

Utilizzato con condizioni booleane come operatore o booleano. Equivalente a ||.

Utilizzato anche nei vincoli dei membri.

override Utilizzato per implementare una versione di un metodo astratto o virtuale che differisce dalla versione di base.
private Limita l'accesso a un membro al codice nello stesso tipo o modulo.
public Consente l'accesso a un membro dall'esterno del tipo.
rec Utilizzato per indicare che una funzione è ricorsiva.
return Utilizzato per indicare un valore da fornire come risultato di un'espressione di calcolo.
return! Utilizzato per indicare un'espressione di calcolo che, una volta valutata, fornisce il risultato dell'espressione di calcolo contenitore.
select Utilizzato nelle espressioni di query per specificare quali campi o colonne estrarre. Nota che questa è una parola chiave contestuale, il che significa che non è effettivamente una parola riservata e agisce solo come una parola chiave nel contesto appropriato.
static Utilizzato per indicare un metodo o una proprietà che può essere chiamata senza un'istanza di un tipo o un membro del valore condiviso tra tutte le istanze di un tipo.
struct

Utilizzato per dichiarare un tipo di struttura.

Utilizzato anche in vincoli di parametri generici.

Utilizzato per la compatibilità OCaml nelle definizioni dei moduli.

then

Utilizzato nelle espressioni condizionali.

Utilizzato anche per eseguire effetti collaterali dopo la costruzione di oggetti.

to Utilizzato nei cicli for per indicare un intervallo.
true Usato come valore letterale booleano.
try Utilizzato per introdurre un blocco di codice che potrebbe generare un'eccezione. Usato insieme a o finalmente.
type Utilizzato per dichiarare una classe, un record, una struttura, un'unione discriminata, un tipo di enumerazione, un'unità di misura o un'abbreviazione di tipo.
upcast Utilizzato per convertire in un tipo che è più alto nella catena di ereditarietà.
use Utilizzato invece di let per i valori che richiedono la chiamata di Dispose per liberare risorse.
use! Usato invece di lasciare! nei flussi di lavoro asincroni e in altre espressioni di calcolo per i valori che richiedono la chiamata di Dispose per liberare risorse.
val Utilizzato in una firma per indicare un valore o in un tipo per dichiarare un membro, in situazioni limitate.
void Indica il tipo di vuoto .NET. Utilizzato durante l'interoperabilità con altri linguaggi .NET.
when Utilizzato per condizioni booleane (quando sorveglia) sulle corrispondenze di modelli e per introdurre una clausola di vincolo per un parametro di tipo generico.
while Introduce un costrutto a ciclo continuo.
with Utilizzato insieme alla parola chiave match nelle espressioni di corrispondenza dei pattern. Utilizzato anche in espressioni di oggetti, espressioni di copia di record ed estensioni di tipo per introdurre definizioni di membri e per introdurre gestori di eccezioni.
yield Utilizzato in un'espressione di sequenza per produrre un valore per una sequenza.
yield! Utilizzato in un'espressione di calcolo per aggiungere il risultato di una data espressione di calcolo a una raccolta di risultati per l'espressione di calcolo contenitore.

Alcune parole chiave riservate provenivano dalla lingua OCaml -

asr terra lor lsl lsr lxor mod sig

Alcune altre parole chiave riservate vengono conservate per la futura espansione di F #.

atomico rompere controllato componente const vincolo 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

UN tupleè una raccolta di valori separati da virgole. Questi vengono utilizzati per creare strutture di dati ad hoc, che raggruppano i valori correlati.

Ad esempio, ("Zara Ali", "Hyderabad", 10) è una tupla tripla con due valori stringa e un valore int, ha il tipo (string * string * int).

Le tuple possono essere coppie, triple e così via, dello stesso tipo o di tipi diversi.

Alcuni esempi sono forniti qui -

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

Esempio

Questo programma ha una funzione che accetta una tupla di quattro valori float e restituisce la media -

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

Quando compili ed esegui il programma, restituisce il seguente output:

Avg of four numbers: 7.275000

Accesso ai singoli membri della tupla

I singoli membri di una tupla possono essere valutati e stampati utilizzando il pattern matching.

L'esempio seguente illustra il concetto:

Esempio

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

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

Quando compili ed esegui il programma, restituisce il seguente output:

Detail Info: "Zara Ali" "Hyderabad" 10

F # ha due funzioni incorporate, fst e snd, che restituiscono il primo e il secondo elemento in una doppia tupla.

L'esempio seguente illustra il concetto:

Esempio

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)

Quando compili ed esegui il programma, restituisce il seguente output:

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

UN recordè simile a una tupla, tuttavia contiene campi denominati. Per esempio,

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

Definizione del record

Un record è definito come un tipo utilizzando l'estensione type parola chiave ei campi del record sono definiti come un elenco separato da punti e virgola.

La sintassi per la definizione di un record è:

type recordName =
   { [ fieldName : dataType ] + }

Creazione di un record

È possibile creare un record specificando i campi del record. Ad esempio, creiamo un record del sito web denominato homepage -

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

I seguenti esempi spiegheranno i concetti:

Esempio 1

Questo programma definisce un tipo di record denominato sito web. Quindi crea alcuni record di tipo website e stampa i record.

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

Quando compili ed esegui il programma, restituisce il seguente output:

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"

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

In F #, un elenco è una serie ordinata e immutabile di elementi dello stesso tipo. In una certa misura è equivalente a una struttura dati di un elenco collegato.

Il modulo F #, Microsoft.FSharp.Collections.List,ha le operazioni comuni sugli elenchi. Tuttavia F # importa questo modulo automaticamente e lo rende accessibile a ogni applicazione F #.

Creazione e inizializzazione di un elenco

Di seguito sono riportati i vari modi per creare elenchi:

  • Utilizzando list literals.

  • Utilizzando cons (: :) operatore.

  • Usando il List.init metodo del modulo List.

  • Usandone alcuni syntactic constructs chiamato List Comprehensions.

List Literals

In questo metodo, è sufficiente specificare una sequenza di valori delimitati da punto e virgola tra parentesi quadre. Ad esempio:

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

I contro (: :) Operator

Con questo metodo, puoi aggiungere alcuni valori anteponendo o cons-ingin un elenco esistente utilizzando l'operatore ::. Ad esempio:

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

[] denota un elenco vuoto.

Metodo di inizializzazione dell'elenco

Il metodo List.init del modulo List viene spesso utilizzato per creare elenchi. Questo metodo ha il tipo -

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

Il primo argomento è la lunghezza desiderata del nuovo elenco e il secondo argomento è una funzione di inizializzazione, che genera elementi nell'elenco.

Per esempio,

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

Qui, la funzione index genera l'elenco.

Comprensioni dell'elenco

Le comprensioni di elenchi sono costrutti sintattici speciali utilizzati per la generazione di elenchi.

La sintassi di comprensione dell'elenco F # è disponibile in due forme: intervalli e generatori.

Gli intervalli hanno i costrutti - [inizio .. fine] e [inizio .. passo .. fine]

Per esempio,

let list3 = [1 .. 10]

I generatori hanno il costrutto - [for x in collection do ... yield expr]

Per esempio,

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

Come la yield parola chiave inserisce un singolo valore in un elenco, la parola chiave, yield!, inserisce una raccolta di valori nell'elenco.

La seguente funzione mostra i metodi precedenti:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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]

Proprietà del tipo di dati elenco

La tabella seguente mostra varie proprietà del tipo di dati elenco:

Proprietà genere Descrizione
Testa 'T Il primo elemento.
Vuoto 'T elenco Una proprietà statica che restituisce un elenco vuoto del tipo appropriato.
È vuoto bool true se l'elenco non ha elementi.
Articolo 'T L'elemento all'indice specificato (in base zero).
Lunghezza int Il numero di elementi.
Coda 'T elenco L'elenco senza il primo elemento.

L'esempio seguente mostra l'uso di queste proprietà:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Operatori di base in elenco

La tabella seguente mostra le operazioni di base sul tipo di dati dell'elenco:

Valore Descrizione
append: 'T list →' T list → 'T list Restituisce un nuovo elenco che contiene gli elementi del primo elenco seguito dagli elementi del secondo.
media: lista 'T → ^ T Restituisce la media degli elementi nell'elenco.
averageBy: ('T → ^ U) →' T list → ^ U Restituisce la media degli elementi generati applicando la funzione a ogni elemento della lista.
scegli: (opzione 'T →' U) → lista 'T → lista' U Applica la funzione data a ogni elemento dell'elenco. Restituisce l'elenco composto dai risultati per ogni elemento in cui restituisce la funzioneSome.
collect: ('T →' U list) → 'T list →' U list Per ogni elemento della lista, applica la funzione data. Concatena tutti i risultati e restituisce l'elenco combinato.
concat: seq <'T lista> →' T lista Restituisce un nuovo elenco che contiene gli elementi di ciascuno degli elenchi in ordine.
vuoto: lista 'T Restituisce un elenco vuoto del tipo specificato.
esiste: ('T → bool) →' T list → bool Verifica se un qualsiasi elemento della lista soddisfa il predicato dato.
esiste2: ('T1 →' T2 → bool) → 'T1 list →' T2 list → bool Verifica se una qualsiasi coppia di elementi corrispondenti delle liste soddisfa il predicato dato.
filtro: ('T → bool) →' T lista → 'T lista Restituisce una nuova raccolta contenente solo gli elementi della raccolta per cui restituisce il predicato specificato true.
trova: ('T → bool) →' T list → 'T Restituisce il primo elemento per il quale restituisce la funzione data true.
findIndex: ('T → bool) →' T list → int Restituisce l'indice del primo elemento nell'elenco che soddisfa il predicato dato.
fold: ('State →' T → 'State) →' State → 'T list →' State Applica una funzione a ogni elemento della raccolta, inserendo un argomento dell'accumulatore attraverso il calcolo. Questa funzione accetta il secondo argomento e applica la funzione ad esso e al primo elemento della lista. Quindi, passa questo risultato alla funzione insieme al secondo elemento e così via. Infine, restituisce il risultato finale. Se la funzione di input è f e gli elementi sono i0 ... iN, questa funzione calcola f (... (fs i0) i1 ...) iN.
fold2: ('State →' T1 → 'T2 →' State) → 'State →' T1 list → 'T2 list →' State Applica una funzione agli elementi corrispondenti di due raccolte, inserendo un argomento dell'accumulatore attraverso il calcolo. Le collezioni devono avere dimensioni identiche. Se la funzione di input è f e gli elementi sono i0 ... iN e j0 ... jN, questa funzione calcola f (... (fs i0 j0) ...) iN jN.
foldBack: ('T →' State → 'State) →' T list → 'State →' State Applica una funzione a ogni elemento della raccolta, inserendo un argomento dell'accumulatore attraverso il calcolo. Se la funzione di input isf e gli elementi sono i0 ... iN, calcola f i0 (... (f iN s)).
foldBack2: ('T1 →' T2 → 'State →' State) → 'T1 list →' T2 list → 'State →' State Applica una funzione agli elementi corrispondenti di due raccolte, inserendo un argomento dell'accumulatore attraverso il calcolo. Le collezioni devono avere dimensioni identiche. Se la funzione di input è f e gli elementi sono i0 ... iN e j0 ... jN, questa funzione calcola f i0 j0 (... (f iN jN s)).
forall: ('T → bool) →' T list → bool Verifica se tutti gli elementi della raccolta soddisfano il predicato specificato.
forall2: ('T1 →' T2 → bool) → 'T1 list →' T2 list → bool Verifica se tutti gli elementi corrispondenti della raccolta soddisfano a coppie il predicato specificato.
head: 'T lista →' T Restituisce il primo elemento della lista.
init: int → (int → 'T) →' T list Crea un elenco chiamando il generatore specificato su ogni indice.
isEmpty: 'T list → bool ritorna true se l'elenco non contiene elementi, false altrimenti.
iter: ('T → unit) →' T list → unit Applica la funzione data a ogni elemento della raccolta.
iter2: ('T1 →' T2 → unit) → 'T1 list →' T2 list → unit Applica la funzione data a due raccolte contemporaneamente. Le collezioni devono avere dimensioni identiche.
iteri: (int → 'T → unit) →' T list → unit Applica la funzione data a ogni elemento della raccolta. L'intero passato alla funzione indica l'indice dell'elemento.
iteri2: (int → 'T1 →' T2 → unit) → 'T1 list →' T2 list → unit Applica la funzione data a due raccolte contemporaneamente. Le collezioni devono avere dimensioni identiche. L'intero passato alla funzione indica l'indice dell'elemento.
lunghezza: lista 'T → int Restituisce la lunghezza dell'elenco.
map: ('T →' U) → 'T list →' U list Crea una nuova raccolta i cui elementi sono il risultato dell'applicazione della funzione data a ciascuno degli elementi della raccolta.
map2: ('T1 →' T2 → 'U) →' T1 list → 'T2 list →' U list Crea una nuova raccolta i cui elementi sono il risultato dell'applicazione della funzione data agli elementi corrispondenti delle due raccolte a coppie.
map3: ('T1 →' T2 → 'T3 →' U) → 'T1 list →' T2 list → 'T3 list →' U list Crea una nuova raccolta i cui elementi sono il risultato dell'applicazione della funzione data agli elementi corrispondenti delle tre raccolte contemporaneamente.
mapi: (int → 'T →' U) → 'T list →' U list Crea una nuova raccolta i cui elementi sono il risultato dell'applicazione della funzione data a ciascuno degli elementi della raccolta. L'indice intero passato alla funzione indica l'indice (da 0) dell'elemento trasformato.
mapi2: (int → 'T1 →' T2 → 'U) →' T1 list → 'T2 list →' U list Come List.mapi, ma mappando gli elementi corrispondenti da due elenchi di uguale lunghezza.
max: 'T lista →' T Restituisce il più grande di tutti gli elementi dell'elenco, confrontato utilizzando Operators.max.
maxBy: ('T →' U) → 'T list →' T Restituisce il più grande di tutti gli elementi dell'elenco, confrontato utilizzando Operators.max sul risultato della funzione.
min: 'T lista →' T Restituisce il più basso di tutti gli elementi dell'elenco, confrontato utilizzando Operators.min.
minBy: ('T →' U) → 'T list →' T Restituisce il più basso di tutti gli elementi dell'elenco, confrontato utilizzando Operators.min sul risultato della funzione
nth: 'T list → int →' T Indici nell'elenco. Il primo elemento ha indice 0.
ofArray: 'T [] →' T list Crea un elenco dalla matrice data.
ofSeq: seq <'T> →' T list Crea un nuovo elenco dall'oggetto enumerabile specificato.
partizione: ('T → bool) →' T list * 'T list Divide la raccolta in due raccolte, contenenti gli elementi per i quali restituisce il predicato specificato true e false rispettivamente.
permute: (int → int) → 'T list →' T list Restituisce un elenco con tutti gli elementi permutati secondo la permutazione specificata.
scegli: (opzione 'T →' U) → lista 'T →' U Applica la funzione data agli elementi successivi, restituendo il primo risultato dove la funzione ritorna Some per qualche valore.
ridurre: ('T →' T → 'T) →' T lista → 'T Applica una funzione a ogni elemento della raccolta, inserendo un argomento dell'accumulatore attraverso il calcolo. Questa funzione applica la funzione specificata ai primi due elementi dell'elenco. Quindi passa questo risultato alla funzione insieme al terzo elemento e così via. Infine, restituisce il risultato finale. Se la funzione di input è f e gli elementi sono i0 ... iN, questa funzione calcola f (... (f i0 i1) i2 ...) iN.
reduceBack: ('T →' T → 'T) →' T list → 'T Applica una funzione a ogni elemento della raccolta, inserendo un argomento dell'accumulatore attraverso il calcolo. Se la funzione di input isf e gli elementi sono i0 ... iN, questa funzione calcola f i0 (... (f iN-1 iN)).
replicare: (int → 'T →' T lista) Crea un elenco chiamando il generatore specificato su ogni indice.
rev: 'T lista →' T lista Restituisce un nuovo elenco con gli elementi in ordine inverso.
scan: ('State →' T → 'State) →' State → 'T list →' State list Applica una funzione a ogni elemento della raccolta, inserendo un argomento dell'accumulatore attraverso il calcolo. Questa funzione accetta il secondo argomento e applica ad esso la funzione specificata e il primo elemento dell'elenco. Quindi, passa questo risultato alla funzione insieme al secondo elemento e così via. Infine, restituisce l'elenco dei risultati intermedi e il risultato finale.
scanBack: ('T →' State → 'State) →' T list → 'State →' State list Come foldBack, ma restituisce sia i risultati intermedi che quelli finali
ordina: 'T lista →' T lista Ordina l'elenco fornito utilizzando Operators.compare.
sortBy: ('T →' Key) → 'T list →' T list Ordina l'elenco fornito utilizzando i tasti forniti dalla proiezione data. Le chiavi vengono confrontate utilizzando Operators.compare.
sortWith: ('T →' T → int) → 'T list →' T list Ordina l'elenco fornito utilizzando la funzione di confronto data.
somma: ^ T lista → ^ T Restituisce la somma degli elementi nell'elenco.
sumBy: ('T → ^ U) →' T list → ^ U Restituisce la somma dei risultati generati applicando la funzione a ogni elemento della lista.
coda: lista 'T → lista' T Restituisce l'elenco di input senza il primo elemento.
toArray: 'T list →' T [] Crea un array dall'elenco fornito.
toSeq: 'T list → seq <' T> Visualizza l'elenco fornito come una sequenza.
tryFind: ('T → bool) →' T list → 'T opzione Restituisce il primo elemento per il quale restituisce la funzione data true. RitornoNone se tale elemento non esiste.
tryFindIndex: ('T → bool) →' T list → int opzione Restituisce l'indice del primo elemento nell'elenco che soddisfa il predicato dato. RitornoNone se tale elemento non esiste.
tryPick: (opzione 'T →' U) → lista 'T → opzione' U Applica la funzione data agli elementi successivi, restituendo il primo risultato dove la funzione ritorna Someper qualche valore. Se tale elemento non esiste, ritornaNone.
unzip: ('T1 *' T2) list → 'T1 list *' T2 list Divide un elenco di coppie in due elenchi.
unzip3: ('T1 *' T2 * 'T3) list →' T1 list * 'T2 list *' T3 list Divide un elenco di triple in tre elenchi.
zip: 'Elenco T1 →' Elenco T2 → ('T1 *' T2) elenco Combina i due elenchi in un elenco di coppie. Le due liste devono avere la stessa lunghezza.
zip3: 'T1 list →' T2 list → 'T3 list → (' T1 * 'T2 *' T3) list Combina le tre liste in una lista di triple. Gli elenchi devono avere la stessa lunghezza.

I seguenti esempi dimostrano gli usi delle funzionalità di cui sopra:

Esempio 1

Questo programma mostra l'inversione ricorsiva di un elenco:

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)

Quando compili ed esegui il programma, restituisce il seguente output:

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

Tuttavia, puoi usare l'estensione rev funzione del modulo per lo stesso scopo -

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Esempio 2

Questo programma mostra il filtraggio di un elenco utilizzando il List.filter metodo -

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Esempio 3

Il List.map metodo mappa un elenco da un tipo a un altro -

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

Quando compili ed esegui il programma, restituisce il seguente 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"]

Esempio 4

Il List.append metodo e l'operatore @ aggiunge un elenco a un altro -

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

Quando compili ed esegui il programma, restituisce il seguente 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']

Esempio 5

Il List.sortmetodo ordina un elenco. IlList.sum fornisce la somma degli elementi nell'elenco e il metodo List.average metodo fornisce la media degli elementi nell'elenco -

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

Quando compili ed esegui il programma, restituisce il seguente 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

Un'operazione di "piegatura" applica una funzione a ciascun elemento in un elenco, aggrega il risultato della funzione in una variabile accumulator e restituisce l'accumulatore come risultato dell'operazione di piegatura.

Esempio 6

Il List.fold metodo applica una funzione a ciascun elemento da sinistra a destra, mentre List.foldBack applica una funzione a ogni elemento da destra a sinistra.

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Le sequenze, come gli elenchi, rappresentano anche una raccolta ordinata di valori. Tuttavia, gli elementi in una sequenza o un'espressione di sequenza vengono calcolati quando richiesto. Non vengono calcolati in una volta e per questo motivo vengono utilizzati per rappresentare strutture dati infinite.

Definizione di sequenze

Le sequenze vengono definite utilizzando la seguente sintassi:

seq { expr }

Per esempio,

let seq1 = seq { 1 .. 10 }

Creazione di sequenze ed espressioni di sequenze

Analogamente agli elenchi, puoi creare sequenze utilizzando intervalli e comprensioni.

Le espressioni di sequenza sono le espressioni che puoi scrivere per creare sequenze. Questi possono essere fatti -

  • Specificando l'intervallo.
  • Specificando l'intervallo con incremento o decremento.
  • Utilizzando il yield parola chiave per produrre valori che diventano parte della sequenza.
  • Utilizzando l'operatore →.

I seguenti esempi dimostrano il concetto:

Esempio 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

Quando compili ed esegui il programma, restituisce il seguente 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); ...]

Esempio 2

Il seguente programma stampa i numeri primi da 1 a 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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Operazioni di base sulla sequenza

La tabella seguente mostra le operazioni di base sul tipo di dati della sequenza:

Valore Descrizione
aggiungi: seq <'T> → seq <' T> → seq <'T> Avvolge le due enumerazioni date come un'unica enumerazione concatenata.
media: seq <^ T> → ^ T Restituisce la media degli elementi nella sequenza.
averageBy: ('T → ^ U) → seq <' T> → ^ U Restituisce la media dei risultati generati applicando la funzione a ogni elemento della sequenza.
cache: seq <'T> → seq <' T> Restituisce una sequenza che corrisponde a una versione memorizzata nella cache della sequenza di input.
cast: IEnumerable → seq <'T> Avvolge un sistema a bassa tipizzazione. Sequenza di raccolte come sequenza digitata.
scegli: (opzione 'T →' U) → seq <'T> → seq <' U> Applica la funzione data a ogni elemento dell'elenco. Restituisce l'elenco composto dai risultati per ogni elemento in cui restituisce la funzioneSome.
collect: ('T →' Collection) → seq <'T> → seq <' U> Applica la funzione data a ciascun elemento della sequenza e concatena tutti i risultati.
compareCon: ('T →' T → int) → seq <'T> → seq <' T> → int Confronta due sequenze utilizzando la funzione di confronto data, elemento per elemento.
concat: seq <'Collection> → seq <' T> Combina l'enumerazione di enumerazioni data come una singola enumerazione concatenata.
countBy: ('T →' Key) → seq <'T> → seq <' Key * int> Applica una funzione di generazione di chiavi a ogni elemento di una sequenza e restituisce una sequenza che fornisce chiavi univoche e il loro numero di occorrenze nella sequenza originale.
ritardo: (unità → seq <'T>) → seq <' T> Restituisce una sequenza creata dalla specifica ritardata di una sequenza.
distinto: seq <'T> → seq <' T> Restituisce una sequenza che non contiene voci duplicate in base a hash generici e confronti di uguaglianza sulle voci. Se un elemento si verifica più volte nella sequenza, le occorrenze successive vengono eliminate.
distintoBy: ('T →' Key) → seq <'T> → seq <' T> Restituisce una sequenza che non contiene voci duplicate in base all'hash generico e ai confronti di uguaglianza sulle chiavi restituite dalla funzione di generazione della chiave specificata. Se un elemento si verifica più volte nella sequenza, le occorrenze successive vengono eliminate.
vuoto: seq <'T> Crea una sequenza vuota.
esattamente Uno: seq <'T> →' T Restituisce l'unico elemento della sequenza.
esiste: ('T → bool) → seq <' T> → bool Verifica se qualsiasi elemento della sequenza soddisfa il predicato dato.
esiste2: ('T1 →' T2 → bool) → seq <'T1> → seq <' T2> → bool Verifica se qualsiasi coppia di elementi corrispondenti delle sequenze di input soddisfa il predicato dato.
filtro: ('T → bool) → seq <' T> → seq <'T> Restituisce una nuova raccolta contenente solo gli elementi della raccolta per cui restituisce il predicato specificato true.
trova: ('T → bool) → seq <' T> → 'T Restituisce il primo elemento per il quale restituisce la funzione data true.
findIndex: ('T → bool) → seq <' T> → int Restituisce l'indice del primo elemento per il quale restituisce la funzione data true.
fold: ('State →' T → 'State) →' State → seq <'T> →' State Applica una funzione a ogni elemento della raccolta, inserendo un argomento dell'accumulatore attraverso il calcolo. Se la funzione di input è f e gli elementi sono i0 ... iN, questa funzione calcola f (... (fs i0) ...) iN.
forall: ('T → bool) → seq <' T> → bool Verifica se tutti gli elementi della sequenza soddisfano il predicato specificato.
forall2: ('T1 →' T2 → bool) → seq <'T1> → seq <' T2> → bool Verifica che tutte le coppie di elementi tratte dalle due sequenze soddisfino il predicato dato. Se una sequenza è più breve dell'altra, gli elementi rimanenti della sequenza più lunga vengono ignorati.
groupBy: ('T →' Key) → seq <'T> → seq <' Key * seq <'T >> Applica una funzione di generazione di chiavi a ogni elemento di una sequenza e produce una sequenza di chiavi univoche. Ogni chiave univoca contiene anche una sequenza di tutti gli elementi che corrispondono a questa chiave.
head: seq <'T> →' T Restituisce il primo elemento della sequenza.
init: int → (int → 'T) → seq <' T> Genera una nuova sequenza che, una volta iterata, restituisce elementi successivi chiamando la funzione data, fino al conteggio dato. I risultati della chiamata della funzione non vengono salvati, ovvero la funzione viene riapplicata se necessario per rigenerare gli elementi. Alla funzione viene passato l'indice dell'elemento generato.
initInfinite: (int → 'T) → seq <' T> Genera una nuova sequenza che, una volta iterata, restituirà elementi successivi chiamando la funzione data. I risultati della chiamata della funzione non vengono salvati, ovvero la funzione verrà riapplicata se necessario per rigenerare gli elementi. Alla funzione viene passato l'indice dell'elemento generato.
isEmpty: seq <'T> → bool Verifica se una sequenza contiene elementi.
iter: ('T → unit) → seq <' T> → unit Applica la funzione data a ogni elemento della raccolta.
iter2: ('T1 →' T2 → unit) → seq <'T1> → seq <' T2> → unit Applica la funzione data a due raccolte contemporaneamente. Se una sequenza è più breve dell'altra, gli elementi rimanenti della sequenza più lunga vengono ignorati.
iteri: (int → 'T → unit) → seq <' T> → unit Applica la funzione data a ogni elemento della raccolta. L'intero passato alla funzione indica l'indice dell'elemento.
ultimo: seq <'T> →' T Restituisce l'ultimo elemento della sequenza.
lunghezza: seq <'T> → int Restituisce la lunghezza della sequenza.
mappa: ('T →' U) → seq <'T> → seq <' U> Crea una nuova raccolta i cui elementi sono il risultato dell'applicazione della funzione data a ciascuno degli elementi della raccolta. La funzione data verrà applicata quando gli elementi vengono richiesti utilizzando il metodo MoveNext sugli enumeratori recuperati dall'oggetto.
map2: ('T1 →' T2 → 'U) → seq <' T1> → seq <'T2> → seq <' U> Crea una nuova raccolta i cui elementi sono il risultato dell'applicazione della funzione data alle coppie di elementi corrispondenti dalle due sequenze. Se una sequenza di input è più breve dell'altra, gli elementi rimanenti della sequenza più lunga vengono ignorati.
mapi: (int → 'T →' U) → seq <'T> → seq <' U> Crea una nuova raccolta i cui elementi sono il risultato dell'applicazione della funzione data a ciascuno degli elementi della raccolta. L'indice intero passato alla funzione indica l'indice (da 0) dell'elemento trasformato.
max: seq <'T> →' T Restituisce il più grande di tutti gli elementi della sequenza, confrontato utilizzando Operators.max.
maxBy: ('T →' U) → seq <'T> →' T Restituisce il più grande di tutti gli elementi della sequenza, confrontato utilizzando Operators.max sul risultato della funzione.
min: seq <'T> →' T Restituisce il più basso di tutti gli elementi della sequenza, confrontato utilizzando Operators.min.
minBy: ('T →' U) → seq <'T> →' T Restituisce il più basso di tutti gli elementi della sequenza, confrontato utilizzando Operators.min sul risultato della funzione.
ennesimo: int → seq <'T> →' T Calcola l' ennesimo elemento nella raccolta.
ofArray: 'T array → seq <' T> Visualizza la matrice data come una sequenza.
ofList: 'T list → seq <' T> Visualizza l'elenco fornito come una sequenza.
a coppie: seq <'T> → seq <' T * 'T> Restituisce una sequenza di ogni elemento nella sequenza di input e il suo predecessore, ad eccezione del primo elemento che viene restituito solo come predecessore del secondo elemento.
scegli: (opzione 'T →' U) → seq <'T> →' U Applica la funzione data a elementi successivi, restituendo il primo valore in cui la funzione restituisce a Some valore.
sola lettura: seq <'T> → seq <' T> Crea un nuovo oggetto sequenza che delega all'oggetto sequenza specificato. Ciò garantisce che la sequenza originale non possa essere riscoperta e modificata da un cast di tipo. Ad esempio, se viene fornito un array, la sequenza restituita restituirà gli elementi dell'array, ma non è possibile eseguire il cast dell'oggetto sequenza restituito su un array.
ridurre: ('T →' T → 'T) → seq <' T> → 'T Applica una funzione a ciascun elemento della sequenza, inserendo un argomento dell'accumulatore attraverso il calcolo. Inizia applicando la funzione ai primi due elementi. Quindi inserisci questo risultato nella funzione insieme al terzo elemento e così via. Restituisci il risultato finale.
scansione: ('State →' T → 'State) →' State → seq <'T> → seq <' State> Come Seq. Piega, ma calcola su richiesta e restituisce la sequenza dei risultati intermedi e finali.
singleton: 'T → seq <' T> Restituisce una sequenza che produce un solo elemento.
salta: int → seq <'T> → seq <' T> Restituisce una sequenza che salta un numero specificato di elementi della sequenza sottostante e quindi restituisce gli elementi rimanenti della sequenza.
skipWhile: ('T → bool) → seq <' T> → seq <'T> Restituisce una sequenza che, quando iterata, salta gli elementi della sequenza sottostante mentre il predicato dato ritorna true, e quindi restituisce gli elementi rimanenti della sequenza.
ordina: seq <'T> → seq <' T> Restituisce una sequenza ordinata per chiavi.
sortBy: ('T →' Key) → seq <'T> → seq <' T> Applica una funzione di generazione di chiavi a ogni elemento di una sequenza e produce una sequenza ordinata per chiavi. Le chiavi vengono confrontate utilizzando il confronto generico implementato da Operators.compare.
somma: seq <^ T> → ^ T Restituisce la somma degli elementi nella sequenza.
sumBy Restituisce la somma dei risultati generati applicando la funzione a ogni elemento della sequenza.
prendere: int → seq <'T> → seq <' T> Restituisce i primi elementi della sequenza fino a un conteggio specificato.
takeWhile: ('T → bool) → seq <' T> → seq <'T> Restituisce una sequenza che, quando iterata, restituisce elementi della sequenza sottostante mentre il predicato dato ritorna true, e quindi non restituisce ulteriori elementi.
toArray: seq <'T> →' T [] Crea un array dalla raccolta data.
toList: seq <'T> →' T list Crea un elenco dalla raccolta data.
troncare: int → seq <'T> → seq <' T> Restituisce una sequenza che, se enumerata, non restituisce più di un numero di elementi specificato.
tryFind: ('T → bool) → seq <' T> → 'T opzione Restituisce il primo elemento per il quale restituisce la funzione data true, o None se tale elemento non esiste.
tryFindIndex: ('T → bool) → seq <' T> → int opzione Restituisce l'indice del primo elemento nella sequenza che soddisfa il predicato dato, o None se tale elemento non esiste.
tryPick: (opzione 'T →' U) → seq <'T> → opzione' U Applica la funzione data a elementi successivi, restituendo il primo valore in cui la funzione restituisce a Some valore.
unfold: ('State →' T * 'State opzione) →' State → seq <'T> Restituisce una sequenza che contiene gli elementi generati dal dato calcolo.
dove: ('T → bool) → seq <' T> → seq <'T> Restituisce una nuova raccolta contenente solo gli elementi della raccolta per cui restituisce il predicato specificato true. Un sinonimo di Seq.filter.
windowed: int → seq <'T> → seq <' T []> Restituisce una sequenza che produce finestre scorrevoli di elementi contenenti disegnati dalla sequenza di input. Ogni finestra viene restituita come un nuovo array.
zip: seq <'T1> → seq <' T2> → seq <'T1 *' T2> Combina le due sequenze in un elenco di coppie. Non è necessario che le due sequenze abbiano la stessa lunghezza: quando una sequenza è esaurita, qualsiasi elemento rimanente nell'altra sequenza viene ignorato.
zip3: seq <'T1> → seq <' T2> → seq <'T3> → seq <' T1 * 'T2 *' T3> Combina le tre sequenze in un elenco di triple. Non è necessario che le sequenze abbiano la stessa lunghezza: quando una sequenza è esaurita, gli elementi rimanenti nelle altre sequenze vengono ignorati.

I seguenti esempi dimostrano gli usi di alcune delle funzionalità di cui sopra:

Esempio 1

Questo programma crea una sequenza vuota e la riempie in seguito -

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

Quando compili ed esegui il programma, restituisce il seguente 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

Si prega di notare che -

  • Il metodo Seq.empty crea una sequenza vuota.

  • Il metodo Seq.singleton crea una sequenza di un solo elemento specificato.

  • Il metodo Seq.init crea una sequenza per la quale vengono creati gli elementi utilizzando una determinata funzione.

  • I metodi Seq.ofArray e Seq.ofList <'T> creano sequenze da array ed elenchi.

  • Il metodo Seq.iter consente l'iterazione attraverso una sequenza.

Esempio 2

Il metodo Seq.unfold genera una sequenza da una funzione di calcolo che assume uno stato e lo trasforma per produrre ogni elemento successivo nella sequenza.

La seguente funzione produce i primi 20 numeri naturali:

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Esempio 3

Il metodo Seq.truncate crea una sequenza da un'altra sequenza, ma limita la sequenza a un numero specificato di elementi.

Il metodo Seq.take crea una nuova sequenza che contiene un numero specificato di elementi dall'inizio di una sequenza.

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Un set in F # è una struttura di dati che funge da raccolta di elementi senza mantenere l'ordine in cui vengono inseriti gli elementi. I set non consentono l'inserimento di voci duplicate nella raccolta.

Creazione di set

I set possono essere creati nei seguenti modi:

  • Creando un set vuoto utilizzando Set.empty e aggiungendo elementi utilizzando la funzione di aggiunta.
  • Conversione di sequenze ed elenchi in insiemi.

Il seguente programma mostra le tecniche:

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

Quando compili ed esegui il programma, restituisce il seguente output:

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]

Operazioni di base sui set

La tabella seguente mostra le operazioni di base sui set:

Valore Descrizione
aggiungere: 'T → Set <' T> → Set <'T> Restituisce un nuovo set con un elemento aggiunto al set. Non viene sollevata alcuna eccezione se l'insieme contiene già l'elemento specificato.
contiene: 'T → Set <' T> → bool Valuta a true se l'elemento dato è nell'insieme dato.
count: Set <'T> → int Restituisce il numero di elementi nel set.
differenza: Imposta <'T> → Imposta <' T> → Imposta <'T> Restituisce un nuovo set con gli elementi del secondo set rimossi dal primo.
vuoto: imposta <'T> Il set vuoto per il tipo specificato.
esiste: ('T → bool) → Set <' T> → bool Verifica se qualsiasi elemento della raccolta soddisfa il predicato specificato. Se la funzione di input è predicato e gli elementi sono i0 ... iN, questa funzione calcola il predicato i0 o ... o il predicato iN.
filtro: ('T → bool) → Set <' T> → Set <'T> Restituisce una nuova raccolta contenente solo gli elementi della raccolta per cui restituisce il predicato specificato true.
fold: ('State →' T → 'State) →' State → Set <'T> →' State Applica la funzione di accumulazione data a tutti gli elementi dell'insieme.
foldBack: ('T →' State → 'State) → Set <' T> → 'State →' State Applica la funzione di accumulazione data a tutti gli elementi dell'insieme.
forall: ('T → bool) → Set <' T> → bool Verifica se tutti gli elementi della raccolta soddisfano il predicato specificato. Se la funzione di input è p e gli elementi sono i0 ... iN, questa funzione calcola p i0 && ... && p iN.
intersecare: Imposta <'T> → Imposta <' T> → Imposta <'T> Calcola l'intersezione dei due insiemi.
intersectMany: seq <Set <'T >> → Set <' T> Calcola l'intersezione di una sequenza di insiemi. La sequenza non deve essere vuota.
isEmpty: Set <'T> → bool ritorna true se il set è vuoto.
isProperSubset: Set <'T> → Set <' T> → bool Valuta a true se tutti gli elementi del primo insieme sono nel secondo e almeno un elemento del secondo non è nel primo.
isProperSuperset: Set <'T> → Set <' T> → bool Valuta a true se tutti gli elementi del secondo insieme sono nel primo e almeno un elemento del primo non è nel secondo.
isSubset: Set <'T> → Set <' T> → bool Valuta a true se tutti gli elementi del primo insieme sono nel secondo.
isSuperset: Set <'T> → Set <' T> → bool Valuta a true se tutti gli elementi del secondo insieme sono nel primo.
iter: ('T → unit) → Set <' T> → unit Applica la funzione data a ciascun elemento dell'insieme, in ordine in base alla funzione di confronto.
mappa: ('T →' U) → Imposta <'T> → Imposta <' U> Restituisce una nuova raccolta contenente i risultati dell'applicazione della funzione data a ciascun elemento del set di input.
maxElement: Set <'T> →' T Restituisce l'elemento più alto nel set in base all'ordine utilizzato per il set.
minElement: Set <'T> →' T Restituisce l'elemento più basso nel set in base all'ordine utilizzato per il set.
ofArray: 'T array → Imposta <' T> Crea un set che contiene gli stessi elementi dell'array specificato.
ofList: 'T list → Imposta <' T> Crea un insieme che contiene gli stessi elementi dell'elenco fornito.
ofSeq: seq <'T> → Imposta <' T> Crea una nuova raccolta dall'oggetto enumerabile specificato.
partizione: ('T → bool) → Set <' T> → Set <'T> * Set <' T> Divide l'insieme in due insiemi contenenti gli elementi per i quali il predicato dato restituisce rispettivamente vero e falso.
rimuovi: 'T → Imposta <' T> → Imposta <'T> Restituisce un nuovo set con l'elemento specificato rimosso. Non viene sollevata alcuna eccezione se l'insieme non contiene l'elemento dato.
singleton: 'T → Set <' T> L'insieme contenente l'elemento dato.
toArray: Imposta <'T> →' T array Crea un array che contiene gli elementi dell'insieme in ordine.
toList: Imposta <'T> →' T list Crea un elenco che contiene gli elementi dell'insieme in ordine.
toSeq: Imposta <'T> → seq <' T> Restituisce una visualizzazione ordinata della raccolta come oggetto enumerabile.
unione: Set <'T> → Set <' T> → Set <'T> Calcola l'unione dei due insiemi.
unionMany: seq <Set <'T >> → Set <' T> Calcola l'unione di una sequenza di insiemi.

L'esempio seguente mostra gli usi di alcune delle funzionalità di cui sopra:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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 #, una mappa è un tipo speciale di insieme che associa i valori a chiave. Una mappa viene creata in modo simile alla creazione degli insiemi.

Creazione di mappe

Le mappe vengono create creando una mappa vuota utilizzando Map.empty e aggiungendo elementi utilizzando la funzione Aggiungi. Il seguente esempio lo dimostra:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

È possibile accedere ai singoli elementi nella mappa utilizzando la chiave.

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Operazioni di base sulle mappe

Aggiungi il nome del modulo

La tabella seguente mostra le operazioni di base sulle mappe:

Membro Descrizione
Inserisci Restituisce una nuova mappa con l'associazione aggiunta alla mappa data.
ContainsKey Verifica se un elemento si trova nel dominio della mappa.
Contare Il numero di associazioni nella mappa.
È vuoto Restituisce vero se non ci sono associazioni nella mappa.
Articolo Cerca un elemento nella mappa. Genera KeyNotFoundException se non esiste alcuna associazione nella mappa.
Rimuovere Rimuove un elemento dal dominio della mappa. Non viene sollevata alcuna eccezione se l'elemento non è presente.
TryFind Cerca un elemento nella mappa, restituendo un file Some valore se l'elemento è nel dominio della mappa e None altrimenti.

L'esempio seguente mostra gli usi di alcune delle funzionalità di cui sopra:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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.

Le unioni, o unioni discriminate, consentono di creare strutture di dati complesse che rappresentano un insieme di scelte ben definito. Ad esempio, è necessario creare un'implementazione di una variabile di scelta , che ha due valori sì e no. Usando lo strumento Unions, puoi progettarlo.

Sintassi

Le unioni discriminate vengono definite utilizzando la seguente sintassi:

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

La nostra semplice implementazione di, choice, sarà simile alla seguente:

type choice =
   | Yes
   | No

L'esempio seguente utilizza la scelta del tipo -

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

Quando compili ed esegui il programma, restituisce il seguente output:

x: Yes
y: No

Esempio 1

L'esempio seguente mostra l'implementazione degli stati di tensione che impostano un po 'su alto o basso -

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Le variabili in F # sono immutable,il che significa che una volta che una variabile è associata a un valore, non può essere modificata. In realtà vengono compilati come proprietà statiche di sola lettura.

Il seguente esempio lo dimostra.

Esempio

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

Quando compili ed esegui il programma, viene visualizzato il seguente messaggio di errore:

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

Variabili mutabili

A volte è necessario modificare i valori memorizzati in una variabile. Per specificare che potrebbe esserci un cambiamento nel valore di una variabile dichiarata e assegnata nella parte successiva di un programma, F # fornisce ilmutableparola chiave. Puoi dichiarare e assegnare variabili mutabili utilizzando questa parola chiave, i cui valori cambierai.

Il mutable parola chiave consente di dichiarare e assegnare valori in una variabile mutabile.

È possibile assegnare un valore iniziale a una variabile mutabile utilizzando il letparola chiave. Tuttavia, per assegnargli un nuovo valore successivo, è necessario utilizzare il<- operatore.

Per esempio,

let mutable x = 10
x <- 15

Il seguente esempio chiarirà il concetto:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente 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

Usi di dati mutabili

I dati mutabili sono spesso richiesti e utilizzati nell'elaborazione dei dati, in particolare con la struttura dei dati dei record. Il seguente esempio lo dimostra:

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Gli array sono raccolte di dimensioni fisse, a base zero e modificabili di elementi di dati consecutivi che sono tutti dello stesso tipo.

Creazione di array

È possibile creare array utilizzando varie sintassi e modi o utilizzando le funzioni dal modulo Array. In questa sezione, discuteremo la creazione di array senza utilizzare le funzioni del modulo.

Esistono tre modi sintattici per creare array senza funzioni:

  • Elencando valori consecutivi compresi tra [| e |] e separati da punto e virgola.
  • Mettendo ogni elemento su una riga separata, nel qual caso il separatore punto e virgola è facoltativo.
  • Utilizzando espressioni di sequenza.

È possibile accedere agli elementi dell'array utilizzando un operatore punto (.) E parentesi ([e]).

L'esempio seguente mostra la creazione di array:

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Operazioni di base sugli array

Il modulo libreria Microsoft.FSharp.Collections.Array supporta operazioni su array unidimensionali.

La tabella seguente mostra le operazioni di base sugli array:

Valore Descrizione
aggiungi: 'T [] →' T [] → 'T [] Crea un array che contiene gli elementi di un array seguito dagli elementi di un altro array.
media: ^ T [] → ^ T Restituisce la media degli elementi in una matrice.
mediaBy: ('T → ^ U) →' T [] → ^ U Restituisce la media degli elementi generati applicando una funzione a ogni elemento di un array.
blit: 'T [] → int →' T [] → int → int → unit Legge un intervallo di elementi da un array e li scrive in un altro.
scegli: (opzione 'T → U) →' T [] → 'U [] Applica una funzione fornita a ogni elemento di un array. Restituisce un array che contiene i risultati x per ogni elemento per il quale la funzione restituisce Some (x).
raccogliere: ('T →' U []) → T [] → 'U [] Applica la funzione fornita a ogni elemento di una matrice, concatena i risultati e restituisce la matrice combinata.
concat: seq <'T []> →' T [] Crea un array che contiene gli elementi di ciascuna delle sequenze di array fornite.
copia: 'T →' T [] Crea un array che contiene gli elementi dell'array fornito.
creare: int → 'T →' T [] Crea un array i cui elementi sono tutti inizialmente il valore fornito.
vuoto: "T [] Restituisce un array vuoto del tipo specificato.
esiste: ('T → bool) →' T [] → bool Verifica se qualsiasi elemento di un array soddisfa il predicato fornito.
esiste2: ('T1 →' T2 → bool) → 'T1 [] →' T2 [] → bool Verifica se qualsiasi coppia di elementi corrispondenti di due array soddisfa la condizione fornita.
riempimento: 'T [] → int → int →' T → unit Riempie un intervallo di elementi di una matrice con il valore fornito.
filtro: ('T → bool) →' T [] → 'T [] Restituisce una raccolta che contiene solo gli elementi della matrice fornita per cui restituisce la condizione fornita true.
trova: ('T → bool) →' T [] → 'T Restituisce il primo elemento per il quale restituisce la funzione fornita true. Genera KeyNotFoundException se non esiste alcun elemento di questo tipo.
findIndex: ('T → bool) →' T [] → int Restituisce l'indice del primo elemento in un array che soddisfa la condizione fornita. Genera KeyNotFoundException se nessuno degli elementi soddisfa la condizione.
fold: ('State →' T → 'State) →' State → 'T [] →' State Applica una funzione a ogni elemento di un array, inserendo un argomento dell'accumulatore attraverso il calcolo. Se la funzione di input è f e gli elementi dell'array sono i0 ... iN, questa funzione calcola f (... (fs i0) ...) iN.
fold2: ('State →' T1 → 'T2 →' State) → 'State →' T1 [] → 'T2 [] →' State Applica una funzione a coppie di elementi da due array forniti, da sinistra a destra, inserendo un argomento dell'accumulatore attraverso il calcolo. I due array di input devono avere la stessa lunghezza; in caso contrario, viene generata ArgumentException.
foldBack: ('T →' State → 'State) →' T [] → 'State →' State Applica una funzione a ogni elemento di un array, inserendo un argomento dell'accumulatore attraverso il calcolo. Se la funzione di input è f e gli elementi dell'array sono i0 ... iN, questa funzione calcola f i0 (... (f iN s)).
foldBack2: ('T1 →' T2 → 'State →' State) → 'T1 [] →' T2 [] → 'State →' State Applica una funzione a coppie di elementi da due array forniti, da destra a sinistra, inserendo un argomento dell'accumulatore attraverso il calcolo. I due array di input devono avere la stessa lunghezza; in caso contrario, viene generata ArgumentException.
forall: ('T → bool) →' T [] → bool Verifica se tutti gli elementi di un array soddisfano la condizione fornita.
forall2: ('T1 →' T2 → bool) → 'T1 [] →' T2 [] → bool Verifica se tutti gli elementi corrispondenti di due array forniti soddisfano una condizione fornita.
ottieni: 'T [] → int →' T Ottiene un elemento da una matrice.
init: int → (int → 'T) →' T [] Utilizza una funzione fornita per creare un array della dimensione fornita.
isEmpty: 'T [] → bool Verifica se un array contiene elementi.
iter: ('T → unit) →' T [] → unit Applica la funzione fornita a ogni elemento di un array.
iter2: ('T1 →' T2 → unità) → 'T1 [] →' T2 [] → unità) Applica la funzione fornita a una coppia di elementi da indici corrispondenti in due matrici. I due array devono avere la stessa lunghezza; in caso contrario, viene generata ArgumentException.
iteri: (int → 'T → unit) →' T [] → unit Applica la funzione fornita a ogni elemento di un array. L'intero passato alla funzione indica l'indice dell'elemento.
iteri2: (int → 'T1 →' T2 → unit) → 'T1 [] →' T2 [] → unit Applica la funzione fornita a una coppia di elementi da indici corrispondenti in due matrici, passando anche l'indice degli elementi. I due array devono avere la stessa lunghezza; in caso contrario, viene generata un'eccezione ArgumentException.
lunghezza: 'T [] → int Restituisce la lunghezza di un array. La proprietà Length fa la stessa cosa.
mappa: ('T →' U) → 'T [] →' U [] Crea un array i cui elementi sono il risultato dell'applicazione della funzione fornita a ciascuno degli elementi di un array fornito.
map2: ('T1 →' T2 → 'U) →' T1 [] → 'T2 [] →' U [] Crea un array i cui elementi sono il risultato dell'applicazione della funzione fornita agli elementi corrispondenti di due array forniti. I due array di input devono avere la stessa lunghezza; in caso contrario, viene generata ArgumentException.
mapi: (int → 'T →' U) → 'T [] →' U [] Crea un array i cui elementi sono il risultato dell'applicazione della funzione fornita a ciascuno degli elementi di un array fornito. Un indice intero passato alla funzione indica l'indice dell'elemento trasformato.
mapi2: (int → 'T1 →' T2 → 'U) →' T1 [] → 'T2 [] →' U [] Crea un array i cui elementi sono il risultato dell'applicazione della funzione fornita agli elementi corrispondenti delle due collezioni a coppie, passando anche l'indice degli elementi. I due array di input devono avere la stessa lunghezza; in caso contrario, viene generata ArgumentException.
max: 'T [] →' T Restituisce il più grande di tutti gli elementi di un array. Operators.max viene utilizzato per confrontare gli elementi.
maxBy: ('T →' U) → 'T [] →' T Restituisce il più grande di tutti gli elementi di un array, confrontato tramite Operators.max sul risultato della funzione.
min: ('T [] →' T Restituisce il più piccolo di tutti gli elementi di un array. Operators.min viene utilizzato per confrontare gli elementi.
minBy: ('T →' U) → 'T [] →' T Restituisce il più piccolo di tutti gli elementi di un array. Operators.min viene utilizzato per confrontare gli elementi.
ofList: 'T list →' T [] Crea un array dall'elenco fornito.
ofSeq: seq <'T> →' T [] Crea un array dall'oggetto enumerabile fornito.
partizione: ('T → bool) →' T [] → 'T [] *' T [] Divide un array in due array, uno contenente gli elementi per i quali restituisce la condizione fornita true, e l'altra contenente quelli per cui ritorna false.
permuto: (int → int) → 'T [] →' T [] Permuta gli elementi di un array in base alla permutazione specificata.
scegli: (opzione 'T →' U) → 'T [] →' U Applica la funzione fornita agli elementi successivi di un array fornito, restituendo il primo risultato in cui la funzione restituisce Some (x) per alcuni x. Se la funzione non restituisce mai Some (x), viene generata KeyNotFoundException.
ridurre: ('T →' T → 'T) →' T [] → 'T Applica una funzione a ogni elemento di un array, inserendo un argomento dell'accumulatore attraverso il calcolo. Se la funzione di input è f e gli elementi dell'array sono i0 ... iN, questa funzione calcola f (... (f i0 i1) ...) iN. Se la matrice ha dimensione zero, viene generata ArgumentException.
reduceBack: ('T →' T → 'T) →' T [] → 'T Applica una funzione a ogni elemento di un array, inserendo un argomento dell'accumulatore attraverso il calcolo. Se la funzione di input è f e gli elementi sono i0 ... iN, questa funzione calcola f i0 (... (f iN-1 iN)). Se la matrice ha dimensione zero, viene generata ArgumentException.
rev: 'T [] →' T [] Inverte l'ordine degli elementi in una matrice fornita.
scansione: ('State →' T → 'State) →' State → 'T [] →' State []) Si comporta come la piega, ma restituisce i risultati intermedi insieme ai risultati finali.
scanBack: ('T →' State → 'State) →' T [] → 'State →' State [] Si comporta come foldBack, ma restituisce i risultati intermedi insieme ai risultati finali.
impostare: 'T [] → int →' T → unità Imposta un elemento di un array.
ordina: 'T [] →' T [] Ordina gli elementi di un array e restituisce un nuovo array. Operators.compare viene utilizzato per confrontare gli elementi.
sortBy: ('T →' Key) → 'T [] →' T [] Ordina gli elementi di un array utilizzando la funzione fornita per trasformare gli elementi nel tipo su cui si basa l'operazione di ordinamento e restituisce un nuovo array. Operators.compare viene utilizzato per confrontare gli elementi.
sortInPlace: 'T [] → unit Ordina gli elementi di un array modificando l'array in posizione, utilizzando la funzione di confronto fornita. Operators.compare viene utilizzato per confrontare gli elementi.
sortInPlaceBy: ('T →' Key) → 'T [] → unit Ordina gli elementi di un array modificando l'array in posizione, utilizzando la proiezione fornita per le chiavi. Operators.compare viene utilizzato per confrontare gli elementi.
sortInPlaceWith: ('T →' T → int) → 'T [] → unit Ordina gli elementi di una matrice utilizzando la funzione di confronto fornita per modificare la matrice in posizione.
sortWith: ('T →' T → int) → 'T [] →' T [] Ordina gli elementi di un array utilizzando la funzione di confronto fornita e restituisce un nuovo array.
sub: 'T [] → int → int →' T [] Crea un array che contiene il sottointervallo fornito, specificato dall'indice iniziale e dalla lunghezza.
somma: 'T [] → ^ T Restituisce la somma degli elementi nell'array.
sumBy: ('T → ^ U) →' T [] → ^ U Restituisce la somma dei risultati generati applicando una funzione a ogni elemento di un array.
toList: 'T [] →' T list Converte la matrice fornita in un elenco.
toSeq: 'T [] → seq <' T> Visualizza l'array fornito come una sequenza.
tryFind: ('T → bool) →' T [] → 'T opzione Restituisce il primo elemento dell'array fornito per il quale restituisce la funzione fornita true. ritornaNone se tale elemento non esiste.
tryFindIndex: ('T → bool) →' T [] → int opzione Restituisce l'indice del primo elemento in un array che soddisfa la condizione fornita.
tryPick: (opzione 'T →' U) → 'T [] → opzione' U Applica la funzione fornita agli elementi successivi dell'array fornito e restituisce il primo risultato in cui la funzione restituisce Some (x) per alcuni x. Se la funzione non restituisce mai Some (x),None viene restituito.
decomprimere: ('T1 *' T2) [] → 'T1 [] *' T2 [] Divide un array di coppie di tuple in una tupla di due array.
unzip3: ('T1 *' T2 * 'T3) [] →' T1 [] * 'T2 [] *' T3 [] Divide una matrice di tuple di tre elementi in una tupla di tre matrici.
zeroCreate: int → 'T [] Crea un array i cui elementi sono inizialmente impostati sul valore predefinito Unchecked.defaultof <'T>.
zip: "T1 [] →" T2 [] → ("T1 *" T2) [] Combina due array in un array di tuple che hanno due elementi. I due array devono avere la stessa lunghezza; in caso contrario, viene generata ArgumentException.
zip3: 'T1 [] →' T2 [] → 'T3 [] → (' T1 * 'T2 * 113' T3) [] Combina tre array in un array di tuple che hanno tre elementi. I tre array devono avere la stessa lunghezza; in caso contrario, viene generata ArgumentException.

Nella sezione seguente vedremo gli usi di alcune di queste funzionalità.

Creazione di array utilizzando le funzioni

Il modulo Array fornisce diverse funzioni che creano un array da zero.

  • Il Array.empty la funzione crea un nuovo array vuoto.

  • Il Array.create funzione crea un array di una dimensione specificata e imposta tutti gli elementi su valori dati.

  • Il Array.init funzione crea un array, data una dimensione e una funzione per generare gli elementi.

  • Il Array.zeroCreate funzione crea un array in cui tutti gli elementi vengono inizializzati al valore zero.

  • Il Array.copy funzione crea un nuovo array che contiene gli elementi che vengono copiati da un array esistente.

  • Il Array.sub la funzione genera un nuovo array da un sottointervallo di un array.

  • Il Array.append funzione crea un nuovo array combinando due array esistenti.

  • Il Array.choose la funzione seleziona gli elementi di un array da includere in un nuovo array.

  • Il Array.collect funzione esegue una funzione specificata su ogni elemento dell'array di un array esistente, quindi raccoglie gli elementi generati dalla funzione e li combina in un nuovo array.

  • Il Array.concat funzione prende una sequenza di array e li combina in un singolo array.

  • Il Array.filter funzione accetta una funzione di condizione booleana e genera un nuovo array che contiene solo quegli elementi dell'array di input per i quali la condizione è vera.

  • Il Array.rev la funzione genera un nuovo array invertendo l'ordine di un array esistente.

I seguenti esempi dimostrano queste funzioni:

Esempio 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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Esempio 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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Ricerca di array

Il Array.find function accetta una funzione booleana e restituisce il primo elemento per il quale la funzione restituisce true, altrimenti solleva un'eccezione KeyNotFoundException.

Il Array.findIndex la funzione funziona in modo simile tranne che restituisce l'indice dell'elemento invece dell'elemento stesso.

Il seguente esempio lo dimostra.

Microsoft fornisce questo interessante esempio di programma, che trova il primo elemento nell'intervallo di un dato numero che è sia un quadrato perfetto che un cubo perfetto -

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Il List<'T> class rappresenta un elenco fortemente tipizzato di oggetti a cui è possibile accedere tramite indice.

È una controparte mutevole della classe List. È simile agli array, poiché è possibile accedervi da un indice, tuttavia, a differenza degli array, gli elenchi possono essere ridimensionati. Pertanto non è necessario specificare una dimensione durante la dichiarazione.

Creazione di un elenco modificabile

Gli elenchi vengono creati utilizzando il newparola chiave e chiamando il costruttore dell'elenco. Il seguente esempio lo dimostra:

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

La classe List (T)

La classe List (T) rappresenta un elenco di oggetti fortemente tipizzato a cui è possibile accedere tramite indice. Fornisce metodi per cercare, ordinare e manipolare gli elenchi.

Le seguenti tabelle forniscono le proprietà, i costruttori ei metodi della classe List (T) -

Proprietà

Proprietà Descrizione
Capacità Ottiene o imposta il numero totale di elementi che la struttura dati interna può contenere senza ridimensionamento.
Contare Ottiene il numero di elementi contenuti in List (T).
Articolo Ottiene o imposta l'elemento in corrispondenza dell'indice specificato.

Costruttori

Costruttore Descrizione
Elenco (T) () Inizializza una nuova istanza della classe List (T) che è vuota e ha la capacità iniziale predefinita.
Elenco (T) (IEnumerable (T)) Inizializza una nuova istanza della classe List (T) che contiene elementi copiati dalla raccolta specificata e ha una capacità sufficiente per contenere il numero di elementi copiati.
Elenco (T) (Int32) Inizializza una nuova istanza della classe List (T) che è vuota e ha la capacità iniziale specificata.

Metodo

Metodi Descrizione
Inserisci Aggiunge un oggetto alla fine della lista (T).
AddRange Aggiunge gli elementi della raccolta specificata alla fine di List (T).
AsReadOnly Restituisce un wrapper IList (T) di sola lettura per la raccolta corrente.
BinarySearch (T) Cerca un elemento nell'intero elenco ordinato (T) utilizzando l'operatore di confronto predefinito e restituisce l'indice in base zero dell'elemento.
BinarySearch (T, IComparer (T)) Cerca un elemento nell'intero elenco ordinato (T) utilizzando l'operatore di confronto specificato e restituisce l'indice in base zero dell'elemento.
BinarySearch (Int32, Int32, T, IComparer (T)) Cerca un elemento in un intervallo di elementi nell'elenco ordinato (T) utilizzando l'operatore di confronto specificato e restituisce l'indice in base zero dell'elemento.
Chiaro Rimuove tutti gli elementi dall'elenco (T).
Contiene Determina se un elemento si trova nell'elenco (T).
ConvertAll (TOutput) Converte gli elementi nell'elenco corrente (T) in un altro tipo e restituisce un elenco contenente gli elementi convertiti.
Copia a (T []) Copia l'intero List (T) in una matrice unidimensionale compatibile, a partire dall'inizio della matrice di destinazione.
Copia a (T [], Int32) Copia l'intero List (T) in una matrice unidimensionale compatibile, a partire dall'indice specificato della matrice di destinazione.
CopyTo (Int32, T [], Int32, Int32) Copia un intervallo di elementi da List (T) a una matrice unidimensionale compatibile, a partire dall'indice specificato della matrice di destinazione.
Uguale a (oggetto) Determina se l'oggetto specificato è uguale all'oggetto corrente. (Ereditato da Object.)
Esiste Determina se List (T) contiene elementi che soddisfano le condizioni definite dal predicato specificato.
Finalizza Consente a un oggetto di provare a liberare risorse ed eseguire altre operazioni di pulizia prima che venga recuperato dalla procedura di Garbage Collection (Ereditato da Object).
Trova Cerca un elemento che soddisfi le condizioni definite dal predicato specificato e restituisce la prima occorrenza all'interno dell'intero List (T).
Trova tutto Recupera tutti gli elementi che soddisfano le condizioni definite dal predicato specificato.
FindIndex (Predicate (T)) Cerca un elemento che soddisfi le condizioni definite dal predicato specificato e restituisce l'indice in base zero della prima occorrenza all'interno dell'intero List (T).
FindIndex (Int32, Predicate (T)) Cerca un elemento che soddisfi le condizioni definite dal predicato specificato e restituisce l'indice in base zero della prima occorrenza all'interno dell'intervallo di elementi nell'elenco (T) che si estende dall'indice specificato all'ultimo elemento.
FindIndex (Int32, Int32, Predicate (T)) Cerca un elemento che soddisfi le condizioni definite dal predicato specificato e restituisce l'indice in base zero della prima occorrenza all'interno dell'intervallo di elementi nell'elenco (T) che inizia dall'indice specificato e contiene il numero di elementi specificato.
FindLast Cerca un elemento che soddisfi le condizioni definite dal predicato specificato e restituisce l'ultima occorrenza all'interno dell'intero List (T).
FindLastIndex (Predicate (T)) Cerca un elemento che soddisfi le condizioni definite dal predicato specificato e restituisce l'indice in base zero dell'ultima occorrenza all'interno dell'intero List (T).
FindLastIndex (Int32, Predicate (T)) Cerca un elemento che soddisfi le condizioni definite dal predicato specificato e restituisce l'indice in base zero dell'ultima occorrenza all'interno dell'intervallo di elementi nell'elenco (T) che si estende dal primo elemento all'indice specificato.
FindLastIndex (Int32, Int32, Predicate (T)) Cerca un elemento che soddisfi le condizioni definite dal predicato specificato e restituisce l'indice in base zero dell'ultima occorrenza all'interno dell'intervallo di elementi nell'elenco (T) che contiene il numero di elementi specificato e termina in corrispondenza dell'indice specificato.
Per ciascuno Esegue l'azione specificata su ogni elemento di List (T).
GetEnumerator Restituisce un enumeratore che itera attraverso List (T).
GetHashCode Serve come funzione hash predefinita. (Ereditato da Object.)
GetRange Crea una copia superficiale di un intervallo di elementi nell'elenco di origine (T).
GetType Ottiene il Type dell'istanza corrente. (Ereditato da Object.)
IndexOf (T) Cerca l'oggetto specificato e restituisce l'indice in base zero della prima occorrenza all'interno dell'intero List (T).
IndexOf (T, Int32) Cerca l'oggetto specificato e restituisce l'indice in base zero della prima occorrenza all'interno dell'intervallo di elementi nell'elenco (T) che si estende dall'indice specificato all'ultimo elemento.
IndexOf (T, Int32, Int32) Cerca l'oggetto specificato e restituisce l'indice in base zero della prima occorrenza all'interno dell'intervallo di elementi nell'elenco (T) che inizia dall'indice specificato e contiene il numero di elementi specificato.
Inserire Inserisce un elemento in List (T) all'indice specificato.
InsertRange Inserisce gli elementi di una raccolta in List (T) in corrispondenza dell'indice specificato.
LastIndexOf (T) Cerca l'oggetto specificato e restituisce l'indice in base zero dell'ultima occorrenza all'interno dell'intero List (T).
LastIndexOf (T, Int32) Cerca l'oggetto specificato e restituisce l'indice in base zero dell'ultima occorrenza all'interno dell'intervallo di elementi nell'elenco (T) che si estende dal primo elemento all'indice specificato.
LastIndexOf (T, Int32, Int32) Cerca l'oggetto specificato e restituisce l'indice in base zero dell'ultima occorrenza all'interno dell'intervallo di elementi nell'elenco (T) che contiene il numero di elementi specificato e termina all'indice specificato.
MemberwiseClone Crea una copia superficiale dell'oggetto Object corrente. (Ereditato da Object.)
Rimuovere Rimuove la prima occorrenza di un oggetto specifico dall'elenco (T).
Rimuovi tutto Rimuove tutti gli elementi che soddisfano le condizioni definite dal predicato specificato.
RemoveAt Rimuove l'elemento in corrispondenza dell'indice specificato di List (T).
RemoveRange Rimuove un intervallo di elementi dall'elenco (T).
Inversione() Inverte l'ordine degli elementi nell'intera lista (T).
Reverse (Int32, Int32) Inverte l'ordine degli elementi nell'intervallo specificato.
Ordinare() Ordina gli elementi nell'intero List (T) utilizzando l'operatore di confronto predefinito.
Ordina (Confronto (T)) Ordina gli elementi nell'intero List (T) utilizzando il System specificato. Confronto (T).
Ordina (IComparer (T)) Ordina gli elementi nell'intero List (T) utilizzando l'operatore di confronto specificato.
Ordina (Int32, Int32, IComparer (T)) Ordina gli elementi in un intervallo di elementi in List (T) utilizzando l'operatore di confronto specificato.
ToArray Copia gli elementi di List (T) in un nuovo array.
Accordare Restituisce una stringa che rappresenta l'oggetto corrente. (Ereditato da Object.)
TrimExcess Imposta la capacità sul numero effettivo di elementi nell'elenco (T), se tale numero è inferiore a un valore di soglia.
TrueForAll Determina se ogni elemento in List (T) soddisfa le condizioni definite dal predicato specificato.

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Il Dictionary<'TKey, 'TValue> class è l'analogo mutabile della struttura dati della mappa F # e contiene molte delle stesse funzioni.

Ricapitolando dal capitolo Mappa in F #, una mappa è un tipo speciale di insieme che associa i valori alla chiave.

Creazione di un dizionario mutevole

I dizionari modificabili vengono creati utilizzando il newparola chiave e chiamando il costruttore dell'elenco. Il seguente esempio lo dimostra:

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

La classe Dictionary (TKey, TValue)

La classe Dictionary (TKey, TValue) rappresenta una raccolta di chiavi e valori.

Le seguenti tabelle forniscono le proprietà, i costruttori ei metodi della classe List (T) -

Proprietà

Proprietà Descrizione
Comparer Ottiene l'oggetto IEqualityComparer (T) utilizzato per determinare l'uguaglianza delle chiavi per il dizionario.
Contare Ottiene il numero di coppie chiave / valore contenute nel Dictionary (TKey, TValue).
Articolo Ottiene o imposta il valore associato alla chiave specificata.
Chiavi Ottiene una raccolta contenente le chiavi nel dizionario (TKey, TValue).
Valori Ottiene una raccolta contenente i valori in Dictionary (TKey, TValue).

Costruttori

Costruttori Descrizione
Dizionario (TKey, TValue) () Inizializza una nuova istanza di Dictionary(TKey, TValue) classe che è vuota, ha la capacità iniziale predefinita e utilizza l'operatore di confronto di uguaglianza predefinito per il tipo di chiave.
Dizionario (TKey, TValue) (IDictionary (TKey, TValue)) Inizializza una nuova istanza di Dictionary(TKey, TValue) classe che contiene elementi copiati dal file specificato IDictionary(TKey, TValue) e utilizza l'operatore di confronto di uguaglianza predefinito per il tipo di chiave.
Dizionario (TKey, TValue) (IEqualityComparer (TKey)) Inizializza una nuova istanza di Dictionary(TKey, TValue) che è vuota, ha la capacità iniziale predefinita e utilizza la classe IEqualityComparer(T).
Dizionario (TKey, TValue) (Int32) Inizializza una nuova istanza di Dictionary(TKey, TValue) class che è vuota, ha la capacità iniziale specificata e utilizza l'operatore di confronto di uguaglianza predefinito per il tipo di chiave.
Dizionario (TKey, TValue) (IDictionary (TKey, TValue), IEqualityComparer (TKey)) Inizializza una nuova istanza di Dictionary(TKey, TValue) classe che contiene elementi copiati dal file specificato IDictionary(TKey, TValue) e utilizza il file IEqualityComparer(T).
Dizionario (TKey, TValue) (Int32, IEqualityComparer (TKey)) Inizializza una nuova istanza di Dictionary(TKey, TValue) che è vuota, ha la capacità iniziale specificata e utilizza la classe IEqualityComparer(T).
Dizionario (TKey, TValue) (SerializationInfo, StreamingContext) Inizializza una nuova istanza di ictionary(TKey, TValue) classe con dati serializzati.

Metodi

Metodo Descrizione
Inserisci Aggiunge la chiave e il valore specificati al dizionario.
Chiaro Rimuove tutte le chiavi e i valori dal dizionario (TKey, TValue).
ContainsKey Determina se il Dictionary (TKey, TValue) contiene la chiave specificata.
ContainsValue Determina se il dizionario (TKey, TValue) contiene un valore specifico.
Uguale a (oggetto) Determina se l'oggetto specificato è uguale all'oggetto corrente. (Ereditato da Object.)
Finalizza Consente a un oggetto di provare a liberare risorse ed eseguire altre operazioni di pulizia prima che venga recuperato dalla procedura di Garbage Collection. (Ereditato da Object.)
GetEnumerator Restituisce un enumeratore che itera nel Dictionary (TKey, TValue).
GetHashCode Serve come funzione hash predefinita. (Ereditato da Object.)
GetObjectData Implementa l'interfaccia System.Runtime.Serialization.ISerializable e restituisce i dati necessari per serializzare l'istanza Dictionary (TKey, TValue).
GetType Ottiene il Type dell'istanza corrente. (Ereditato da Object.)
MemberwiseClone Crea una copia superficiale dell'oggetto Object corrente. (Ereditato da Object.)
OnDeserialization Implementa l'interfaccia System.Runtime.Serialization.ISerializable e genera l'evento di deserializzazione quando la deserializzazione è completa.
Rimuovere Rimuove il valore con la chiave specificata dal dizionario (TKey, TValue).
Accordare Restituisce una stringa che rappresenta l'oggetto corrente. (Ereditato da Object.)
TryGetValue Ottiene il valore associato alla chiave specificata.

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

L'uscita di ingresso di base include:

  • Leggere e scrivere nella console.
  • Lettura e scrittura su file.

Modulo Core.Printf

Abbiamo usato le funzioni printf e printfn per scrivere nella console. In questa sezione, esamineremo i dettagli diPrintf modulo di F #.

Oltre alle funzioni precedenti, il modulo Core.Printf di F # dispone di vari altri metodi per la stampa e la formattazione utilizzando% marker come segnaposto. La tabella seguente mostra i metodi con una breve descrizione:

Valore Descrizione
bprintf: StringBuilder → BuilderFormat <'T> →' T Stampa su un StringBuilder.
eprintf: TextWriterFormat <'T> →' T Stampa l'output formattato su stderr.
eprintfn: TextWriterFormat <'T> →' T Stampa l'output formattato su stderr, aggiungendo una nuova riga.
failwithf: StringFormat <'T,' Result> → 'T Stampa su un buffer di stringa e solleva un'eccezione con il risultato dato.
fprintf: TextWriter → TextWriterFormat <'T> →' T Stampa su uno scrittore di testo.
fprintfn: TextWriter → TextWriterFormat <'T> →' T Stampa su uno scrittore di testo, aggiungendo una nuova riga.
kbprintf: (unità → 'Risultato) → StringBuilder → BuilderFormat <' T, 'Risultato> →' T Come bprintf, ma chiama la funzione specificata per generare il risultato.
kfprintf: (unità → 'Risultato) → TextWriter → TextWriterFormat <' T, 'Risultato> →' T Come fprintf, ma chiama la funzione specificata per generare il risultato.
kprintf: (stringa → 'Risultato) → StringFormat <' T, 'Risultato> →' T Come printf, ma chiama la funzione specificata per generare il risultato. Ad esempio, questi consentono alla stampa di forzare uno scarico dopo che tutto l'output è stato immesso nel canale, ma non prima.
ksprintf: (stringa → 'Risultato) → StringFormat <' T, 'Risultato> →' T Come sprintf, ma chiama la funzione specificata per generare il risultato.
printf: TextWriterFormat <'T> →' T Stampa l'output formattato su stdout.
printfn: TextWriterFormat <'T> →' T Stampa l'output formattato su stdout, aggiungendo una nuova riga.
sprintf: StringFormat <'T> →' T Stampa su una stringa utilizzando un buffer di stringa interno e restituisce il risultato come stringa.

Specifiche di formato

Le specifiche di formato vengono utilizzate per formattare l'input o l'output, in base alle necessità dei programmatori.

Si tratta di stringhe con marcatori% che indicano segnaposto di formato.

La sintassi di un segnaposto di formato è:

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

Il type è interpretato come -

genere Descrizione
% b Formati a bool, formattato come true o false.
% c Formatta un carattere.
%S Formati a string, formattato come contenuto, senza interpretare alcun carattere di escape.
% d,% i Formatta qualsiasi tipo intero di base formattato come intero decimale, con segno se il tipo intero di base è firmato.
% u Formatta qualsiasi tipo intero di base formattato come numero intero decimale senza segno.
%X Formatta qualsiasi tipo intero di base formattato come intero esadecimale senza segno, utilizzando lettere minuscole da a a f.
%X Formatta qualsiasi tipo intero di base formattato come intero esadecimale senza segno, utilizzando le lettere maiuscole dalla A alla F.
% o Formatta qualsiasi tipo intero di base formattato come intero ottale senza segno.
% e,% E,% f,% F,% g,% G Formatta qualsiasi tipo di virgola mobile di base (float, float32) formattato utilizzando specifiche di formato a virgola mobile in stile C.
% e,% E Formatta un valore con segno avente la forma [-] d.dddde [segno] ddd dove d è una singola cifra decimale, dddd è una o più cifre decimali, ddd è esattamente tre cifre decimali e il segno è + o -.
% f Formatta un valore con segno avente la forma [-] dddd.dddd, dove dddd è una o più cifre decimali. Il numero di cifre prima della virgola decimale dipende dalla grandezza del numero e il numero di cifre dopo la virgola decimale dipende dalla precisione richiesta.
% g,% G Formatta un valore con segno stampato in formato f o e, a seconda di quale sia più compatto per il valore e la precisione dati.
% M Formatta un valore Decimal.
% O Formatta qualsiasi valore, stampato inscatolando l'oggetto e usando il suo ToString metodo.
% A,% + A Formatta qualsiasi valore, stampato con le impostazioni di layout predefinite. Usa% + A per stampare la struttura dei sindacati discriminati con rappresentazioni interne e private.
%un

Un identificatore di formato generale, richiede due argomenti. Il primo argomento è una funzione che accetta due argomenti: primo, un parametro di contesto del tipo appropriato per la funzione di formattazione data (ad esempio, un TextWriter) e secondo, un valore da stampare e che restituisce o restituisce il testo appropriato.

Il secondo argomento è il valore particolare da stampare.

% t Un identificatore di formato generale richiede un argomento: una funzione che accetta un parametro di contesto del tipo appropriato per la funzione di formattazione data (aTextWriter) e che restituisce o restituisce il testo appropriato. I tipi interi di base sonobyte, sbyte, int16, uint16, int32, uint32, int64, uint64, nativeint, e unativeint. I tipi di virgola mobile di base sono float e float32.

Il widthè un parametro opzionale. È un numero intero che indica la larghezza minima del risultato. Ad esempio,% 5d stampa un numero intero con almeno spazi di 5 caratteri.

Valido flags sono descritti nella tabella seguente -

Valore Descrizione
0 Specifica di aggiungere zeri invece di spazi per ottenere la larghezza richiesta.
- Specifica di giustificare a sinistra il risultato entro la larghezza specificata.
+ Specifica di aggiungere un carattere + se il numero è positivo (per far corrispondere un segno - per i numeri negativi).
' ' (spazio) Specifica di aggiungere uno spazio extra se il numero è positivo (per far corrispondere un segno - per i numeri negativi).
# Non valido.

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

La classe della console

Questa classe fa parte del framework .NET. Rappresenta i flussi di input, output e errore standard per le applicazioni della console.

Fornisce vari metodi per leggere e scrivere nella console. La tabella seguente mostra i metodi:

Metodo Descrizione
Beep () Riproduce il suono di un segnale acustico attraverso l'altoparlante della console.
Beep (Int32, Int32) Riproduce il suono di un segnale acustico di una frequenza e una durata specificate attraverso l'altoparlante della console.
Chiaro Cancella il buffer della console e la finestra della console corrispondente delle informazioni di visualizzazione.
MoveBufferArea (Int32, Int32, Int32, Int32, Int32, Int32) Copia un'area di origine specificata del buffer dello schermo in un'area di destinazione specificata.
MoveBufferArea (Int32, Int32, Int32, Int32, Int32, Int32, Char, ConsoleColor, ConsoleColor) Copia un'area di origine specificata del buffer dello schermo in un'area di destinazione specificata.
OpenStandardError () Acquisisce il flusso di errore standard.
OpenStandardError (Int32) Acquisisce il flusso di errore standard, che è impostato su una dimensione del buffer specificata.
OpenStandardInput () Acquisisce il flusso di input standard.
OpenStandardInput (Int32) Acquisisce il flusso di input standard, che è impostato su una dimensione del buffer specificata.
OpenStandardOutput () Acquisisce il flusso di output standard.
OpenStandardOutput (Int32) Acquisisce il flusso di output standard, che è impostato su una dimensione del buffer specificata.
Leggere Legge il carattere successivo dal flusso di input standard.
ReadKey () Ottiene il carattere o il tasto funzione successivo premuto dall'utente. Il tasto premuto viene visualizzato nella finestra della console.
ReadKey (booleano) Ottiene il carattere o il tasto funzione successivo premuto dall'utente. Il tasto premuto viene visualizzato facoltativamente nella finestra della console.
Linea di lettura Legge la riga di caratteri successiva dal flusso di input standard.
ResetColor Imposta i colori di primo piano e di sfondo della console sui valori predefiniti.
SetBufferSize Imposta l'altezza e la larghezza dell'area del buffer dello schermo sui valori specificati.
SetCursorPosition Imposta la posizione del cursore.
SetError Imposta la proprietà Error sull'oggetto TextWriter specificato .
SetIn Imposta la proprietà In sull'oggetto TextReader specificato .
SetOut Imposta la proprietà Out sull'oggetto TextWriter specificato .
SetWindowPosition Imposta la posizione della finestra della console rispetto al buffer dello schermo.
SetWindowSize Imposta l'altezza e la larghezza della finestra della console sui valori specificati.
Scrivi (booleano) Scrive la rappresentazione testuale del valore booleano specificato nel flusso di output standard.
Scrivi (Char) Scrive il valore del carattere Unicode specificato nel flusso di output standard.
Scrivi (Char []) Scrive la matrice specificata di caratteri Unicode nel flusso di output standard.
Scrivi (decimale) Scrive la rappresentazione testuale del valore Decimal specificato nel flusso di output standard.
Scrivi (doppia) Scrive la rappresentazione testuale del valore a virgola mobile e precisione doppia specificato nel flusso di output standard.
Scrivi (Int32) Scrive la rappresentazione testuale del valore intero con segno a 32 bit specificato nel flusso di output standard.
Scrivi (Int64) Scrive la rappresentazione testuale del valore intero con segno a 64 bit specificato nel flusso di output standard.
Scrivi (oggetto) Scrive la rappresentazione testuale dell'oggetto specificato nel flusso di output standard.
Scrivi (singolo) Scrive la rappresentazione testuale del valore a virgola mobile a precisione singola specificato nel flusso di output standard.
Scrivi (stringa) Scrive il valore di stringa specificato nel flusso di output standard.
Scrivi (UInt32) Scrive la rappresentazione testuale del valore intero senza segno a 32 bit specificato nel flusso di output standard.
Scrivi (UInt64) Scrive la rappresentazione testuale del valore intero senza segno a 64 bit specificato nel flusso di output standard.
Scrivi (stringa, oggetto) Scrive la rappresentazione testuale dell'oggetto specificato nel flusso di output standard utilizzando le informazioni sul formato specificate.
Scrivi (stringa, oggetto []) Scrive la rappresentazione testuale della matrice di oggetti specificata nel flusso di output standard utilizzando le informazioni sul formato specificate.
Scrivi (Char [], Int32, Int32) Scrive il sottoarray specificato di caratteri Unicode nel flusso di output standard.
Scrivi (stringa, oggetto, oggetto) Scrive la rappresentazione testuale degli oggetti specificati nel flusso di output standard utilizzando le informazioni sul formato specificate.
Scrivi (stringa, oggetto, oggetto, oggetto) Scrive la rappresentazione testuale degli oggetti specificati nel flusso di output standard utilizzando le informazioni sul formato specificate.
Scrivi (stringa, oggetto, oggetto, oggetto, oggetto) Scrive la rappresentazione testuale degli oggetti specificati e l'elenco dei parametri di lunghezza variabile nel flusso di output standard utilizzando le informazioni sul formato specificato.
Linea di scrittura() Scrive il terminatore di riga corrente nel flusso di output standard.
WriteLine (Boolean) Scrive la rappresentazione testuale del valore booleano specificato, seguita dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (Char) Scrive il carattere Unicode specificato, seguito dal terminatore di riga corrente, valore nel flusso di output standard.
WriteLine (Char []) Scrive la matrice specificata di caratteri Unicode, seguita dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (decimale) Scrive la rappresentazione testuale del valore Decimal specificato, seguita dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (Double) Scrive la rappresentazione testuale del valore a virgola mobile e precisione doppia specificato, seguita dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (Int32) Scrive la rappresentazione testuale del valore intero con segno a 32 bit specificato, seguita dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (Int64) Scrive la rappresentazione testuale del valore intero con segno a 64 bit specificato, seguita dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (oggetto) Scrive la rappresentazione testuale dell'oggetto specificato, seguita dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (Single) Scrive la rappresentazione testuale del valore a virgola mobile a precisione singola specificato, seguita dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (stringa) Scrive il valore di stringa specificato, seguito dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (UInt32) Scrive la rappresentazione testuale del valore intero senza segno a 32 bit specificato, seguita dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (UInt64) Scrive la rappresentazione testuale del valore intero senza segno a 64 bit specificato, seguito dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (String, Object) Scrive la rappresentazione testuale dell'oggetto specificato, seguita dal terminatore di riga corrente, nel flusso di output standard utilizzando le informazioni sul formato specificato.
WriteLine (String, Object []) Scrive la rappresentazione testuale della matrice di oggetti specificata, seguita dal terminatore di riga corrente, nel flusso di output standard utilizzando le informazioni sul formato specificato.
WriteLine (Char [], Int32, Int32) Scrive il sottoarray specificato di caratteri Unicode, seguito dal terminatore di riga corrente, nel flusso di output standard.
WriteLine (String, Object, Object) Scrive la rappresentazione testuale degli oggetti specificati, seguita dal terminatore di riga corrente, nel flusso di output standard utilizzando le informazioni sul formato specificato.
WriteLine (String, Object, Object, Object) Scrive la rappresentazione testuale degli oggetti specificati, seguita dal terminatore di riga corrente, nel flusso di output standard utilizzando le informazioni sul formato specificato.
WriteLine (String, Object, Object, Object, Object) Scrive la rappresentazione testuale degli oggetti specificati e l'elenco dei parametri di lunghezza variabile, seguita dal terminatore di riga corrente, nel flusso di output standard utilizzando le informazioni sul formato specificato.

L'esempio seguente mostra la lettura dalla console e la scrittura in essa:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Lo spazio dei nomi System.IO

Lo spazio dei nomi System.IO contiene una varietà di classi utili per eseguire operazioni di I / O di base.

Contiene tipi o classi che consentono la lettura e la scrittura su file e flussi di dati e tipi che forniscono supporto di base per file e directory.

Classi utili per lavorare con il file system -

  • La classe System.IO.File viene utilizzata per creare, aggiungere ed eliminare file.
  • La classe System.IO.Directory viene utilizzata per creare, spostare ed eliminare le directory.
  • La classe System.IO.Path esegue operazioni sulle stringhe, che rappresentano i percorsi dei file.
  • La classe System.IO.FileSystemWatcher consente agli utenti di ascoltare le modifiche in una directory.

Classi utili per lavorare con i flussi (sequenza di byte) -

  • La classe System.IO.StreamReader viene utilizzata per leggere i caratteri da un flusso.
  • La classe System.IO.StreamWriter viene utilizzata per scrivere caratteri in un flusso.
  • La classe System.IO.MemoryStream crea un flusso di byte in memoria.

La tabella seguente mostra tutte le classi fornite nello spazio dei nomi insieme a una breve descrizione:

Classe Descrizione
BinaryReader Legge i tipi di dati primitivi come valori binari in una codifica specifica.
BinaryWriter Scrive tipi primitivi in ​​binario in un flusso e supporta la scrittura di stringhe in una codifica specifica.
BufferedStream Aggiunge un livello di buffering per leggere e scrivere operazioni su un altro flusso.
Directory Espone metodi statici per la creazione, lo spostamento e l'enumerazione di directory e sottodirectory.
DirectoryInfo Espone i metodi di istanza per la creazione, lo spostamento e l'enumerazione tramite directory e sottodirectory.
DirectoryNotFoundException Eccezione generata quando non è possibile trovare una parte di un file o di una directory.
DriveInfo Fornisce accesso alle informazioni su un'unità.
DriveNotFoundException Eccezione generata quando si tenta di accedere a un'unità o una condivisione non disponibile.
EndOfStreamException Eccezione generata quando si tenta di leggere oltre la fine di un flusso.
ErrorEventArgs Fornisce dati per l'evento FileSystemWatcher.Error.
File Fornisce metodi statici per la creazione, la copia, l'eliminazione, lo spostamento e l'apertura di un singolo file e aiuta nella creazione di oggetti FileStream.
FileFormatException L'eccezione generata quando un file di input o un flusso di dati che dovrebbe essere conforme a una determinata specifica del formato di file non è corretto.
FileInfo Fornisce proprietà e metodi di istanza per la creazione, la copia, l'eliminazione, lo spostamento e l'apertura di file e aiuta nella creazione di oggetti FileStream.
FileLoadException Eccezione generata quando viene trovato un assembly gestito ma non può essere caricato.
FileNotFoundException Eccezione generata quando un tentativo di accedere a un file che non esiste su disco fallisce.
FileStream Espone un flusso attorno a un file, supportando operazioni di lettura e scrittura sincrone e asincrone.
FileSystemEventArgs Fornisce dati per gli eventi della directory: modificati, creati, eliminati.
FileSystemInfo Fornisce la classe base per gli oggetti FileInfo e DirectoryInfo.
FileSystemWatcher Ascolta le notifiche di modifica del file system e genera eventi quando una directory, o un file in una directory, cambia.
InternalBufferOverflowException Eccezione generata quando il buffer interno è in overflow.
InvalidDataException Eccezione generata quando un flusso di dati è in un formato non valido.
IODescriptionAttribute Imposta la descrizione che i designer di oggetti visivi possono visualizzare quando fanno riferimento a un evento, un extender o una proprietà.
IOException Eccezione generata quando si verifica un errore di I / O.
MemoryStream Crea un flusso il cui archivio di backup è la memoria.
Sentiero Esegue operazioni su istanze String che contengono informazioni sul percorso di file o directory. Queste operazioni vengono eseguite in modo multipiattaforma.
PathTooLongException Eccezione generata quando un percorso o un nome file è più lungo della lunghezza massima definita dal sistema.
PipeException Generato quando si verifica un errore all'interno di una named pipe.
RenamedEventArgs Fornisce dati per l'evento Renamed.
Stream Fornisce una visualizzazione generica di una sequenza di byte. Questa è una classe astratta.
StreamReader Implementa un TextReader che legge i caratteri da un flusso di byte in una particolare codifica.
StreamWriter Implementa un TextWriter per scrivere caratteri in un flusso in una particolare codifica. Per esplorare il codice sorgente di .NET Framework per questo tipo, vedere la fonte di riferimento.
StringReader Implementa un TextReader che legge da una stringa.
StringWriter Implementa un TextWriter per scrivere informazioni su una stringa. Le informazioni vengono archiviate in uno StringBuilder sottostante.
TextReader Rappresenta un lettore in grado di leggere una serie sequenziale di caratteri.
TextWriter Rappresenta uno scrittore in grado di scrivere una serie sequenziale di caratteri. Questa classe è astratta.
UnmanagedMemoryAccessor Fornisce accesso casuale a blocchi di memoria non gestiti dal codice gestito.
UnmanagedMemoryStream Fornisce accesso a blocchi di memoria non gestiti dal codice gestito.
WindowsRuntimeStorageExtensions Contiene metodi di estensione per le interfacce IStorageFile e IStorageFolder in Windows Runtime durante lo sviluppo di app di Windows Store.
WindowsRuntimeStreamExtensions Contiene metodi di estensione per la conversione tra flussi in Windows Runtime e flussi gestiti nelle app .NET per Windows Store.

Esempio

L'esempio seguente crea un file chiamato test.txt, vi scrive un messaggio, legge il testo dal file e lo stampa sulla console.

Note - La quantità di codice necessaria per farlo è sorprendentemente inferiore!

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

Quando compili ed esegui il programma, restituisce il seguente output:

Hello There
Welcome to:
Tutorials Point

I generici consentono di ritardare la specifica del tipo di dati degli elementi di programmazione in una classe o in un metodo, fino a quando non viene effettivamente utilizzato nel programma. In altre parole, i generici ti consentono di scrivere una classe o un metodo che può funzionare con qualsiasi tipo di dati.

Si scrivono le specifiche per la classe o il metodo, con parametri sostitutivi per i tipi di dati. Quando il compilatore incontra un costruttore per la classe o una chiamata di funzione per il metodo, genera codice per gestire il tipo di dati specifico.

In F #, i valori di funzione, i metodi, le proprietà e i tipi di aggregazione come classi, record e unioni discriminate possono essere generici.

I costrutti generici contengono almeno un parametro di tipo. Le funzioni ei tipi generici consentono di scrivere codice che funziona con una varietà di tipi senza ripetere il codice per ogni tipo.

Sintassi

La sintassi per scrivere un costrutto generico è la seguente:

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

Esempi

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

printFunc<float> 10.0 20.0

Quando compili ed esegui il programma, restituisce il seguente output:

10.0, 20.0

Puoi anche rendere generica una funzione utilizzando la sintassi delle virgolette singole:

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

printFunction 10.0 20.0

Quando compili ed esegui il programma, restituisce il seguente output:

10.0 20.0

Si noti che quando si utilizzano funzioni o metodi generici, potrebbe non essere necessario specificare gli argomenti del tipo. Tuttavia, in caso di ambiguità, è possibile fornire argomenti di tipo tra parentesi angolari come abbiamo fatto nel primo esempio.

Se hai più di un tipo, separa più argomenti di tipo con virgole.

Classe generica

Come le funzioni generiche, puoi anche scrivere classi generiche. Il seguente esempio lo dimostra:

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Un delegato è una variabile del tipo di riferimento che contiene il riferimento a un metodo. Il riferimento può essere modificato in fase di esecuzione. I delegati F # sono simili ai puntatori alle funzioni, in C o C ++.

Dichiarazione dei delegati

La dichiarazione del delegato determina i metodi a cui può fare riferimento il delegato. Un delegato può fare riferimento a un metodo, che ha la stessa firma di quella del delegato.

La sintassi per la dichiarazione del delegato è:

type delegate-typename = delegate of type1 -> type2

Ad esempio, considera i delegati:

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

Entrambi i delegati possono essere utilizzati per fare riferimento a qualsiasi metodo che abbia due parametri int e restituisca una variabile di tipo int .

Nella sintassi -

  • type1 rappresenta il / i tipo / i di argomento.

  • type2 rappresenta il tipo restituito.

Nota:

  • I tipi di argomenti vengono automaticamente selezionati.

  • I delegati possono essere associati a valori di funzione e metodi statici o di istanza.

  • I valori della funzione F # possono essere passati direttamente come argomenti ai costruttori delegati.

  • Per un metodo statico, il delegato viene chiamato utilizzando il nome della classe e il metodo. Per un metodo di istanza, viene utilizzato il nome dell'istanza di oggetto e del metodo.

  • Il metodo Invoke sul tipo delegato chiama la funzione incapsulata.

  • Inoltre, i delegati possono essere passati come valori di funzione facendo riferimento al nome del metodo Invoke senza parentesi.

Il seguente esempio dimostra il concetto:

Esempio

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)

Quando compili ed esegui il programma, restituisce il seguente output:

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

Un'enumerazione è un insieme di costanti intere denominate.

In F #, enumerations, conosciuto anche come enums,sono tipi integrali in cui le etichette sono assegnate a un sottoinsieme di valori. Puoi usarli al posto dei letterali per rendere il codice più leggibile e gestibile.

Dichiarazione di enumerazioni

La sintassi generale per dichiarare un'enumerazione è:

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

L'esempio seguente dimostra l'uso di enumerazioni:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

Monday: Mon
Saturday: Sat
Sunday: Sun

La corrispondenza dei modelli consente di "confrontare i dati con una o più strutture logiche, scomporre i dati in parti costituenti o estrarre informazioni dai dati in vari modi".

In altri termini, fornisce un modo più flessibile e potente per testare i dati rispetto a una serie di condizioni ed eseguire alcuni calcoli basati sulla condizione soddisfatta.

Concettualmente, è come una serie di affermazioni if ​​... then.

Sintassi

In termini di alto livello, la corrispondenza dei modelli segue questa sintassi in F # -

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

Dove,

  • Ogni | il simbolo definisce una condizione.
  • Il simbolo -> significa "se la condizione è vera, restituisci questo valore ...".
  • Il simbolo _ fornisce il modello predefinito, il che significa che corrisponde a tutte le altre cose come un carattere jolly.

Esempio 1

L'esempio seguente calcola i numeri di Fibonacci utilizzando la sintassi del pattern matching:

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)

Quando compili ed esegui il programma, restituisce il seguente output:

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

Puoi anche concatenare più condizioni, che restituiscono lo stesso valore. Ad esempio:

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

Quando compili ed esegui il programma, restituisce il seguente output:

Winter
Spring
Autumn
Rainy

Funzioni di corrispondenza dei modelli

F # consente di scrivere funzioni di corrispondenza dei modelli usando il function parola chiave -

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

Quando compili ed esegui il programma, restituisce il seguente output:

10
20.5
21
8.75
15

Aggiunta di filtri o protezioni ai modelli

Puoi aggiungere filtri, o protezioni, ai pattern utilizzando when parola chiave.

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

Quando compili ed esegui il programma, restituisce il seguente output:

-1
1
0

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Pattern Matching con tuple

L'esempio seguente mostra la corrispondenza del modello con le tuple:

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Pattern Matching con i record

L'esempio seguente mostra la corrispondenza del modello con i record:

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 }

Quando compili ed esegui il programma, restituisce il seguente output:

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

Un'eccezione è un problema che sorge durante l'esecuzione di un programma. Un'eccezione F # è una risposta a una circostanza eccezionale che si verifica durante l'esecuzione di un programma, ad esempio un tentativo di divisione per zero.

Le eccezioni forniscono un modo per trasferire il controllo da una parte all'altra di un programma. La gestione delle eccezioni F # fornisce i seguenti costrutti:

Costruire Descrizione
aumentare expr Genera l'eccezione data.
failwith expr Alza il System.Exception eccezione.
prova expr con le regole Cattura le espressioni che corrispondono alle regole del modello.
prova infine expr expr Esecuzione del finally espressione sia quando il calcolo ha esito positivo sia quando viene sollevata un'eccezione.
| :? ArgumentException Una regola che corrisponde al tipo di eccezione .NET specificato.
| :? ArgumentException come e Una regola che corrisponde al tipo di eccezione .NET specificato, che lega il nome e al valore dell'oggetto eccezione.
| Errore (msg) → expr Una regola che corrisponde all'eccezione F # di trasporto dati specificata.
| exn → expr Una regola che corrisponde a qualsiasi eccezione, vincolando il nome exn al valore dell'oggetto eccezione.
| exn quando expr → expr Una regola che corrisponde all'eccezione alla condizione data, vincolando il nome exn al valore dell'oggetto eccezione.

Cominciamo con la sintassi di base della gestione delle eccezioni.

Sintassi

La sintassi di base per il blocco di gestione delle eccezioni F # è:

exception exception-type of argument-type

Dove,

  • exception-type è il nome di un nuovo tipo di eccezione F #.

  • argument-type rappresenta il tipo di un argomento che può essere fornito quando si solleva un'eccezione di questo tipo.

  • È possibile specificare più argomenti utilizzando un tipo di tupla per il tipo di argomento.

Il try...with espressione viene utilizzata per la gestione delle eccezioni nel linguaggio F #.

La sintassi per il tentativo ... con l'espressione è -

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

Il try...finally espressione consente di eseguire il codice di ripulitura anche se un blocco di codice genera un'eccezione.

Sintassi per il tentativo ... finalmente l'espressione è -

try
   expression1
finally
   expression2

Il raiseviene utilizzata per indicare che si è verificato un errore o una condizione eccezionale. Cattura anche le informazioni sull'errore in un oggetto eccezione.

La sintassi per la funzione raise è -

raise (expression)

Il failwith la funzione genera un'eccezione F #.

La sintassi per la funzione failwith è:

failwith error-message-string

Il invalidArg la funzione genera un'eccezione di argomento.

invalidArg parameter-name error-message-string

Esempio di gestione delle eccezioni

Esempio 1

Il seguente programma mostra la gestione delle eccezioni di base con un semplice tentativo ... con blocco -

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

let result1 = divisionprog 100 0

Quando compili ed esegui il programma, restituisce il seguente output:

Division by zero!

Esempio 2

F # fornisce un file exceptiontipo per la dichiarazione delle eccezioni. È possibile utilizzare un tipo di eccezione direttamente nei filtri in un filetry...with espressione.

Il seguente esempio lo dimostra:

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

Quando compili ed esegui il programma, restituisce il seguente output:

Error2 Error Not detected 100
Error1 Equal Number Error

Esempio 3

L'esempio seguente mostra la gestione delle eccezioni annidate:

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Esempio 4

La seguente funzione mostra il failwith funzione -

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

Quando compili ed esegui il programma, restituisce il seguente output:

Divisor cannot be zero.
0
25

Esempio 5

Il invalidArgla funzione genera un'eccezione di argomento. Il seguente programma lo dimostra:

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)

Quando compili ed esegui il programma, restituisce il seguente output:

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

Verranno visualizzate anche alcune altre informazioni sul file e sulla variabile che causano l'errore nel sistema, a seconda del sistema.

Le classi sono tipi che rappresentano oggetti che possono avere proprietà, metodi ed eventi. "Sono utilizzati per modellare azioni, processi e qualsiasi entità concettuale nelle applicazioni".

Sintassi

La sintassi per definire un tipo di classe è la seguente:

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

Dove,

  • Il type-nameè un identificatore valido. Il modificatore di accesso predefinito per questo èpublic.

  • Il type-params descrive parametri di tipo generico facoltativo.

  • Il parameter-listdescrive i parametri del costruttore. Il modificatore di accesso predefinito per il costruttore principale èpublic.

  • Il identifier utilizzato con l'opzionale as parola chiave dà un nome alla variabile di istanza, o self-identifier, che può essere utilizzato nella definizione del tipo per fare riferimento all'istanza del tipo.

  • Il inherit parola chiave consente di specificare la classe di base per una classe.

  • Il let i collegamenti consentono di dichiarare campi o valori di funzioni locali alla classe.

  • Il do-bindings la sezione include il codice da eseguire sulla costruzione dell'oggetto.

  • Il member-list è costituito da costruttori aggiuntivi, dichiarazioni di istanze e metodi statici, dichiarazioni di interfaccia, associazioni astratte e dichiarazioni di proprietà ed eventi.

  • Le parole chiave class e end che segnano l'inizio e la fine della definizione sono facoltativi.

Costruttore di una classe

Il costruttore è il codice che crea un'istanza del tipo di classe.

In F #, i costruttori funzionano in modo leggermente diverso dagli altri linguaggi .Net. Nella definizione della classe, gli argomenti del costruttore principale sono descritti come elenco di parametri.

Il corpo del costruttore è costituito da let e do attacchi.

È possibile aggiungere ulteriori costruttori utilizzando la nuova parola chiave per aggiungere un membro:

new (argument-list) = constructor-body

L'esempio seguente illustra il concetto:

Esempio

Il seguente programma crea una classe di linea insieme a un costruttore che calcola la lunghezza della linea mentre viene creato un oggetto della classe -

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)

Quando compili ed esegui il programma, restituisce il seguente output:

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

Lascia che Bindings

Le associazioni let in una definizione di classe consentono di definire campi privati ​​e funzioni private per le classi F #.

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

Quando compili ed esegui il programma, restituisce il seguente output:

Hello Zara

Si prega di notare l'uso dell'autoidentificatore gr per la classe Greetings .

Una struttura in F # è un tipo di dati di tipo valore. Ti aiuta a creare una singola variabile, a conservare i dati correlati di vari tipi di dati. Ilstruct la parola chiave viene utilizzata per creare una struttura.

Sintassi

La sintassi per definire una struttura è la seguente:

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

Esistono due sintassi. La prima sintassi viene utilizzata principalmente, perché, se si utilizza l'estensionestruct e end parole chiave, puoi omettere il StructAttribute attributo.

Gli elementi di definizione della struttura forniscono:

  • Dichiarazioni e definizioni dei membri.
  • Costruttori e campi mutabili e immutabili.
  • Membri e implementazioni dell'interfaccia.

A differenza delle classi, le strutture non possono essere ereditate e non possono contenere associazioni let o do. Da allora, le strutture non hanno lasciato legami; è necessario dichiarare i campi nelle strutture utilizzando ilval parola chiave.

Quando si definisce un campo e il suo tipo utilizzando valparola chiave, non è possibile inizializzare il valore del campo, ma vengono inizializzati a zero o null. Quindi, per una struttura con un costruttore implicito, ilval le dichiarazioni devono essere annotate con il DefaultValue attributo.

Esempio

Il seguente programma crea una struttura a linee insieme a un costruttore. Il programma calcola la lunghezza di una linea utilizzando la struttura -

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

Quando compili ed esegui il programma, restituisce il seguente output:

Length of the Line: 5

È possibile ridefinire o sovraccaricare la maggior parte degli operatori incorporati disponibili in F #. Pertanto un programmatore può utilizzare anche operatori con tipi definiti dall'utente.

Gli operatori sono funzioni con nomi speciali, racchiusi tra parentesi. Devono essere definiti come membri di una classe statica. Come qualsiasi altra funzione, un operatore sovraccarico ha un tipo restituito e un elenco di parametri.

L'esempio seguente mostra un operatore + su numeri complessi -

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

La funzione precedente implementa l'operatore di addizione (+) per una classe Complex definita dall'utente. Aggiunge gli attributi di due oggetti e restituisce l'oggetto Complex risultante.

Implementazione del sovraccarico dell'operatore

Il seguente programma mostra l'implementazione completa:

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

Quando compili ed esegui il programma, restituisce il seguente output:

7 5
4.2 3.1
11.2 8.1
2.8 1.9

Uno dei concetti più importanti nella programmazione orientata agli oggetti è quello dell'ereditarietà. L'ereditarietà ci consente di definire una classe in termini di un'altra classe, il che semplifica la creazione e la manutenzione di un'applicazione. Ciò offre anche l'opportunità di riutilizzare la funzionalità del codice e tempi di implementazione rapidi.

Quando si crea una classe, invece di scrivere membri dati e funzioni membro completamente nuovi, il programmatore può designare che la nuova classe erediti i membri di una classe esistente. Questa classe esistente viene chiamata classe base e la nuova classe viene definita classe derivata.

L'idea di eredità implementa la relazione IS-A. Ad esempio, il mammifero è un animale, il cane è un mammifero quindi anche il cane è un animale e così via.

Classe di base e sottoclasse

Una sottoclasse è derivata da una classe base, che è già definita. Una sottoclasse eredita i membri della classe di base e dispone dei propri membri.

Una sottoclasse viene definita utilizzando il inherit parola chiave come mostrato di seguito -

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

In F # una classe può avere al massimo una classe base diretta. Se non si specifica una classe di base utilizzando ilinherit parola chiave, la classe eredita implicitamente da Object.

Nota:

  • I metodi ei membri della classe base sono disponibili per gli utenti della classe derivata come i membri diretti della classe derivata.

  • Lascia che i collegamenti ei parametri del costruttore siano privati ​​di una classe e, pertanto, non è possibile accedervi dalle classi derivate.

  • La parola chiave basesi riferisce all'istanza della classe base. È usato come l'identificatore di sé.

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Metodi di sostituzione

È possibile sovrascrivere un comportamento predefinito di un metodo della classe base e implementarlo in modo diverso nella sottoclasse o nella classe derivata.

I metodi in F # non possono essere sovrascritti per impostazione predefinita.

Per sovrascrivere i metodi in una classe derivata, devi dichiarare il tuo metodo come sovrascrivibile usando il abstract e default parole chiave come segue:

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

Ora, il metodo Greet della classe Person può essere sovrascritto nelle classi derivate. Il seguente esempio lo dimostra:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

Hi, I'm Mohan
Student Zara
Teacher Mariam.

Classe astratta

A volte è necessario fornire un'implementazione incompleta di un oggetto, che non dovrebbe essere implementata nella realtà. Successivamente, qualche altro programmatore dovrebbe creare sottoclassi della classe astratta per un'implementazione completa.

Ad esempio, la classe Persona non sarà necessaria in un sistema di gestione scolastica. Tuttavia, sarà necessaria la classe Studente o Insegnante. In questi casi, puoi dichiarare la classe Person come classe astratta.

Il AbstractClass attributo dice al compilatore che la classe ha alcuni membri astratti.

Non è possibile creare un'istanza di una classe astratta perché la classe non è completamente implementata.

Il seguente esempio lo dimostra:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

Student Zara
Teacher Mariam.

Le interfacce forniscono un modo astratto per scrivere i dettagli di implementazione di una classe. È un modello che dichiara i metodi che la classe deve implementare ed esporre pubblicamente.

Sintassi

Un'interfaccia specifica i set di membri correlati implementati da altre classi. Ha la seguente sintassi:

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

Nota:

  • In una dichiarazione di interfaccia i membri non sono implementati.

  • I membri sono astratti, dichiarati dal abstractparola chiave. Tuttavia è possibile fornire un'implementazione predefinita utilizzando ildefault parola chiave.

  • È possibile implementare le interfacce utilizzando espressioni di oggetti o utilizzando tipi di classe.

  • Nell'implementazione di una classe o di un oggetto, è necessario fornire i corpi dei metodi per i metodi astratti dell'interfaccia.

  • Le parole chiave interface e end, che segnano l'inizio e la fine della definizione, sono facoltativi.

Per esempio,

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

Richiamo dei metodi di interfaccia

I metodi di interfaccia vengono chiamati tramite l'interfaccia, non tramite l'istanza della classe o il tipo che implementa l'interfaccia. Per chiamare un metodo di interfaccia, eseguire il cast al tipo di interfaccia utilizzando il:> operatore (operatore upcast).

Per esempio,

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

L'esempio seguente illustra il concetto:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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

Ereditarietà dell'interfaccia

Le interfacce possono ereditare da una o più interfacce di base.

L'esempio seguente mostra il concetto:

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

Quando compili ed esegui il programma, restituisce il seguente output:

10
15
5

Gli eventi consentono alle classi di inviare e ricevere messaggi tra loro.

Nella GUI, gli eventi sono azioni dell'utente come la pressione di un tasto, i clic, i movimenti del mouse, ecc. O alcuni eventi come le notifiche generate dal sistema. Le applicazioni devono rispondere agli eventi quando si verificano. Ad esempio, interrompe. Gli eventi vengono utilizzati per la comunicazione tra processi.

Gli oggetti comunicano tra loro tramite il passaggio di messaggi sincrono.

Gli eventi sono associati ad altre funzioni; registro oggetticallback funzioni a un evento e questi callback vengono eseguiti quando (e se) l'evento viene attivato da un oggetto.

La classe di eventi e il modulo di eventi

La classe Control.Event <'T> aiuta nella creazione di un oggetto o evento osservabile.

Ha i seguenti membri di istanza per lavorare con gli eventi:

Membro Descrizione
Pubblicare Pubblica un'osservazione come valore di prima classe.
Trigger Attiva un'osservazione utilizzando i parametri forniti.

Il modulo Control.Event fornisce funzioni per la gestione dei flussi di eventi:

Valore Descrizione
aggiungi: ('T → unit) → Event <' Del, 'T> → unit Esegue la funzione data ogni volta che viene attivato l'evento specificato.
scegli: (opzione 'T →' U) → IEvent <'Del,' T> → IEvent <'U> Restituisce un nuovo evento che si attiva su una selezione di messaggi dall'evento originale. La funzione di selezione trasforma un messaggio originale in un nuovo messaggio opzionale.
filtro: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> Restituisce un nuovo evento che ascolta l'evento originale e attiva l'evento risultante solo quando l'argomento dell'evento supera la funzione data.
mappa: ('T →' U) → IEvent <'Del,' T> → IEvent <'U> Restituisce un nuovo evento che passa valori trasformati dalla funzione data.
unione: IEvent <'Del1,' T> → IEvent <'Del2,' T> → IEvent <'T> Genera l'evento di output quando uno degli eventi di input viene attivato.
pairwise: IEvent <'Del,' T> → IEvent <'T *' T> Restituisce un nuovo evento che si attiva alla seconda e successiva attivazione dell'evento di input. IlNth l'attivazione dell'evento di input passa gli argomenti dal file N-1th e Nthinnescando in coppia. L'argomento è passato alN-1th l'attivazione viene mantenuta in uno stato interno nascosto fino a quando il Nth si verifica il trigger.
partizione: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> * IEvent <'T> Restituisce un nuovo evento che ascolta l'evento originale e attiva il primo evento risultante se l'applicazione del predicato agli argomenti dell'evento ha restituito true e il secondo evento se ha restituito false.
scansione: ('U →' T → 'U) →' U → IEvent <'Del,' T> → IEvent <'U> Restituisce un nuovo evento costituito dai risultati dell'applicazione della funzione di accumulazione data a valori successivi attivati ​​sull'evento di input. Un elemento di stato interno registra il valore corrente del parametro di stato. Lo stato interno non è bloccato durante l'esecuzione della funzione di accumulazione, quindi è necessario prestare attenzione che l'ingresso IEvent non venga attivato da più thread contemporaneamente.
split: ('T → Choice <' U1, 'U2>) → IEvent <' Del, 'T> → IEvent <' U1> * IEvent <'U2> Restituisce un nuovo evento che ascolta l'evento originale e attiva il primo evento risultante se l'applicazione della funzione agli argomenti dell'evento ha restituito un Choice1Of2 e il secondo evento se restituisce un Choice2Of2.

Creazione di eventi

Gli eventi vengono creati e utilizzati tramite Eventclasse. Il costruttore di eventi viene utilizzato per creare un evento.

Esempio

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

Dopodiché devi esporre il campo nameChanged come membro pubblico, in modo che gli ascoltatori possano agganciarsi all'evento per il quale, usi il Publish proprietà dell'evento -

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

Successivamente, aggiungi i callback ai gestori di eventi. Ogni gestore di eventi ha il tipo IEvent <'T>, che fornisce diversi metodi:

Metodo Descrizione
val Aggiungi: evento :( 'T → unit) → unit Collega una funzione listener all'evento. Il listener verrà richiamato quando l'evento viene attivato.
val AddHandler: 'del → unit Connette un oggetto delegato del gestore all'evento. Un gestore può essere successivamente rimosso utilizzando RemoveHandler. Il listener verrà richiamato quando l'evento viene attivato.
val RemoveHandler: 'del → unit Rimuove un delegato listener da un archivio listener di eventi.

La sezione seguente fornisce un esempio completo.

Esempio

Il seguente esempio dimostra il concetto e le tecniche discusse sopra:

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"

Quando compili ed esegui il programma, restituisce il seguente output:

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!

Come per la libreria MSDN, un modulo F # è un raggruppamento di costrutti di codice F #, ad esempio tipi, valori, valori di funzione e codice in associazioni do. È implementato come una classe CLR (Common Language Runtime) che ha solo membri statici.

A seconda della situazione se l'intero file è incluso nel modulo, ci sono due tipi di dichiarazioni del modulo:

  • Dichiarazione del modulo di primo livello
  • Dichiarazione del modulo locale

In una dichiarazione di modulo di primo livello, l'intero file è incluso nel modulo. In questo caso, la prima dichiarazione nel file è la dichiarazione del modulo. Non è necessario indentare le dichiarazioni in un modulo di primo livello.

In una dichiarazione di modulo locale, solo le dichiarazioni rientrate in quella dichiarazione di modulo fanno parte del modulo.

Sintassi

La sintassi per la dichiarazione del modulo è la seguente:

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

Tieni presente che il modificatore di accessibilità può essere uno dei seguenti: pubblico, privato, interno. L'impostazione predefinita èpublic.

I seguenti esempi dimostreranno i concetti:

Esempio 1

Il file del modulo 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

Il file di programma 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

Quando compili ed esegui il programma, restituisce il seguente output:

34
16
225
2
110
90
1000
10

Esempio 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

Quando compili ed esegui il programma, restituisce il seguente output:

125
325

UN namespaceè progettato per fornire un modo per mantenere un insieme di nomi separato da un altro. I nomi delle classi dichiarati in uno spazio dei nomi non entreranno in conflitto con gli stessi nomi delle classi dichiarati in un altro.

Secondo la libreria MSDN, a namespace consente di organizzare il codice in aree di funzionalità correlate consentendo di allegare un nome a un raggruppamento di elementi del programma.

Dichiarazione di uno spazio dei nomi

Per organizzare il codice in uno spazio dei nomi, è necessario dichiarare lo spazio dei nomi come prima dichiarazione nel file. Il contenuto dell'intero file diventa quindi parte dello spazio dei nomi.

namespace [parent-namespaces.]identifier

L'esempio seguente illustra il concetto:

Esempio

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

Quando compili ed esegui il programma, restituisce il seguente output:

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