F # - szybki przewodnik
F # to funkcjonalny język programowania. Aby zrozumieć konstrukcje języka F #, należy przeczytać kilka wierszy dotyczących nazwanego paradygmatu programowaniaFunctional Programming.
Programowanie funkcjonalne traktuje programy komputerowe jako funkcje matematyczne. W programowaniu funkcjonalnym skupiono by się na stałych i funkcjach zamiast na zmiennych i stanach. Ponieważ funkcje i stałe to rzeczy, które się nie zmieniają.
W programowaniu funkcjonalnym będziesz pisać programy modułowe, tj. Programy będą składać się z funkcji, które przyjmą inne funkcje jako dane wejściowe.
Programy napisane w funkcjonalnym języku programowania są zwykle zwięzłe.
O F #
Poniżej znajdują się podstawowe informacje o języku F # -
- Został opracowany w 2005 roku w Microsoft Research.
- Jest częścią rodziny języka .Net firmy Microsoft.
- Jest to funkcjonalny język programowania.
- Opiera się na funkcjonalnym języku programowania OCaml.
Funkcje języka F #
Jest to implementacja OCaml .Net.
Kompiluje .Net CLI (Common Language Interface) kod bajtowy lub MSIL (Microsoft Intermediate Language), który działa w środowisku CLR (Common Language Runtime).
Zapewnia wnioskowanie o typie.
Zapewnia bogate konstrukcje dopasowywania wzorców.
Posiada interaktywne możliwości tworzenia skryptów i debugowania.
Pozwala na pisanie funkcji wyższego rzędu.
Zapewnia dobrze rozwinięty model obiektowy.
Korzystanie z F #
F # jest zwykle używany w następujących obszarach -
- Tworzenie modelu naukowego
- Rozwiązywanie problemów matematycznych
- Praca badawcza w zakresie sztucznej inteligencji
- Modelowanie finansowe
- Projekt graficzny
- Konstrukcja procesora
- Programowanie kompilatora
- Telecommunications
Jest również używany w aplikacjach CRUD, stronach internetowych, grach GUI i innych programach ogólnego przeznaczenia.
W tym rozdziale omówiono narzędzia wymagane do programowania w języku F #.
Zintegrowane środowisko programistyczne (IDE) dla języka F #
Firma Microsoft udostępnia program Visual Studio 2013 do programowania w języku F #.
Bezpłatny program Visual Studio 2013 Community Edition jest dostępny w oficjalnej witrynie firmy Microsoft. Visual Studio 2013 Community i nowsze wersje są dostarczane z narzędziami Visual F #. Szczegóły instalacji dostępne w samouczku Asp.net . Narzędzia Visual F # obejmują kompilator wiersza polecenia (fsc.exe) i F # Interactive (fsi.exe).
Korzystając z tych narzędzi, można pisać wszelkiego rodzaju programy w języku F #, od prostych aplikacji wiersza polecenia po bardziej złożone aplikacje. Możesz również pisać pliki kodu źródłowego F # za pomocą podstawowego edytora tekstu, takiego jak Notatnik, i kompilować kod do zestawów za pomocą kompilatora wiersza polecenia.
Możesz go pobrać z Microsoft Visual Studio. Jest automatycznie instalowany na twoim komputerze.
Pisanie programów F # na łączach
Odwiedź oficjalną stronę F #, aby uzyskać najnowsze instrukcje dotyczące pobierania narzędzi jako pakietu Debiana lub kompilowania ich bezpośrednio ze źródła - https://fsharp.org/use/linux/.
F # to język programowania funkcjonalnego.
W języku F # funkcje działają jak typy danych. Możesz deklarować i używać funkcji w taki sam sposób, jak każdej innej zmiennej.
Ogólnie rzecz biorąc, aplikacja F # nie ma określonego punktu wejścia. Kompilator wykonuje wszystkie instrukcje najwyższego poziomu w pliku od góry do dołu.
Jednak zgodnie z proceduralnym stylem programowania wiele aplikacji zachowuje jedną instrukcję najwyższego poziomu, która wywołuje pętlę główną.
Poniższy kod przedstawia prosty program w języku 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()
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
sign 5: positive
Należy pamiętać, że -
Plik kodu F # może zaczynać się od liczby open instrukcje używane do importowania przestrzeni nazw.
Treść plików zawiera inne funkcje, które implementują logikę biznesową aplikacji.
Główna pętla zawiera najważniejsze instrukcje wykonywalne.
Widziałeś już podstawową strukturę programu F #, więc łatwo będzie zrozumieć inne podstawowe elementy składowe języka programowania F #.
Tokeny w F #
Program F # składa się z różnych tokenów. Token może być słowem kluczowym, identyfikatorem, stałą, literałem ciągu lub symbolem. Możemy podzielić tokeny F # na dwa typy -
- Keywords
- Symbol i operatory
Słowa kluczowe F #
W poniższej tabeli przedstawiono słowa kluczowe i krótkie opisy słów kluczowych. Użycie tych słów kluczowych omówimy w kolejnych rozdziałach.
Słowo kluczowe | Opis |
---|---|
abstract | Wskazuje metodę, która nie ma implementacji w typie, w którym jest zadeklarowana, lub jest wirtualna i ma domyślną implementację. |
and | Używany we wzajemnie cyklicznych powiązaniach, w deklaracjach właściwości i z wieloma ograniczeniami dotyczącymi parametrów ogólnych. |
as | Służy do nadania bieżącemu obiektowi klasy nazwy obiektu. Używane także do nadawania nazwy całemu wzorowi w dopasowaniu do wzorca. |
assert | Służy do weryfikacji kodu podczas debugowania. |
base | Używany jako nazwa obiektu klasy bazowej. |
begin | W pełnej składni wskazuje początek bloku kodu. |
class | W pełnej składni wskazuje początek definicji klasy. |
default | Wskazuje implementację metody abstrakcyjnej; używane razem z deklaracją metody abstrakcyjnej do tworzenia metody wirtualnej. |
delegate | Służy do deklarowania delegata. |
do | Używany w konstrukcjach zapętlonych lub do wykonywania kodu imperatywnego. |
done | W pełnej składni wskazuje koniec bloku kodu w wyrażeniu zapętlonym. |
downcast | Służy do konwersji na typ, który znajduje się niżej w łańcuchu dziedziczenia. |
downto | W for wyrażenie używane podczas liczenia w odwrotnej kolejności. |
elif | Używany w rozgałęzieniach warunkowych. Krótka forma else if. |
else | Używany w rozgałęzieniach warunkowych. |
end | W definicjach typów i rozszerzeniach typów wskazuje koniec sekcji definicji elementów członkowskich. W pełnej składni służy do określenia końca bloku kodu, który zaczyna się od słowa kluczowego begin. |
exception | Służy do deklarowania typu wyjątku. |
extern | Wskazuje, że zadeklarowany element programu jest zdefiniowany w innym pliku binarnym lub zestawie. |
false | Używany jako literał boolowski. |
finally | Używane razem z próbą wprowadzenia bloku kodu, który jest wykonywany niezależnie od tego, czy wystąpi wyjątek. |
for | Używany w konstrukcjach zapętlonych. |
fun | Używane w wyrażeniach lambda, zwanych również funkcjami anonimowymi. |
function | Używany jako krótsza alternatywa dla słowa kluczowego fun i wyrażenia dopasowującego w wyrażeniu lambda, które ma dopasowanie do wzorca dla pojedynczego argumentu. |
global | Służy do odwoływania się do obszaru nazw platformy .NET najwyższego poziomu. |
if | Używany w warunkowych konstrukcjach rozgałęziających. |
in | Używany do wyrażeń sekwencji i, w pełnej składni, do oddzielania wyrażeń od powiązań. |
inherit | Służy do określania klasy bazowej lub interfejsu podstawowego. |
inline | Służy do wskazania funkcji, która powinna zostać zintegrowana bezpośrednio z kodem dzwoniącego. |
interface | Służy do deklarowania i implementowania interfejsów. |
internal | Służy do określenia, że element jest widoczny wewnątrz zespołu, ale nie poza nim. |
lazy | Służy do określenia obliczenia, które ma być wykonane tylko wtedy, gdy wymagany jest wynik. |
let | Służy do kojarzenia lub wiązania nazwy z wartością lub funkcją. |
let! | Używany w asynchronicznych przepływach pracy do wiązania nazwy z wynikiem obliczenia asynchronicznego lub, w innych wyrażeniach obliczeniowych, do wiązania nazwy z wynikiem, który jest typu obliczeniowego. |
match | Służy do rozgałęziania przez porównanie wartości ze wzorcem. |
member | Służy do deklarowania właściwości lub metody w typie obiektu. |
module | Służy do kojarzenia nazwy z grupą powiązanych typów, wartości i funkcji, aby logicznie oddzielić ją od innego kodu. |
mutable | Służy do deklarowania zmiennej, czyli wartości, którą można zmienić. |
namespace | Służy do kojarzenia nazwy z grupą powiązanych typów i modułów, aby logicznie oddzielić ją od innego kodu. |
new | Służy do deklarowania, definiowania lub wywoływania konstruktora, który tworzy lub może utworzyć obiekt. Używany również w ogólnych ograniczeniach parametrów, aby wskazać, że typ musi mieć określony konstruktor. |
not | Właściwie to nie słowo kluczowe. Jednak nie struct w połączeniu jest używany jako ogólne ograniczenie parametru. |
null | Wskazuje na brak obiektu. Używany również w ogólnych ograniczeniach parametrów. |
of | Używany w unii rozłącznych do wskazywania typu kategorii wartości oraz w deklaracjach delegatów i wyjątków. |
open | Służy do udostępniania zawartości przestrzeni nazw lub modułu bez kwalifikacji. |
or | Używane z warunkami boolowskimi jako logiczne lub operator. Odpowiednik ||. Używany również w ograniczeniach elementów. |
override | Służy do implementowania wersji metody abstrakcyjnej lub wirtualnej, która różni się od wersji podstawowej. |
private | Ogranicza dostęp do członka do kodu tego samego typu lub modułu. |
public | Umożliwia dostęp do członka spoza typu. |
rec | Służy do wskazania, że funkcja jest rekurencyjna. |
return | Służy do wskazania wartości, która ma być podana jako wynik wyrażenia obliczenia. |
return! | Służy do wskazania wyrażenia obliczeniowego, które po oszacowaniu dostarcza wynik zawierającego wyrażenie obliczeniowe. |
select | Używane w wyrażeniach zapytań do określenia pól lub kolumn do wyodrębnienia. Zwróć uwagę, że jest to kontekstowe słowo kluczowe, co oznacza, że w rzeczywistości nie jest to słowo zastrzeżone i działa jak słowo kluczowe tylko w odpowiednim kontekście. |
static | Służy do wskazania metody lub właściwości, które można wywołać bez wystąpienia typu lub elementu członkowskiego wartości, który jest współużytkowany przez wszystkie wystąpienia typu. |
struct | Służy do deklarowania typu struktury. Używany również w ogólnych ograniczeniach parametrów. Używany w celu zapewnienia zgodności z OCaml w definicjach modułów. |
then | Używane w wyrażeniach warunkowych. Służy również do wywoływania efektów ubocznych po konstrukcji obiektu. |
to | Używane w pętlach for do wskazania zakresu. |
true | Używany jako literał boolowski. |
try | Służy do wprowadzania bloku kodu, który może generować wyjątek. Używany razem z lub ostatecznie. |
type | Służy do deklarowania klasy, rekordu, struktury, unii dyskryminowanej, typu wyliczenia, jednostki miary lub skrótu typu. |
upcast | Służy do konwersji na typ znajdujący się wyżej w łańcuchu dziedziczenia. |
use | Używane zamiast let dla wartości, które wymagają wywołania metody Dispose w celu zwolnienia zasobów. |
use! | Używane zamiast let! w asynchronicznych przepływach pracy i innych wyrażeniach obliczeniowych dla wartości, które wymagają wywołania metody Dispose w celu zwolnienia zasobów. |
val | Używany w podpisie, aby wskazać wartość lub w typie do zadeklarowania elementu członkowskiego, w ograniczonych sytuacjach. |
void | Wskazuje typ unieważnienia platformy .NET. Używany podczas współpracy z innymi językami .NET. |
when | Służy do warunków logicznych (gdy guards) na dopasowaniach wzorców i do wprowadzenia klauzuli ograniczenia dla parametru typu ogólnego. |
while | Wprowadza konstrukcję zapętloną. |
with | Używane razem ze słowem kluczowym match w wyrażeniach dopasowywania wzorców. Używany również w wyrażeniach obiektów, wyrażeniach kopiowania rekordów i rozszerzeniach typów w celu wprowadzenia definicji elementów członkowskich i wprowadzenia programów obsługi wyjątków. |
yield | Używany w wyrażeniu sekwencji do tworzenia wartości dla sekwencji. |
yield! | Używany w wyrażeniu obliczeniowym w celu dołączenia wyniku danego wyrażenia obliczeniowego do kolekcji wyników dla zawierającego wyrażenie obliczeniowe. |
Niektóre zastrzeżone słowa kluczowe pochodzą z języka OCaml -
asr | wylądować | lor | lsl | lsr | lxor | mod | sig |
Niektóre inne zastrzeżone słowa kluczowe są zachowywane na potrzeby przyszłego rozszerzenia języka F #.
atomowy | przerwa | sprawdzone | składnik | konst | przymus | 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
ZA tupleto zbiór wartości oddzielonych przecinkami. Są one używane do tworzenia struktur danych ad hoc, które grupują powiązane wartości.
Na przykład („Zara Ali”, „Hyderabad”, 10) to trzyosobowa krotka z dwiema wartościami łańcuchowymi i wartością typu int, ma typ (string * string * int).
Krotki mogą być parami, trójkami i tak dalej tego samego lub różnych typów.
Oto kilka przykładów -
// 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)
Przykład
Ten program ma funkcję, która pobiera krotkę czterech wartości zmiennoprzecinkowych i zwraca średnią -
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Avg of four numbers: 7.275000
Dostęp do poszczególnych członków krotki
Poszczególnych członków krotki można było ocenić i wydrukować za pomocą dopasowania wzorców.
Poniższy przykład ilustruje koncepcję -
Przykład
let display tuple1 =
match tuple1 with
| (a, b, c) -> printfn "Detail Info: %A %A %A" a b c
display ("Zara Ali", "Hyderabad", 10 )
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Detail Info: "Zara Ali" "Hyderabad" 10
F # ma dwie wbudowane funkcje, fst i snd, które zwracają pierwszy i drugi element w podwójnej krotce.
Poniższy przykład ilustruje koncepcję -
Przykład
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)
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
First member: 23
Second member: 30
First member: "Hello"
Second member: "World!"
First Name: "Zara"
Second Name: "Ali"
ZA recordjest podobny do krotki, ale zawiera nazwane pola. Na przykład,
type website =
{ title : string;
url : string }
Definiowanie rekordu
Rekord jest definiowany jako typ przy użyciu rozszerzenia type słowo kluczowe, a pola rekordu są zdefiniowane jako lista oddzielona średnikami.
Składnia definiowania rekordu to -
type recordName =
{ [ fieldName : dataType ] + }
Tworzenie rekordu
Możesz utworzyć rekord, określając jego pola. Na przykład stwórzmy rekord witryny o nazwie strona główna -
let homepage = { Title = "TutorialsPoint"; Url = "www.tutorialspoint.com" }
Poniższe przykłady wyjaśnią pojęcia -
Przykład 1
Ten program definiuje typ rekordu o nazwie witryna internetowa. Następnie tworzy rekordy typu „witryna internetowa” i drukuje je.
(* 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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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"
Przykład 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()
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Before Registration: : {Name = "Zara";
ID = 10;
RegistrationText = null;
IsRegistered = false;}
After Registration: : {Name = "Zara";
ID = 10;
RegistrationText = "Registered";
IsRegistered = true;}
W języku F # lista jest uporządkowaną, niezmienną serią elementów tego samego typu. Jest to do pewnego stopnia równoważne strukturze danych z połączonej listy.
Moduł F #, Microsoft.FSharp.Collections.List,ma wspólne operacje na listach. Jednak F # importuje ten moduł automatycznie i udostępnia go każdej aplikacji F #.
Tworzenie i inicjowanie listy
Poniżej przedstawiono różne sposoby tworzenia list -
Korzystanie z listy literals.
Za pomocą cons (: :) operator.
Używając List.init metoda modułu List.
Korzystanie z niektórych syntactic constructs nazywa List Comprehensions.
Lista literałów
W tej metodzie wystarczy określić rozdzieloną średnikami sekwencję wartości w nawiasach kwadratowych. Na przykład -
let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
Wady (: :) Operator
Za pomocą tej metody można dodać niektóre wartości, poprzedzając lub cons-ingdo istniejącej listy przy użyciu operatora ::. Na przykład -
let list2 = 1::2::3::4::5::6::7::8::9::10::[];;
[] oznacza pustą listę.
List init Method
Metoda List.init modułu List jest często używana do tworzenia list. Ta metoda ma typ -
val init : int -> (int -> 'T) -> 'T list
Pierwszy argument to żądana długość nowej listy, a drugi argument to funkcja inicjująca, która generuje pozycje na liście.
Na przykład,
let list5 = List.init 5 (fun index -> (index, index * index, index * index * index))
Tutaj funkcja indeksu generuje listę.
Lista ujęć
Listy składane to specjalne konstrukcje składniowe używane do generowania list.
Składnia składni listy F # występuje w dwóch formach - zakresów i generatorów.
Zakresy mają konstrukcje - [start .. end] i [start .. step .. end]
Na przykład,
let list3 = [1 .. 10]
Generatory mają konstrukcję - [for x in collection do ... yield expr]
Na przykład,
let list6 = [ for a in 1 .. 10 do yield (a * a) ]
Ponieważ yield słowo kluczowe wypycha pojedynczą wartość na listę, słowo kluczowe, yield!, umieszcza zbiór wartości na liście.
Poniższa funkcja demonstruje powyższe metody -
Przykład
(* 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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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]
Właściwości typu danych listy
W poniższej tabeli przedstawiono różne właściwości typu danych listy -
własność | Rodzaj | Opis |
---|---|---|
Głowa | „T | Pierwszy element. |
Pusty | Lista 'T | Właściwość statyczna, która zwraca pustą listę odpowiedniego typu. |
Jest pusty | bool | true jeśli lista nie zawiera elementów. |
Pozycja | „T | Element o określonym indeksie (liczony od zera). |
Długość | int | Liczba elementów. |
Ogon | Lista 'T | Lista bez pierwszego elementu. |
Poniższy przykład pokazuje użycie tych właściwości -
Przykład
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))
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
Podstawowe operatory na liście
Poniższa tabela przedstawia podstawowe operacje na typie danych listy -
Wartość | Opis |
---|---|
dołącz: 'Lista T →' Lista T → 'Lista T. | Zwraca nową listę zawierającą elementy pierwszej listy, po których następują elementy drugiej. |
średnia: 'T lista → ^ T | Zwraca średnią elementów na liście. |
średnia Przez: ('T → ^ U) →' T lista → ^ U | Zwraca średnią z elementów wygenerowanych przez zastosowanie funkcji do każdego elementu listy. |
wybierz: (opcja 'T →' U) → 'Lista T →' Lista U | Stosuje daną funkcję do każdego elementu listy. Zwraca listę zawierającą wyniki dla każdego elementu, z którego funkcja zwracaSome. |
zbierać: ('T →' Lista U) → 'Lista T →' Lista U | Do każdego elementu listy stosuje daną funkcję. Łączy wszystkie wyniki i zwraca połączoną listę. |
concat: seq <'T lista> →' T lista | Zwraca nową listę, która zawiera elementy każdej z list w kolejności. |
puste: 'T lista | Zwraca pustą listę podanego typu. |
istnieje: ('T → bool) →' T lista → bool | Sprawdza, czy którykolwiek element listy spełnia podany predykat. |
istnieje2: ('T1 →' T2 → bool) → 'Lista T1 →' Lista T2 → bool | Sprawdza, czy jakakolwiek para odpowiednich elementów list spełnia podany predykat. |
filtr: ('T → bool) →' T lista → 'T lista | Zwraca nową kolekcję zawierającą tylko elementy kolekcji, dla których zwraca dany predykat true. |
znajdź: ('T → bool) →' Lista T → 'T | Zwraca pierwszy element, dla którego zwraca dana funkcja true. |
findIndex: ('T → bool) →' T lista → int | Zwraca indeks pierwszego elementu na liście, który spełnia podany predykat. |
fold: ('Stan →' T → 'Stan) →' Stan → 'Lista T →' Stan | Stosuje funkcję do każdego elementu kolekcji, tworząc wątek argumentu akumulatora przez obliczenia. Ta funkcja przyjmuje drugi argument i stosuje do niego funkcję oraz pierwszy element listy. Następnie przekazuje ten wynik do funkcji wraz z drugim elementem i tak dalej. Na koniec zwraca wynik końcowy. Jeśli funkcją wejściową jest f, a elementy są i0 ... iN, to ta funkcja oblicza f (... (fs i0) i1 ...) iN. |
fold2: ('Stan →' T1 → 'T2 →' Stan) → 'Stan →' Lista T1 → 'Lista T2 →' Stan | Stosuje funkcję do odpowiednich elementów dwóch kolekcji, tworząc wątek argumentu akumulatora przez obliczenia. Kolekcje muszą mieć identyczne rozmiary. Jeśli funkcją wejściową jest f, a elementy to i0 ... iN oraz j0 ... jN, to ta funkcja oblicza f (... (fs i0 j0) ...) iN jN. |
foldBack: ('T →' Stan → 'Stan) →' Lista T → 'Stan →' Stan | Stosuje funkcję do każdego elementu kolekcji, tworząc wątek argumentu akumulatora przez obliczenia. Jeśli funkcja wejściowa isf, a elementy to i0 ... iN, oblicza f i0 (... (f iN s)). |
foldBack2: ('T1 →' T2 → 'Stan →' Stan) → 'Lista T1 →' Lista T2 → 'Stan →' Stan | Stosuje funkcję do odpowiednich elementów dwóch kolekcji, tworząc wątek argumentu akumulatora przez obliczenia. Kolekcje muszą mieć identyczne rozmiary. Jeśli funkcją wejściową jest f, a elementy to i0 ... iN oraz j0 ... jN, to ta funkcja oblicza f i0 j0 (... (f iN jN s)). |
forall: ('T → bool) →' T lista → bool | Sprawdza, czy wszystkie elementy kolekcji spełniają podany predykat. |
forall2: ('T1 →' T2 → bool) → 'Lista T1 →' Lista T2 → bool | Sprawdza, czy wszystkie odpowiadające elementy kolekcji spełniają podany predykat parami. |
head: 'T lista →' T | Zwraca pierwszy element listy. |
init: int → (int → 'T) →' T list | Tworzy listę poprzez wywołanie danego generatora w każdym indeksie. |
isEmpty: 'T lista → bool | Zwroty true jeśli lista nie zawiera elementów, false Inaczej. |
iter: ('T → jednostka) →' Lista T → jednostka | Stosuje daną funkcję do każdego elementu kolekcji. |
iter2: ('T1 →' T2 → jednostka) → 'Lista T1 →' Lista T2 → jednostka | Stosuje daną funkcję do dwóch kolekcji jednocześnie. Kolekcje muszą mieć identyczny rozmiar. |
iteri: (int → 'T → jednostka) →' T lista → jednostka | Stosuje daną funkcję do każdego elementu kolekcji. Liczba całkowita przekazana do funkcji wskazuje indeks elementu. |
iteri2: (int → 'T1 →' T2 → jednostka) → 'Lista T1 →' Lista T2 → jednostka | Stosuje daną funkcję do dwóch kolekcji jednocześnie. Kolekcje muszą mieć identyczny rozmiar. Liczba całkowita przekazana do funkcji wskazuje indeks elementu. |
długość: 'T lista → wew | Zwraca długość listy. |
mapa: ('T →' U) → 'Lista T →' Lista U | Tworzy nową kolekcję, której elementy są wynikiem zastosowania danej funkcji do każdego z elementów kolekcji. |
mapa2: ('T1 →' T2 → 'U) →' Lista T1 → 'Lista T2 →' Lista U | Tworzy nową kolekcję, której elementy są wynikiem zastosowania danej funkcji do odpowiednich elementów dwóch kolekcji parami. |
map3: ('T1 →' T2 → 'T3 →' U) → 'Lista T1 →' Lista T2 → 'Lista T3 →' Lista U | Tworzy nową kolekcję, której elementy są wynikiem zastosowania danej funkcji do odpowiednich elementów trzech kolekcji jednocześnie. |
mapi: (int → 'T →' U) → 'Lista T →' Lista U | Tworzy nową kolekcję, której elementy są wynikiem zastosowania danej funkcji do każdego z elementów kolekcji. Indeks będący liczbą całkowitą przekazaną do funkcji wskazuje indeks (od 0) transformowanego elementu. |
mapi2: (int → 'T1 →' T2 → 'U) →' Lista T1 → 'Lista T2 →' Lista U | Podobnie jak List.mapi, ale mapuje odpowiednie elementy z dwóch list o równej długości. |
max: 'T lista →' T | Zwraca największy ze wszystkich elementów listy w porównaniu przy użyciu Operators.max. |
maxBy: ('T →' U) → 'Lista T →' T | Zwraca największy ze wszystkich elementów listy w porównaniu przy użyciu metody Operators.max w wyniku funkcji. |
min: 'T lista →' T | Zwraca najniższy ze wszystkich elementów listy w porównaniu przy użyciu Operators.min. |
min Przez: ('T →' U) → 'Lista T →' T | Zwraca najniższy ze wszystkich elementów listy w porównaniu przy użyciu Operators.min w wyniku funkcji |
nth: 'T lista → int →' T | Indeksy do listy. Pierwszy element ma indeks 0. |
ofArray: 'T [] →' T lista | Tworzy listę z podanej tablicy. |
ofSeq: seq <'T> →' T list | Tworzy nową listę z podanego wyliczalnego obiektu. |
partycja: ('T → bool) →' T lista * 'T lista | Dzieli kolekcję na dwie kolekcje zawierające elementy, dla których zwraca dany predykat true i false odpowiednio. |
permute: (int → int) → 'T lista →' T lista | Zwraca listę ze wszystkimi elementami permutowanymi zgodnie z określoną permutacją. |
wybierz: (opcja 'T →' U) → 'Lista T →' U | Stosuje daną funkcję do kolejnych elementów, zwracając pierwszy wynik, gdy funkcja zwraca Some za jakąś wartość. |
zmniejsz: ('T →' T → 'T) →' Lista T → 'T | Stosuje funkcję do każdego elementu kolekcji, tworząc wątek argumentu akumulatora przez obliczenia. Ta funkcja stosuje określoną funkcję do pierwszych dwóch elementów listy. Następnie przekazuje ten wynik do funkcji wraz z trzecim elementem i tak dalej. Na koniec zwraca wynik końcowy. Jeśli funkcją wejściową jest f, a elementy są i0 ... iN, to funkcja ta oblicza f (... (f i0 i1) i2 ...) iN. |
redukcjaBack: ('T →' T → 'T) →' Lista T → 'T | Stosuje funkcję do każdego elementu kolekcji, tworząc wątek argumentu akumulatora przez obliczenia. Jeśli funkcja wejściowa isf, a elementy to i0 ... iN, to ta funkcja oblicza f i0 (... (f iN-1 iN)). |
replicate: (int → 'T →' T list) | Tworzy listę poprzez wywołanie danego generatora w każdym indeksie. |
rev: 'Lista T →' Lista T. | Zwraca nową listę z elementami w odwrotnej kolejności. |
skanowanie: ('Stan →' T → 'Stan) →' Stan → 'Lista T →' Lista stanów | Stosuje funkcję do każdego elementu kolekcji, tworząc wątek argumentu akumulatora przez obliczenia. Ta funkcja przyjmuje drugi argument i stosuje do niego określoną funkcję oraz pierwszy element listy. Następnie przekazuje ten wynik do funkcji wraz z drugim elementem i tak dalej. Na koniec zwraca listę wyników pośrednich i wyniku końcowego. |
scanBack: ('T →' Stan → 'Stan) →' Lista T → 'Stan →' Lista stanów | Podobnie jak foldBack, ale zwraca wyniki pośrednie i końcowe |
sortuj: 'T lista →' T lista | Sortuje podaną listę za pomocą Operators.compare. |
sortBy: ('T →' Key) → 'T list →' T list | Sortuje podaną listę za pomocą kluczy podanych przez daną projekcję. Klucze są porównywane za pomocą Operators.compare. |
sortWith: ('T →' T → int) → 'T lista →' T lista | Sortuje podaną listę przy użyciu podanej funkcji porównania. |
suma: ^ T lista → ^ T | Zwraca sumę elementów na liście. |
sumBy: ('T → ^ U) →' T lista → ^ U | Zwraca sumę wyników wygenerowanych przez zastosowanie funkcji do każdego elementu listy. |
ogon: 'Lista T →' Lista T. | Zwraca listę wejściową bez pierwszego elementu. |
toArray: 'T lista →' T [] | Tworzy tablicę z podanej listy. |
toSeq: 'T list → seq <' T> | Wyświetla podaną listę jako sekwencję. |
tryFind: ('T → bool) →' Lista T → opcja 'T | Zwraca pierwszy element, dla którego zwraca dana funkcja true. PowrótNone jeśli taki element nie istnieje. |
tryFindIndex: ('T → bool) →' T lista → opcja int | Zwraca indeks pierwszego elementu na liście, który spełnia podany predykat. PowrótNone jeśli taki element nie istnieje. |
tryPick: (opcja 'T →' U) → 'Lista T → opcja' U | Stosuje daną funkcję do kolejnych elementów, zwracając pierwszy wynik, gdy funkcja zwraca Someza jakąś wartość. Jeśli taki element nie istnieje, powróćNone. |
rozpakuj: ('T1 *' T2) lista → 'T1 lista *' Lista T2 | Dzieli listę par na dwie listy. |
unzip3: ('T1 *' T2 * 'T3) lista →' Lista T1 * 'Lista T2 *' Lista T3 | Dzieli listę trójek na trzy listy. |
zip: 'Lista T1 →' Lista T2 → ('T1 *' T2) lista | Łączy dwie listy w listę par. Obie listy muszą mieć równe długości. |
zip3: 'Lista T1 →' Lista T2 → 'Lista T3 → (' T1 * 'T2 *' T3) lista | Łączy trzy listy w listę trójek. Listy muszą mieć równe długości. |
Poniższe przykłady pokazują zastosowania powyższych funkcji -
Przykład 1
Ten program pokazuje rekurencyjne odwracanie listy -
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)
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
The original list: [2; 4; 6; 8; 10; 12; 14; 16]
The reversed list: [16; 14; 12; 10; 8; 6; 4; 2]
Możesz jednak użyć rev funkcja modułu w tym samym celu -
let list1 = [ 2; 4; 6; 8; 10; 12; 14; 16 ]
printfn "The original list: %A" list1
printfn "The reversed list: %A" (List.rev list1)
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
The original list: [2; 4; 6; 8; 10; 12; 14; 16]
The reversed list: [16; 14; 12; 10; 8; 6; 4; 2]
Przykład 2
Ten program pokazuje filtrowanie listy przy użyciu rozszerzenia List.filter metoda -
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
The list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
The Filtered list: [2; 4; 6; 8; 10]
Przykład 3
Plik List.map metoda odwzorowuje listę z jednego typu na inny -
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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"]
Przykład 4
Plik List.append metoda, a operator @ dołącza jedną listę do drugiej -
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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']
Przykład 5
Plik List.sortmetoda sortuje listę. PlikList.sum zwraca sumę elementów na liście i List.average metoda podaje średnią elementów na liście -
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
Operacja „zwijania” stosuje funkcję do każdego elementu na liście, agreguje wynik funkcji w zmiennej akumulatorowej i zwraca akumulator jako wynik operacji zwinięcia.
Przykład 6
Plik List.fold metoda stosuje funkcję do każdego elementu od lewej do prawej, podczas gdy List.foldBack stosuje funkcję do każdego elementu od prawej do lewej.
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 ])
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Sum of the elements of list [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] is 55.
Sekwencje, podobnie jak listy, również reprezentują uporządkowany zbiór wartości. Jednak elementy w sekwencji lub wyrażeniu sekwencji są obliczane, gdy jest to wymagane. Nie są one obliczane od razu iz tego powodu są używane do reprezentowania nieskończonych struktur danych.
Definiowanie sekwencji
Sekwencje są definiowane przy użyciu następującej składni -
seq { expr }
Na przykład,
let seq1 = seq { 1 .. 10 }
Tworzenie sekwencji i wyrażeń sekwencji
Podobnie jak w przypadku list, możesz tworzyć sekwencje przy użyciu zakresów i wyrażeń.
Wyrażenia sekwencji to wyrażenia, które można napisać w celu tworzenia sekwencji. Można to zrobić -
- Określając zakres.
- Określając zakres ze zwiększaniem lub zmniejszaniem.
- Korzystając z yield słowo kluczowe, aby wygenerować wartości, które staną się częścią sekwencji.
- Używając operatora →.
Poniższe przykłady ilustrują koncepcję -
Przykład 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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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); ...]
Przykład 2
Poniższy program wypisuje liczby pierwsze od 1 do 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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
1
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
Podstawowe operacje na sekwencji
W poniższej tabeli przedstawiono podstawowe operacje na sekwencjach typu danych -
Wartość | Opis |
---|---|
append: seq <'T> → seq <' T> → seq <'T> | Zawija dwa podane wyliczenia jako pojedyncze połączone wyliczenie. |
średnia: seq <^ T> → ^ T | Zwraca średnią elementów w sekwencji. |
średnia Przez: ('T → ^ U) → seq <' T> → ^ U | Zwraca średnią wyników wygenerowanych przez zastosowanie funkcji do każdego elementu sekwencji. |
cache: seq <'T> → seq <' T> | Zwraca sekwencję, która odpowiada buforowanej wersji sekwencji wejściowej. |
cast: IEnumerable → seq <'T> | Zawija luźno wpisany System. Sekwencja kolekcji jako sekwencja wpisana. |
wybierz: (opcja 'T →' U) → seq <'T> → seq <' U> | Stosuje daną funkcję do każdego elementu listy. Zwróć listę zawierającą wyniki dla każdego elementu, z którego funkcja zwracaSome. |
collect: ('T →' Collection) → seq <'T> → seq <' U> | Stosuje daną funkcję do każdego elementu sekwencji i łączy wszystkie wyniki. |
porównaj Z: ('T →' T → int) → seq <'T> → seq <' T> → int | Porównuje dwie sekwencje przy użyciu danej funkcji porównania, element po elemencie. |
concat: seq <'Collection> → seq <' T> | Łączy podane wyliczenia jako pojedyncze połączone wyliczenie. |
countBy: ('T →' Key) → seq <'T> → seq <' Key * int> | Stosuje funkcję generującą klucz do każdego elementu sekwencji i zwraca sekwencję dającą unikatowe klucze i ich liczbę wystąpień w oryginalnej sekwencji. |
opóźnienie: (unit → seq <'T>) → seq <' T> | Zwraca sekwencję utworzoną na podstawie podanej opóźnionej specyfikacji sekwencji. |
odrębny: seq <'T> → seq <' T> | Zwraca sekwencję, która nie zawiera zduplikowanych wpisów zgodnie z ogólnymi porównaniami skrótów i równości wpisów. Jeśli element występuje wiele razy w sekwencji, późniejsze wystąpienia są odrzucane. |
odrębnyBy: (klawisz 'T →') → seq <'T> → seq <' T> | Zwraca sekwencję, która nie zawiera zduplikowanych wpisów zgodnie z ogólnym skrótem i porównaniami równości kluczy zwróconych przez daną funkcję generującą klucz. Jeśli element występuje wiele razy w sekwencji, późniejsze wystąpienia są odrzucane. |
pusty: seq <'T> | Tworzy pustą sekwencję. |
dokładnie jeden: seq <'T> →' T | Zwraca jedyny element sekwencji. |
istnieje: ('T → bool) → seq <' T> → bool | Sprawdza, czy jakikolwiek element ciągu spełnia podany predykat. |
istnieje2: ('T1 →' T2 → bool) → seq <'T1> → seq <' T2> → bool | Sprawdza, czy jakakolwiek para odpowiednich elementów sekwencji wejściowych spełnia podany predykat. |
filter: ('T → bool) → seq <' T> → seq <'T> | Zwraca nową kolekcję zawierającą tylko elementy kolekcji, dla których zwraca dany predykat true. |
znajdź: ('T → bool) → seq <' T> → 'T | Zwraca pierwszy element, dla którego zwraca dana funkcja true. |
findIndex: ('T → bool) → seq <' T> → int | Zwraca indeks pierwszego elementu, dla którego zwraca dana funkcja true. |
fold: ('Stan →' T → 'Stan) →' Stan → sekwencja <'T> →' Stan | Stosuje funkcję do każdego elementu kolekcji, tworząc wątek argumentu akumulatora przez obliczenia. Jeśli funkcją wejściową jest f, a elementy to i0 ... iN, to ta funkcja oblicza f (... (fs i0) ...) iN. |
forall: ('T → bool) → seq <' T> → bool | Sprawdza, czy wszystkie elementy ciągu spełniają podany predykat. |
forall2: ('T1 →' T2 → bool) → seq <'T1> → seq <' T2> → bool | Testuje wszystkie pary elementów narysowanych z dwóch sekwencji, które spełniają zadany predykat. Jeśli jedna sekwencja jest krótsza od drugiej, pozostałe elementy dłuższej sekwencji są ignorowane. |
groupBy: ('T →' Key) → seq <'T> → seq <' Key * seq <'T >> | Stosuje funkcję generującą klucz do każdego elementu sekwencji i zwraca sekwencję unikatowych kluczy. Każdy unikalny klucz zawiera również sekwencję wszystkich elementów, które pasują do tego klucza. |
head: seq <'T> →' T | Zwraca pierwszy element sekwencji. |
init: int → (int → 'T) → seq <' T> | Generuje nową sekwencję, która po wykonaniu iteracji zwraca kolejne elementy, wywołując daną funkcję, aż do podanej liczby. Wyniki wywołania funkcji nie są zapisywane, to znaczy funkcja jest ponownie stosowana w razie potrzeby do ponownego wygenerowania elementów. Funkcja otrzymuje indeks generowanego elementu. |
initInfinite: (int → 'T) → seq <' T> | Generuje nową sekwencję, która po wykonaniu iteracji zwróci kolejne elementy, wywołując daną funkcję. Wyniki wywołania funkcji nie są zapisywane, to znaczy funkcja zostanie ponownie zastosowana w razie potrzeby do ponownego wygenerowania elementów. Funkcja otrzymuje indeks generowanego elementu. |
isEmpty: seq <'T> → bool | Sprawdza, czy sekwencja ma jakieś elementy. |
iter: ('T → unit) → seq <' T> → unit | Stosuje daną funkcję do każdego elementu kolekcji. |
iter2: ('T1 →' T2 → unit) → seq <'T1> → seq <' T2> → unit | Stosuje daną funkcję do dwóch kolekcji jednocześnie. Jeśli jedna sekwencja jest krótsza od drugiej, pozostałe elementy dłuższej sekwencji są ignorowane. |
iteri: (int → 'T → unit) → seq <' T> → unit | Stosuje daną funkcję do każdego elementu kolekcji. Liczba całkowita przekazana do funkcji wskazuje indeks elementu. |
ostatnia: seq <'T> →' T | Zwraca ostatni element sekwencji. |
length: seq <'T> → int | Zwraca długość sekwencji. |
map: ('T →' U) → seq <'T> → seq <' U> | Tworzy nową kolekcję, której elementy są wynikiem zastosowania danej funkcji do każdego z elementów kolekcji. Podana funkcja zostanie zastosowana, gdy elementy są żądane przy użyciu metody MoveNext na modułach wyliczających pobranych z obiektu. |
map2: ('T1 →' T2 → 'U) → seq <' T1> → seq <'T2> → seq <' U> | Tworzy nową kolekcję, której elementy są wynikiem zastosowania danej funkcji do odpowiednich par elementów z dwóch sekwencji. Jeśli jedna sekwencja wejściowa jest krótsza od drugiej, pozostałe elementy dłuższej sekwencji są ignorowane. |
mapi: (int → 'T →' U) → seq <'T> → seq <' U> | Tworzy nową kolekcję, której elementy są wynikiem zastosowania danej funkcji do każdego z elementów kolekcji. Indeks będący liczbą całkowitą przekazaną do funkcji wskazuje indeks (od 0) transformowanego elementu. |
max: seq <'T> →' T | Zwraca największy ze wszystkich elementów sekwencji w porównaniu przy użyciu Operators.max. |
maxBy: ('T →' U) → seq <'T> →' T | Zwraca największy ze wszystkich elementów sekwencji w porównaniu przy użyciu Operators.max w wyniku funkcji. |
min: seq <'T> →' T | Zwraca najniższy ze wszystkich elementów sekwencji w porównaniu przy użyciu Operators.min. |
min By: ('T →' U) → seq <'T> →' T | Zwraca najniższy ze wszystkich elementów sekwencji w porównaniu przy użyciu Operators.min w wyniku funkcji. |
nth: int → seq <'T> →' T | Oblicza n-ty element w kolekcji. |
ofArray: 'T array → seq <' T> | Wyświetla daną tablicę jako sekwencję. |
ofList: 'T lista → seq <' T> | Wyświetla podaną listę jako sekwencję. |
parami: seq <'T> → seq <' T * 'T> | Zwraca sekwencję każdego elementu w sekwencji wejściowej i jego poprzednika, z wyjątkiem pierwszego elementu, który jest zwracany tylko jako poprzednik drugiego elementu. |
wybierz: (opcja 'T →' U) → seq <'T> →' U | Stosuje daną funkcję do kolejnych elementów, zwracając pierwszą wartość, gdy funkcja zwraca Some wartość. |
readonly: seq <'T> → seq <' T> | Tworzy nowy obiekt sekwencji, który jest delegowany do danego obiektu sekwencji. Dzięki temu oryginalna sekwencja nie może zostać ponownie odkryta i zmutowana przez rzutowanie typu. Na przykład, jeśli dana jest tablica, zwrócona sekwencja zwróci elementy tablicy, ale nie można rzutować zwróconego obiektu sekwencji na tablicę. |
zmniejszyć: ('T →' T → 'T) → seq <' T> → 'T | Stosuje funkcję do każdego elementu sekwencji, tworząc wątek argumentu akumulatora przez obliczenia. Zacznij od zastosowania funkcji do pierwszych dwóch elementów. Następnie wprowadź ten wynik do funkcji wraz z trzecim elementem i tak dalej. Zwróć wynik końcowy. |
skanowanie: ('Stan →' T → 'Stan) →' Stan → seq <'T> → seq <' Stan> | Podobnie jak Seq.fold, ale oblicza na żądanie i zwraca sekwencję wyników pośrednich i końcowych. |
singleton: 'T → seq <' T> | Zwraca sekwencję, która daje tylko jeden element. |
skip: int → seq <'T> → seq <' T> | Zwraca sekwencję, która pomija określoną liczbę elementów sekwencji podstawowej, a następnie zwraca pozostałe elementy sekwencji. |
skipWhile: ('T → bool) → seq <' T> → seq <'T> | Zwraca sekwencję, która po wykonaniu iteracji pomija elementy sekwencji bazowej, gdy dany predykat zwraca true, a następnie zwraca pozostałe elementy sekwencji. |
sort: seq <'T> → seq <' T> | Podaje sekwencję uporządkowaną według kluczy. |
sortBy: ('T →' Key) → seq <'T> → seq <' T> | Stosuje funkcję generującą klucz do każdego elementu sekwencji i zwraca sekwencję uporządkowaną według kluczy. Klucze są porównywane przy użyciu porównania ogólnego zaimplementowanego przez Operators.compare. |
suma: seq <^ T> → ^ T | Zwraca sumę elementów w sekwencji. |
sumBy | Zwraca sumę wyników wygenerowanych przez zastosowanie funkcji do każdego elementu sekwencji. |
take: int → seq <'T> → seq <' T> | Zwraca pierwsze elementy sekwencji do określonej liczby. |
takeWhile: ('T → bool) → seq <' T> → seq <'T> | Zwraca sekwencję, która po wykonaniu iteracji zwraca elementy sekwencji bazowej, podczas gdy dany predykat zwraca true, a następnie nie zwraca żadnych dalszych elementów. |
toArray: seq <'T> →' T [] | Tworzy tablicę z podanej kolekcji. |
toList: seq <'T> →' T list | Tworzy listę z podanej kolekcji. |
truncate: int → seq <'T> → seq <' T> | Zwraca sekwencję, która po wyliczeniu zwraca nie więcej niż określoną liczbę elementów. |
tryFind: ('T → bool) → seq <' T> → 'T opcja | Zwraca pierwszy element, dla którego zwraca dana funkcja true, lub None jeśli taki element nie istnieje. |
tryFindIndex: ('T → bool) → seq <' T> → int opcja | Zwraca indeks pierwszego elementu w sekwencji, który spełnia podany predykat lub None jeśli taki element nie istnieje. |
tryPick: (opcja 'T →' U) → seq <'T> → opcja' U | Stosuje daną funkcję do kolejnych elementów, zwracając pierwszą wartość, gdy funkcja zwraca Some wartość. |
unfold: ('Stan →' T * 'opcja stanu) →' Stan → sekwencja <'T> | Zwraca sekwencję zawierającą elementy wygenerowane przez dane obliczenie. |
gdzie: ('T → bool) → seq <' T> → seq <'T> | Zwraca nową kolekcję zawierającą tylko elementy kolekcji, dla których zwraca dany predykat true. Synonim dla Seq.filter. |
windowed: int → seq <'T> → seq <' T []> | Zwraca sekwencję, która daje przesuwane okna zawierające elementy narysowane z sekwencji wejściowej. Każde okno jest zwracane jako nowa tablica. |
zip: seq <'T1> → seq <' T2> → seq <'T1 *' T2> | Łączy dwie sekwencje w listę par. Dwie sekwencje nie muszą mieć równych długości - gdy jedna sekwencja jest wyczerpana, wszystkie pozostałe elementy w drugiej sekwencji są ignorowane. |
zip3: seq <'T1> → seq <' T2> → seq <'T3> → seq <' T1 * 'T2 *' T3> | Łączy trzy sekwencje w listę trójek. Sekwencje nie muszą mieć równych długości - gdy jedna sekwencja jest wyczerpana, wszelkie pozostałe elementy w innych sekwencjach są ignorowane. |
Poniższe przykłady pokazują zastosowania niektórych z powyższych funkcji -
Przykład 1
Ten program tworzy pustą sekwencję i wypełnia ją później -
(* 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""
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
Należy pamiętać, że -
Metoda Seq.empty tworzy pustą sekwencję.
Metoda Seq.singleton tworzy sekwencję tylko jednego określonego elementu.
Metoda Seq.init tworzy sekwencję, dla której tworzone są elementy przy użyciu danej funkcji.
Metody Seq.ofArray i Seq.ofList <'T> tworzą sekwencje z tablic i list.
Metoda Seq.iter umożliwia iterację sekwencji.
Przykład 2
Metoda Seq.unfold generuje sekwencję z funkcji obliczeniowej, która przyjmuje stan i przekształca go w celu utworzenia każdego kolejnego elementu w sekwencji.
Poniższa funkcja daje pierwsze 20 liczb naturalnych -
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" "
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
Przykład 3
Metoda Seq.truncate tworzy sekwencję z innej sekwencji, ale ogranicza sekwencję do określonej liczby elementów.
Metoda Seq.take tworzy nową sekwencję zawierającą określoną liczbę elementów od początku sekwencji.
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""
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
Zestaw w F # to struktura danych, która działa jak kolekcja elementów bez zachowania kolejności, w jakiej elementy są wstawiane. Zestawy nie pozwalają na wstawianie do kolekcji zduplikowanych wpisów.
Tworzenie zestawów
Zestawy można tworzyć w następujący sposób -
- Tworząc pusty zestaw za pomocą Set.empty i dodając elementy za pomocą funkcji add.
- Przekształcanie sekwencji i list w zestawy.
Poniższy program demonstruje techniki -
(* 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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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]
Podstawowe operacje na zbiorach
Poniższa tabela przedstawia podstawowe operacje na zestawach -
Wartość | Opis |
---|---|
dodaj: 'T → Ustaw <' T> → Ustaw <'T> | Zwraca nowy zestaw z elementem dodanym do zestawu. Żaden wyjątek nie jest zgłaszany, jeśli zestaw zawiera już dany element. |
zawiera: 'T → Ustaw <' T> → bool | Ocenia do true czy dany element należy do danego zbioru. |
count: Ustaw <'T> → int | Zwraca liczbę elementów w zestawie. |
różnica: Ustaw <'T> → Ustaw <' T> → Ustaw <'T> | Zwraca nowy zestaw z elementami drugiego zestawu usuniętymi z pierwszego. |
pusty: Ustaw <'T> | Pusty zestaw dla określonego typu. |
istnieje: ('T → bool) → Set <' T> → bool | Sprawdza, czy którykolwiek element kolekcji spełnia podany predykat. Jeśli funkcja wejściowa jest predykatem, a elementy są i0 ... iN, to ta funkcja oblicza predykat i0 lub ... lub predykat iN. |
filtr: ('T → bool) → Ustaw <' T> → Ustaw <'T> | Zwraca nową kolekcję zawierającą tylko elementy kolekcji, dla których zwraca dany predykat true. |
fold: ('Stan →' T → 'Stan) →' Stan → Ustaw <'T> →' Stan | Stosuje daną funkcję sumującą do wszystkich elementów zbioru. |
foldBack: ('T →' Stan → 'Stan) → Ustaw <' T> → 'Stan →' Stan | Stosuje daną funkcję sumującą do wszystkich elementów zbioru. |
forall: ('T → bool) → Set <' T> → bool | Sprawdza, czy wszystkie elementy kolekcji spełniają podany predykat. Jeśli funkcją wejściową jest p, a elementy to i0 ... iN, to ta funkcja oblicza p i0 && ... && p iN. |
przecięcie: Ustaw <'T> → Ustaw <' T> → Ustaw <'T> | Oblicza przecięcie dwóch zbiorów. |
intersectMany: seq <Ustaw <'T >> → Ustaw <' T> | Oblicza przecięcie sekwencji zbiorów. Sekwencja nie może być pusta. |
isEmpty: Set <'T> → bool | Zwroty true jeśli zestaw jest pusty. |
isProperSubset: Set <'T> → Set <' T> → bool | Ocenia do true jeśli wszystkie elementy pierwszego zestawu są w drugim, a co najmniej jeden element drugiego nie znajduje się w pierwszym. |
isProperSuperset: Set <'T> → Set <' T> → bool | Ocenia do true jeśli wszystkie elementy drugiego zestawu znajdują się w pierwszym, a przynajmniej jeden element pierwszego nie znajduje się w drugim. |
isSubset: Set <'T> → Set <' T> → bool | Ocenia do true jeśli wszystkie elementy pierwszego zestawu znajdują się w drugim. |
isSuperset: Set <'T> → Set <' T> → bool | Ocenia do true jeśli wszystkie elementy drugiego zestawu znajdują się w pierwszym. |
iter: ('T → jednostka) → Ustaw <' T> → jednostka | Stosuje daną funkcję do każdego elementu zestawu, zgodnie z funkcją porównania. |
map: ('T →' U) → Ustaw <'T> → Ustaw <' U> | Zwraca nową kolekcję zawierającą wyniki zastosowania danej funkcji do każdego elementu zestawu wejściowego. |
maxElement: Ustaw <'T> →' T | Zwraca najwyższy element w zestawie zgodnie z kolejnością używaną w zestawie. |
minElement: Ustaw <'T> →' T | Zwraca najniższy element w zestawie zgodnie z kolejnością używaną dla zestawu. |
ofArray: 'Tablica T → Ustaw <' T> | Tworzy zestaw zawierający te same elementy, co dana tablica. |
ofList: 'T lista → Ustaw <' T> | Tworzy zestaw zawierający te same elementy, co podana lista. |
ofSeq: seq <'T> → Set <' T> | Tworzy nową kolekcję z danego wyliczalnego obiektu. |
partycja: ('T → bool) → Ustaw <' T> → Ustaw <'T> * Ustaw <' T> | Dzieli zestaw na dwa zestawy zawierające elementy, dla których dany predykat zwraca odpowiednio prawdę i fałsz. |
usuń: 'T → Ustaw <' T> → Ustaw <'T> | Zwraca nowy zestaw z usuniętym danym elementem. Żaden wyjątek nie jest zgłaszany, jeśli zestaw nie zawiera danego elementu. |
singleton: 'T → Ustaw <' T> | Zestaw zawierający dany element. |
toArray: Ustaw tablicę <'T> →' T. | Tworzy tablicę zawierającą elementy zestawu w kolejności. |
toList: Ustaw <'T> →' T list | Tworzy listę zawierającą elementy zestawu w kolejności. |
toSeq: Ustaw <'T> → seq <' T> | Zwraca uporządkowany widok kolekcji jako wyliczalny obiekt. |
suma: Ustaw <'T> → Ustaw <' T> → Ustaw <'T> | Oblicza sumę dwóch zbiorów. |
unionMany: seq <Ustaw <'T >> → Ustaw <' T> | Oblicza sumę sekwencji zbiorów. |
Poniższy przykład demonstruje zastosowania niektórych z powyższych funkcji -
Przykład
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""
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
W języku F # mapa to specjalny rodzaj zestawu, który kojarzy wartości z kluczem. Mapa jest tworzona w podobny sposób jak zestawy.
Tworzenie map
Mapy tworzy się, tworząc pustą mapę za pomocą Map.empty i dodając elementy za pomocą funkcji Dodaj. Poniższy przykład demonstruje to -
Przykład
(* 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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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")]
Możesz uzyskać dostęp do poszczególnych elementów mapy za pomocą klawisza.
Przykład
(* 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"]
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Map - students: map
[("Gillian Megan", "1504"); ("Rishita Gupta", "1502"); ("Robin Sahoo", "1503
");
("Zara Ali", "1501")]
"1501"
Podstawowe operacje na mapach
Dodaj nazwę modułu
Poniższa tabela przedstawia podstawowe operacje na mapach -
Członek | Opis |
---|---|
Dodaj | Zwraca nową mapę z powiązaniem dodanym do danej mapy. |
ContainsKey | Testuje, czy element znajduje się w domenie mapy. |
Liczyć | Liczba powiązań na mapie. |
Jest pusty | Zwraca wartość true, jeśli na mapie nie ma żadnych powiązań. |
Pozycja | Wyszukaj element na mapie. Podnosi KeyNotFoundException, jeśli w mapie nie istnieje żadne powiązanie. |
Usunąć | Usuwa element z domeny mapy. Żaden wyjątek nie jest zgłaszany, jeśli element nie jest obecny. |
TryFind | Wyszukaj element na mapie, zwracając plik Some wartość, jeśli element znajduje się w domenie mapy i None Jeśli nie. |
Poniższy przykład demonstruje zastosowania niektórych z powyższych funkcji -
Przykład
(* 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."
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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.
Związki, czyli związki rozłączne, umożliwiają tworzenie złożonych struktur danych reprezentujących dobrze zdefiniowany zestaw wyborów. Na przykład musisz zbudować implementację zmiennej wyboru , która ma dwie wartości tak i nie. Za pomocą narzędzia Związki możesz to zaprojektować.
Składnia
Związki rozłączne są definiowane przy użyciu następującej składni -
type type-name =
| case-identifier1 [of [ fieldname1 : ] type1 [ * [ fieldname2 : ]
type2 ...]
| case-identifier2 [of [fieldname3 : ]type3 [ * [ fieldname4 : ]type4 ...]
...
Nasza prosta implementacja, wybór, będzie wyglądać następująco -
type choice =
| Yes
| No
W poniższym przykładzie zastosowano wybór typu -
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()
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
x: Yes
y: No
Przykład 1
Poniższy przykład pokazuje implementację stanów napięcia, które ustawiają się nieco na wysokie lub niskie -
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()
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Switch on state: High
Switch off state: Low
Toggle off: High
Toggle the Changed state: Low
Przykład 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)
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
Zmienne w języku F # to immutable,co oznacza, że po przypisaniu zmiennej do wartości nie można jej zmienić. W rzeczywistości są one kompilowane jako statyczne właściwości tylko do odczytu.
Poniższy przykład ilustruje to.
Przykład
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
Podczas kompilowania i wykonywania programu wyświetla następujący komunikat o błędzie -
Duplicate definition of value 'x'
Duplicate definition of value 'Y'
Duplicate definition of value 'Z'
Zmienne zmienne
Czasami trzeba zmienić wartości przechowywane w zmiennej. Aby określić, że może nastąpić zmiana wartości zadeklarowanej i przypisanej zmiennej w dalszej części programu, F # udostępniamutablesłowo kluczowe. Za pomocą tego słowa kluczowego możesz deklarować i przypisywać zmienne zmienne, których wartości będziesz zmieniać.
Plik mutable słowo kluczowe pozwala zadeklarować i przypisać wartości w zmiennej zmiennej.
Możesz przypisać jakąś wartość początkową do zmiennej zmiennej za pomocą letsłowo kluczowe. Jednak aby przypisać do niego nową kolejną wartość, musisz użyć rozszerzenia<- operator.
Na przykład,
let mutable x = 10
x <- 15
Poniższy przykład wyjaśni tę koncepcję -
Przykład
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
Zastosowania zmiennych danych
Zmienne dane są często wymagane i wykorzystywane w przetwarzaniu danych, szczególnie w przypadku struktury danych rekordów. Poniższy przykład demonstruje to -
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()
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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";}
Tablice to zmienne kolekcje o stałym rozmiarze, liczone od zera, kolejnych elementów danych, które są tego samego typu.
Tworzenie tablic
Możesz tworzyć tablice przy użyciu różnych składni i sposobów lub używając funkcji z modułu Array. W tej sekcji omówimy tworzenie tablic bez korzystania z funkcji modułu.
Istnieją trzy syntaktyczne sposoby tworzenia tablic bez funkcji -
- Wymieniając kolejne wartości między [| i |] i oddzielone średnikami.
- Umieszczając każdy element w osobnym wierszu, w takim przypadku separator średnika jest opcjonalny.
- Używając wyrażeń sekwencyjnych.
Dostęp do elementów tablicy można uzyskać za pomocą operatora kropki (.) I nawiasów kwadratowych ([i]).
Poniższy przykład demonstruje tworzenie tablic -
//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" "
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
1 2 3 4 5 6
1 2 3 4 5
1 4 9 16 25 36 49 64 81 100
Podstawowe operacje na tablicach
Moduł biblioteki Microsoft.FSharp.Collections.Array obsługuje operacje na tablicach jednowymiarowych.
W poniższej tabeli przedstawiono podstawowe operacje na tablicach -
Wartość | Opis |
---|---|
dołącz: „T [] →„ T [] → „T []” | Tworzy tablicę zawierającą elementy jednej tablicy, po których następują elementy innej tablicy. |
średnia: ^ T [] → ^ T | Zwraca średnią elementów w tablicy. |
średnia Przez: ('T → ^ U) →' T [] → ^ U | Zwraca średnią z elementów wygenerowanych przez zastosowanie funkcji do każdego elementu tablicy. |
blit: 'T [] → int →' T [] → int → int → unit | Odczytuje zakres elementów z jednej tablicy i zapisuje je w innej. |
wybierz: (opcja 'T → U) →' T [] → 'U [] | Stosuje podaną funkcję do każdego elementu tablicy. Zwraca tablicę zawierającą wyniki x dla każdego elementu, dla którego funkcja zwraca Some (x). |
zbierać: ('T →' U []) → T [] → 'U [] | Stosuje podaną funkcję do każdego elementu tablicy, konkatenuje wyniki i zwraca połączoną tablicę. |
concat: seq <'T []> →' T [] | Tworzy tablicę zawierającą elementy każdej z podanych sekwencji tablic. |
kopia: „T →” T [] | Tworzy tablicę zawierającą elementy podanej tablicy. |
utwórz: int → 'T →' T [] | Tworzy tablicę, której wszystkie elementy są początkowo podaną wartością. |
pusty: „T [] | Zwraca pustą tablicę podanego typu. |
istnieje: ('T → bool) →' T [] → bool | Testuje, czy dowolny element tablicy spełnia podany predykat. |
istnieje2: ('T1 →' T2 → bool) → 'T1 [] →' T2 [] → bool | Testuje, czy dowolna para odpowiednich elementów dwóch tablic spełnia podany warunek. |
wypełnienie: 'T [] → int → int →' T → unit | Wypełnia zakres elementów tablicy podaną wartością. |
filtr: ('T → bool) →' T [] → 'T [] | Zwraca kolekcję zawierającą tylko elementy podanej tablicy, dla których zwraca podany warunek true. |
znajdź: ('T → bool) →' T [] → 'T | Zwraca pierwszy element, dla którego podana funkcja zwraca true. Podnosi KeyNotFoundException, jeśli taki element nie istnieje. |
findIndex: ('T → bool) →' T [] → int | Zwraca indeks pierwszego elementu w tablicy, który spełnia podany warunek. Podnosi KeyNotFoundException, jeśli żaden z elementów nie spełnia warunku. |
fold: („Stan →„ T → ”Stan) →„ Stan → „T [] →„ Stan | Stosuje funkcję do każdego elementu tablicy, tworząc wątek argumentu akumulatora przez obliczenia. Jeśli funkcją wejściową jest f, a elementy tablicy to i0 ... iN, ta funkcja oblicza f (... (fs i0) ...) iN. |
fold2: ('Stan →' T1 → 'T2 →' Stan) → 'Stan →' T1 [] → 'T2 [] →' Stan | Stosuje funkcję do par elementów z dwóch dostarczonych tablic, od lewej do prawej, tworząc wątek argumentu akumulatora przez obliczenia. Dwie tablice wejściowe muszą mieć takie same długości; w przeciwnym razie zostanie zgłoszony ArgumentException. |
foldBack: ('T →' Stan → 'Stan) →' T [] → 'Stan →' Stan | Stosuje funkcję do każdego elementu tablicy, tworząc wątek argumentu akumulatora przez obliczenia. Jeśli funkcją wejściową jest f, a elementy tablicy to i0 ... iN, ta funkcja oblicza f i0 (... (f iN s)). |
foldBack2 : ('T1 → 'T2 → 'State → 'State) → 'T1 [] → 'T2 [] → 'State → 'State | Applies a function to pairs of elements from two supplied arrays, right-to-left, threading an accumulator argument through the computation. The two input arrays must have the same lengths; otherwise, ArgumentException is raised. |
forall : ('T → bool) → 'T [] → bool | Tests whether all elements of an array satisfy the supplied condition. |
forall2 : ('T1 → 'T2 → bool) → 'T1 [] → 'T2 [] → bool | Tests whether all corresponding elements of two supplied arrays satisfy a supplied condition. |
get : 'T [] → int → 'T | Gets an element from an array. |
init : int → (int → 'T) → 'T [] | Uses a supplied function to create an array of the supplied dimension. |
isEmpty : 'T [] → bool | Tests whether an array has any elements. |
iter : ('T → unit) → 'T [] → unit | Applies the supplied function to each element of an array. |
iter2 : ('T1 → 'T2 → unit) → 'T1 [] → 'T2 [] → unit) | Applies the supplied function to a pair of elements from matching indexes in two arrays. The two arrays must have the same lengths; otherwise, ArgumentException is raised. |
iteri : (int → 'T → unit) → 'T [] → unit | Applies the supplied function to each element of an array. The integer passed to the function indicates the index of the element. |
iteri2 : (int → 'T1 → 'T2 → unit) → 'T1 [] → 'T2 [] → unit | Applies the supplied function to a pair of elements from matching indexes in two arrays, also passing the index of the elements. The two arrays must have the same lengths; otherwise, an ArgumentException is raised. |
length : 'T [] → int | Returns the length of an array. The Length property does the same thing. |
map : ('T → 'U) → 'T [] → 'U [] | Creates an array whose elements are the results of applying the supplied function to each of the elements of a supplied array. |
map2 : ('T1 → 'T2 → 'U) → 'T1 [] → 'T2 [] → 'U [] | Creates an array whose elements are the results of applying the supplied function to the corresponding elements of two supplied arrays. The two input arrays must have the same lengths; otherwise, ArgumentException is raised. |
mapi : (int → 'T → 'U) → 'T [] → 'U [] | Creates an array whose elements are the results of applying the supplied function to each of the elements of a supplied array. An integer index passed to the function indicates the index of the element being transformed. |
mapi2 : (int → 'T1 → 'T2 → 'U) → 'T1 [] → 'T2 [] → 'U [] | Creates an array whose elements are the results of applying the supplied function to the corresponding elements of the two collections pairwise, also passing the index of the elements. The two input arrays must have the same lengths; otherwise, ArgumentException is raised. |
max : 'T [] → 'T | Returns the largest of all elements of an array. Operators.max is used to compare the elements. |
maxBy : ('T → 'U) → 'T [] → 'T | Returns the largest of all elements of an array, compared via Operators.max on the function result. |
min : ('T [] → 'T | Returns the smallest of all elements of an array. Operators.min is used to compare the elements. |
minBy : ('T → 'U) → 'T [] → 'T | Returns the smallest of all elements of an array. Operators.min is used to compare the elements. |
ofList : 'T list → 'T [] | Creates an array from the supplied list. |
ofSeq : seq<'T> → 'T [] | Creates an array from the supplied enumerable object. |
partition : ('T → bool) → 'T [] → 'T [] * 'T [] | Splits an array into two arrays, one containing the elements for which the supplied condition returns true, and the other containing those for which it returns false. |
permute : (int → int) → 'T [] → 'T [] | Permutes the elements of an array according to the specified permutation. |
pick : ('T → 'U option) → 'T [] → 'U | Applies the supplied function to successive elements of a supplied array, returning the first result where the function returns Some(x) for some x. If the function never returns Some(x), KeyNotFoundException is raised. |
reduce : ('T → 'T → 'T) → 'T [] → 'T | Applies a function to each element of an array, threading an accumulator argument through the computation. If the input function is f and the array elements are i0...iN, this function computes f (...(f i0 i1)...) iN. If the array has size zero, ArgumentException is raised. |
reduceBack : ('T → 'T → 'T) → 'T [] → 'T | Applies a function to each element of an array, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN, this function computes f i0 (...(f iN-1 iN)). If the array has size zero, ArgumentException is raised. |
rev : 'T [] → 'T [] | Reverses the order of the elements in a supplied array. |
scan : ('State → 'T → 'State) → 'State → 'T [] → 'State []) | Behaves like fold, but returns the intermediate results together with the final results. |
scanBack : ('T → 'State → 'State) → 'T [] → 'State → 'State [] | Behaves like foldBack, but returns the intermediary results together with the final results. |
set : 'T [] → int → 'T → unit | Sets an element of an array. |
sort : 'T[] → 'T [] | Sorts the elements of an array and returns a new array. Operators.compare is used to compare the elements. |
sortBy : ('T → 'Key) → 'T [] → 'T [] | Sorts the elements of an array by using the supplied function to transform the elements to the type on which the sort operation is based, and returns a new array. Operators.compare is used to compare the elements. |
sortInPlace : 'T [] → unit | Sorts the elements of an array by changing the array in place, using the supplied comparison function. Operators.compare is used to compare the elements. |
sortInPlaceBy : ('T → 'Key) → 'T [] → unit | Sorts the elements of an array by changing the array in place, using the supplied projection for the keys. Operators.compare is used to compare the elements. |
sortInPlaceWith : ('T → 'T → int) → 'T [] → unit | Sorts the elements of an array by using the supplied comparison function to change the array in place. |
sortWith : ('T → 'T → int) → 'T [] → 'T [] | Sorts the elements of an array by using the supplied comparison function, and returns a new array. |
sub : 'T [] → int → int → 'T [] | Creates an array that contains the supplied subrange, which is specified by starting index and length. |
sum : 'T [] → ^T | Returns the sum of the elements in the array. |
sumBy : ('T → ^U) → 'T [] → ^U | Returns the sum of the results generated by applying a function to each element of an array. |
toList : 'T [] → 'T list | Converts the supplied array to a list. |
toSeq : 'T [] → seq<'T> | Views the supplied array as a sequence. |
tryFind : ('T → bool) → 'T [] → 'T option | Returns the first element in the supplied array for which the supplied function returns true. Returns None if no such element exists. |
tryFindIndex : ('T → bool) → 'T [] → int option | Returns the index of the first element in an array that satisfies the supplied condition. |
tryPick : ('T → 'U option) → 'T [] → 'U option | Applies the supplied function to successive elements of the supplied array, and returns the first result where the function returns Some(x) for some x. If the function never returns Some(x), None is returned. |
unzip : ('T1 * 'T2) [] → 'T1 [] * 'T2 [] | Splits an array of tuple pairs into a tuple of two arrays. |
unzip3 : ('T1 * 'T2 * 'T3) [] → 'T1 [] * 'T2 [] * 'T3 [] | Splits an array of tuples of three elements into a tuple of three arrays. |
zeroCreate : int → 'T [] | Creates an array whose elements are initially set to the default value Unchecked.defaultof<'T>. |
zip : 'T1 [] → 'T2 [] → ('T1 * 'T2) [] | Combines two arrays into an array of tuples that have two elements. The two arrays must have equal lengths; otherwise, ArgumentException is raised. |
zip3 : 'T1 [] → 'T2 [] → 'T3 [] → ('T1 * 'T2 * 113 'T3) [] | Combines three arrays into an array of tuples that have three elements. The three arrays must have equal lengths; otherwise, ArgumentException is raised. |
In the following section, we will see the uses of some of these functionalities.
Creating Arrays Using Functions
The Array module provides several functions that create an array from scratch.
The Array.empty function creates a new empty array.
The Array.create function creates an array of a specified size and sets all the elements to given values.
The Array.init function creates an array, given a dimension and a function to generate the elements.
The Array.zeroCreate function creates an array in which all the elements are initialized to the zero value.
The Array.copy function creates a new array that contains elements that are copied from an existing array.
The Array.sub function generates a new array from a subrange of an array.
The Array.append function creates a new array by combining two existing arrays.
The Array.choose function selects elements of an array to include in a new array.
The Array.collect function runs a specified function on each array element of an existing array and then collects the elements generated by the function and combines them into a new array.
The Array.concat function takes a sequence of arrays and combines them into a single array.
The Array.filter function takes a Boolean condition function and generates a new array that contains only those elements from the input array for which the condition is true.
The Array.rev function generates a new array by reversing the order of an existing array.
The following examples demonstrate these functions −
Example 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
When you compile and execute the program, it yields the following 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|]
Example 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
When you compile and execute the program, it yields the following 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|]
Searching Arrays
The Array.find function takes a Boolean function and returns the first element for which the function returns true, else raises a KeyNotFoundException.
The Array.findIndex function works similarly except that it returns the index of the element instead of the element itself.
The following example demonstrates this.
Microsoft provides this interesting program example, which finds the first element in the range of a given number that is both a perfect square as well as a perfect cube −
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
When you compile and execute the program, it yields the following output −
The first element that is both a square and a cube is 64 and its index is 62.
The List<'T> class represents a strongly typed list of objects that can be accessed by index.
It is a mutable counterpart of the List class. It is similar to arrays, as it can be accessed by an index, however, unlike arrays, lists can be resized. Therefore you need not specify a size during declaration.
Creating a Mutable List
Lists are created using the new keyword and calling the list's constructor. The following example demonstrates this −
(* 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])
When you compile and execute the program, it yields the following output −
0: Gone with the Wind
1: Atlas Shrugged
2: Fountainhead
3: Thornbirds
4: Rebecca
5: Narnia
The List(T) Class
The List(T) class represents a strongly typed list of objects that can be accessed by index. It provide methods to search, sort, and manipulate lists.
The following tables provide the properties, constructors and the methods of the List(T) class −
Properties
Property | Description |
---|---|
Capacity | Gets or sets the total number of elements the internal data structure can hold without resizing. |
Count | Gets the number of elements contained in the List(T). |
Item | Gets or sets the element at the specified index. |
Constructors
Constructor | Description |
---|---|
List(T)() | Initializes a new instance of the List(T) class that is empty and has the default initial capacity. |
List(T)(IEnumerable(T)) | Initializes a new instance of the List(T) class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied. |
List(T)(Int32) | Initializes a new instance of the List(T) class that is empty and has the specified initial capacity. |
Method
Methods | Description |
---|---|
Add | Adds an object to the end of the List(T). |
AddRange | Adds the elements of the specified collection to the end of the List(T). |
AsReadOnly | Returns a read-only IList(T) wrapper for the current collection. |
BinarySearch(T) | Searches the entire sorted List(T) for an element using the default comparer and returns the zero-based index of the element. |
BinarySearch(T, IComparer(T)) | Searches the entire sorted List(T) for an element using the specified comparer and returns the zero-based index of the element. |
BinarySearch(Int32, Int32, T, IComparer(T)) | Searches a range of elements in the sorted List(T) for an element using the specified comparer and returns the zero-based index of the element. |
Clear | Removes all elements from the List(T). |
Contains | Determines whether an element is in the List(T). |
ConvertAll(TOutput) | Converts the elements in the current List(T) to another type, and returns a list containing the converted elements. |
CopyTo(T[]) | Copies the entire List(T) to a compatible one-dimensional array, starting at the beginning of the target array. |
CopyTo(T[], Int32) | Copies the entire List(T) to a compatible one-dimensional array, starting at the specified index of the target array. |
CopyTo(Int32, T[], Int32, Int32) | Copies a range of elements from the List(T) to a compatible one-dimensional array, starting at the specified index of the target array. |
Equals(Object) | Determines whether the specified object is equal to the current object. (Inherited from Object.) |
Exists | Determines whether the List(T) contains elements that match the conditions defined by the specified predicate. |
Finalize | Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection (Inherited from Object). |
Find | Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire List(T). |
FindAll | Retrieves all the elements that match the conditions defined by the specified predicate. |
FindIndex(Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the entire List(T). |
FindIndex(Int32, Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the range of elements in the List(T) that extends from the specified index to the last element. |
FindIndex(Int32, Int32, Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the range of elements in the List(T) that starts at the specified index and contains the specified number of elements. |
FindLast | Searches for an element that matches the conditions defined by the specified predicate, and returns the last occurrence within the entire List(T). |
FindLastIndex(Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the last occurrence within the entire List(T). |
FindLastIndex(Int32, Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the last occurrence within the range of elements in the List(T) that extends from the first element to the specified index. |
FindLastIndex(Int32, Int32, Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the last occurrence within the range of elements in the List(T) that contains the specified number of elements and ends at the specified index. |
ForEach | Performs the specified action on each element of the List(T). |
GetEnumerator | Returns an enumerator that iterates through the List(T). |
GetHashCode | Serves as the default hash function. (Inherited from Object.) |
GetRange | Creates a shallow copy of a range of elements in the source List(T). |
GetType | Gets the Type of the current instance. (Inherited from Object.) |
IndexOf(T) | Searches for the specified object and returns the zero-based index of the first occurrence within the entire List(T). |
IndexOf(T, Int32) | Searches for the specified object and returns the zero-based index of the first occurrence within the range of elements in the List(T) that extends from the specified index to the last element. |
IndexOf(T, Int32, Int32) | Searches for the specified object and returns the zero-based index of the first occurrence within the range of elements in the List(T) that starts at the specified index and contains the specified number of elements. |
Insert | Inserts an element into the List(T) at the specified index. |
InsertRange | Inserts the elements of a collection into the List(T) at the specified index. |
LastIndexOf(T) | Searches for the specified object and returns the zero-based index of the last occurrence within the entire List(T). |
LastIndexOf(T, Int32) | Searches for the specified object and returns the zero-based index of the last occurrence within the range of elements in the List(T) that extends from the first element to the specified index. |
LastIndexOf(T, Int32, Int32) | Searches for the specified object and returns the zero-based index of the last occurrence within the range of elements in the List(T) that contains the specified number of elements and ends at the specified index. |
MemberwiseClone | Creates a shallow copy of the current Object. (Inherited from Object.) |
Remove | Removes the first occurrence of a specific object from the List(T). |
RemoveAll | Removes all the elements that match the conditions defined by the specified predicate. |
RemoveAt | Removes the element at the specified index of the List(T). |
RemoveRange | Removes a range of elements from the List(T). |
Reverse() | Reverses the order of the elements in the entire List(T). |
Reverse(Int32, Int32) | Reverses the order of the elements in the specified range. |
Sort() | Sorts the elements in the entire List(T) using the default comparer. |
Sort(Comparison(T)) | Sorts the elements in the entire List(T) using the specified System. Comparison(T). |
Sort(IComparer(T)) | Sorts the elements in the entire List(T) using the specified comparer. |
Sort(Int32, Int32, IComparer(T)) | Sorts the elements in a range of elements in List(T) using the specified comparer. |
ToArray | Copies the elements of the List(T) to a new array. |
ToString | Returns a string that represents the current object. (Inherited from Object.) |
TrimExcess | Sets the capacity to the actual number of elements in the List(T), if that number is less than a threshold value. |
TrueForAll | Determines whether every element in the List(T) matches the conditions defined by the specified predicate. |
Przykład
(* 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])
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
Plik Dictionary<'TKey, 'TValue> class jest zmiennym odpowiednikiem struktury danych mapy F # i zawiera wiele takich samych funkcji.
Podsumowując z rozdziału Mapa w języku F #, mapa to specjalny rodzaj zestawu, który kojarzy wartości z kluczem.
Tworzenie słownika mutowalnego
Zmienne słowniki są tworzone przy użyciu rozszerzenia newsłowo kluczowe i wywołanie konstruktora listy. Poniższy przykład demonstruje to -
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Dictionary - students: seq
[[1501, Zara Ali]; [1502, Rishita Gupta]; [1503, Robin Sahoo];
[1504, Gillian Megan]]
Klasa słownika (TKey, TValue)
Klasa Dictionary (TKey, TValue) reprezentuje zbiór kluczy i wartości.
Poniższe tabele zawierają właściwości, konstruktory i metody klasy List (T) -
Nieruchomości
własność | Opis |
---|---|
Porównaj | Pobiera IEqualityComparer (T), który jest używany do określania równości kluczy dla słownika. |
Liczyć | Pobiera liczbę par klucz / wartość zawartych w Dictionary (TKey, TValue). |
Pozycja | Pobiera lub ustawia wartość skojarzoną z określonym kluczem. |
Klucze | Pobiera kolekcję zawierającą klucze w Dictionary (TKey, TValue). |
Wartości | Pobiera kolekcję zawierającą wartości z Dictionary (TKey, TValue). |
Konstruktorzy
Konstruktorzy | Opis |
---|---|
Słownik (TKey, TValue) () | Inicjuje nowe wystąpienie Dictionary(TKey, TValue) klasa, która jest pusta, ma domyślną pojemność początkową i używa domyślnej funkcji porównującej równość dla typu klucza. |
Słownik (TKey, TValue) (IDictionary (TKey, TValue)) | Inicjuje nowe wystąpienie Dictionary(TKey, TValue) klasa, która zawiera elementy skopiowane z określonego IDictionary(TKey, TValue) i używa domyślnej funkcji porównującej równość dla typu klucza. |
Słownik (TKey, TValue) (IEqualityComparer (TKey)) | Inicjuje nowe wystąpienie Dictionary(TKey, TValue) klasa, która jest pusta, ma domyślną pojemność początkową i używa określonej IEqualityComparer(T). |
Słownik (TKey, TValue) (Int32) | Inicjuje nowe wystąpienie Dictionary(TKey, TValue) klasa, która jest pusta, ma określoną pojemność początkową i używa domyślnej funkcji porównującej równość dla typu klucza. |
Słownik (TKey, TValue) (IDictionary (TKey, TValue), IEqualityComparer (TKey)) | Inicjuje nowe wystąpienie Dictionary(TKey, TValue) klasa, która zawiera elementy skopiowane z określonego IDictionary(TKey, TValue) i używa określonego IEqualityComparer(T). |
Słownik (TKey, TValue) (Int32, IEqualityComparer (TKey)) | Inicjuje nowe wystąpienie Dictionary(TKey, TValue) klasa, która jest pusta, ma określoną pojemność początkową i używa określonej IEqualityComparer(T). |
Słownik (TKey, TValue) (SerializationInfo, StreamingContext) | Inicjuje nowe wystąpienie ictionary(TKey, TValue) klasa z zserializowanymi danymi. |
Metody
metoda | Opis |
---|---|
Dodaj | Dodaje określony klucz i wartość do słownika. |
Jasny | Usuwa wszystkie klucze i wartości ze słownika (TKey, TValue). |
ContainsKey | Określa, czy Dictionary (TKey, TValue) zawiera określony klucz. |
ContainsValue | Określa, czy Dictionary (TKey, TValue) zawiera określoną wartość. |
Równa się (obiekt) | Określa, czy określony obiekt jest równy bieżącemu obiektowi. (Odziedziczone po Object.) |
Sfinalizować | Umożliwia obiektowi próbę zwolnienia zasobów i wykonanie innych operacji czyszczenia, zanim zostanie odzyskany przez wyrzucanie elementów bezużytecznych. (Odziedziczone po Object.) |
GetEnumerator | Zwraca moduł wyliczający, który wykonuje iterację w Dictionary (TKey, TValue). |
GetHashCode | Służy jako domyślna funkcja skrótu. (Odziedziczone po Object.) |
GetObjectData | Implementuje interfejs System.Runtime.Serialization.ISerializable i zwraca dane potrzebne do serializacji wystąpienia Dictionary (TKey, TValue). |
GetType | Pobiera typ bieżącego wystąpienia. (Odziedziczone po Object.) |
MemberwiseClone | Tworzy płytką kopię bieżącego obiektu. (Odziedziczone po Object.) |
OnDeserialization | Implementuje interfejs System.Runtime.Serialization.ISerializable i wywołuje zdarzenie deserializacji po zakończeniu deserializacji. |
Usunąć | Usuwa wartość z określonym kluczem z Dictionary (TKey, TValue). |
ToString | Zwraca ciąg, który reprezentuje bieżący obiekt. (Odziedziczone po Object.) |
TryGetValue | Pobiera wartość skojarzoną z określonym kluczem. |
Przykład
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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"]
Podstawowe wejście Wyjście obejmuje -
- Czytanie i pisanie w konsoli.
- Czytanie zi zapisywanie do pliku.
Moduł Core.Printf
Użyliśmy printf i printfn do zapisu w konsoli. W tej sekcji przyjrzymy się szczegółomPrintf moduł F #.
Oprócz powyższych funkcji, moduł Core.Printf F # ma różne inne metody drukowania i formatowania przy użyciu znaczników% jako symboli zastępczych. Poniższa tabela przedstawia metody wraz z krótkim opisem -
Wartość | Opis |
---|---|
bprintf: StringBuilder → BuilderFormat <'T> →' T | Drukuje do StringBuilder. |
eprintf: TextWriterFormat <'T> →' T | Wyświetla sformatowane wyjście na stderr. |
eprintfn: TextWriterFormat <'T> →' T | Wyświetla sformatowane dane wyjściowe na stderr, dodając nowy wiersz. |
failwithf: StringFormat <'T,' Wynik> → 'T | Drukuje do bufora łańcuchowego i zgłasza wyjątek z podanym wynikiem. |
fprintf: TextWriter → TextWriterFormat <'T> →' T | Drukuje dla autora tekstu. |
fprintfn: TextWriter → TextWriterFormat <'T> →' T | Drukuje do pisarza tekstu, dodając nowy wiersz. |
kbprintf: (jednostka → 'Wynik) → StringBuilder → BuilderFormat <' T, 'Wynik> →' T | Podobnie jak bprintf, ale wywołuje określoną funkcję w celu wygenerowania wyniku. |
kfprintf: (jednostka → 'Wynik) → TextWriter → TextWriterFormat <' T, 'Wynik> →' T | Podobnie jak fprintf, ale wywołuje określoną funkcję w celu wygenerowania wyniku. |
kprintf: (string → 'Wynik) → StringFormat <' T, 'Wynik> →' T | Podobnie jak printf, ale wywołuje określoną funkcję w celu wygenerowania wyniku. Na przykład, pozwalają one drukować na wymuszenie wyrównania po wprowadzeniu całego wyjścia na kanał, ale nie wcześniej. |
ksprintf: (string → 'Wynik) → StringFormat <' T, 'Wynik> →' T | Podobnie jak sprintf, ale wywołuje określoną funkcję, aby wygenerować wynik. |
printf: TextWriterFormat <'T> →' T | Wyświetla sformatowane dane wyjściowe na standardowe wyjście. |
printfn: TextWriterFormat <'T> →' T | Wyświetla sformatowane dane wyjściowe na standardowe wyjście, dodając nowy wiersz. |
sprintf: StringFormat <'T> →' T | Drukuje do ciągu przy użyciu wewnętrznego bufora ciągu i zwraca wynik jako ciąg. |
Specyfikacje formatu
Specyfikacje formatu są używane do formatowania wejścia lub wyjścia, zgodnie z potrzebami programistów.
Są to ciągi znaków ze znacznikami% wskazującymi symbole zastępcze formatu.
Składnia symboli zastępczych formatu to -
%[flags][width][.precision][type]
Plik type jest interpretowane jako -
Rodzaj | Opis |
---|---|
%b | Formaty a bool, sformatowany jako true lub false. |
%do | Formatuje znak. |
% s | Formaty a string, sformatowany jako zawartość, bez interpretowania żadnych znaków zmiany znaczenia. |
% d,% i | Formatuje dowolny podstawowy typ liczby całkowitej sformatowany jako dziesiętna liczba całkowita ze znakiem, jeśli podstawowy typ liczby całkowitej jest podpisany. |
% u | Formatuje dowolny podstawowy typ liczby całkowitej sformatowany jako dziesiętna liczba całkowita bez znaku. |
% x | Formatuje dowolny podstawowy typ liczby całkowitej sformatowany jako liczba szesnastkowa bez znaku, używając małych liter od a do f. |
% X | Formatuje dowolny podstawowy typ liczby całkowitej sformatowany jako liczba szesnastkowa bez znaku, używając wielkich liter od A do F. |
% o | Formatuje dowolny podstawowy typ liczby całkowitej sformatowany jako ósemkowa liczba całkowita bez znaku. |
% e,% E,% f,% F,% g,% G | Formatuje dowolny podstawowy typ zmiennoprzecinkowy (float, float32) sformatowany przy użyciu specyfikacji formatu zmiennoprzecinkowego w stylu C. |
% e,% E | Formatuje wartość ze znakiem mającą postać [-] d.dddde [znak] ddd, gdzie d to pojedyncza cyfra dziesiętna, dddd to jedna lub więcej cyfr dziesiętnych, ddd to dokładnie trzy cyfry dziesiętne, a znak to + lub -. |
%fa | Formatuje wartość ze znakiem w postaci [-] dddd.dddd, gdzie dddd to jedna lub więcej cyfr dziesiętnych. Liczba cyfr przed przecinkiem zależy od wielkości liczby, a liczba cyfr po przecinku zależy od wymaganej dokładności. |
% g,% G | Formatuje podpisaną wartość drukowaną w formacie f lub e, w zależności od tego, który jest bardziej zwarty dla podanej wartości i dokładności. |
% M | Formatuje wartość Decimal. |
% O | Formatuje dowolną wartość, drukowaną przez umieszczenie obiektu w ramce i użycie jego ToString metoda. |
% A,% + A | Formatuje dowolną wartość, drukowaną z domyślnymi ustawieniami układu. Użyj% + A, aby wydrukować strukturę związków rozłącznych z reprezentacjami wewnętrznymi i prywatnymi. |
%za | Ogólny specyfikator formatu wymaga dwóch argumentów. Pierwszy argument to funkcja, która przyjmuje dwa argumenty: pierwszy parametr kontekstu odpowiedniego typu dla danej funkcji formatującej (na przykład TextWriter), a drugi wartość do wydrukowania i która zwraca lub zwraca odpowiedni tekst. Drugi argument to określona wartość do wydrukowania. |
% t | Ogólny specyfikator formatu wymaga jednego argumentu: funkcji, która przyjmuje parametr kontekstu odpowiedniego typu dla danej funkcji formatującej (aTextWriter) i która albo wyprowadza, albo zwraca odpowiedni tekst. Podstawowe typy liczb całkowitych tobyte, sbyte, int16, uint16, int32, uint32, int64, uint64, nativeint, i unativeint. Podstawowe typy zmiennoprzecinkowe to float i float32. |
Plik widthjest opcjonalnym parametrem. Jest to liczba całkowita określająca minimalną szerokość wyniku. Na przykład% 5d drukuje liczbę całkowitą z co najmniej 5 znakami spacji.
Ważny flags opisano w poniższej tabeli -
Wartość | Opis |
---|---|
0 | Określa, aby dodać zera zamiast spacji, aby uzyskać wymaganą szerokość. |
- | Określa wyrównywanie wyniku do lewej w określonej szerokości. |
+ | Określa, że należy dodać znak +, jeśli liczba jest dodatnia (aby dopasować znak - dla liczb ujemnych). |
' ' (przestrzeń) | Określa, że należy dodać dodatkową spację, jeśli liczba jest dodatnia (aby dopasować znak - dla liczb ujemnych). |
# | Nieważny. |
Przykład
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
Klasa konsoli
Ta klasa jest częścią platformy .NET. Reprezentuje standardowe strumienie wejścia, wyjścia i błędów dla aplikacji konsolowych.
Zapewnia różne metody odczytu i zapisu w konsoli. Poniższa tabela przedstawia metody -
metoda | Opis |
---|---|
Brzęczyk() | Odtwarza dźwięk sygnału dźwiękowego przez głośnik konsoli. |
Sygnał dźwiękowy (Int32, Int32) | Odtwarza dźwięk sygnału dźwiękowego o określonej częstotliwości i czasie trwania przez głośnik konsoli. |
Jasny | Czyści bufor konsoli i odpowiednie okno konsoli z wyświetlanymi informacjami. |
MoveBufferArea (Int32, Int32, Int32, Int32, Int32, Int32) | Kopiuje określony obszar źródłowy buforu ekranu do określonego obszaru docelowego. |
MoveBufferArea (Int32, Int32, Int32, Int32, Int32, Int32, Char, ConsoleColor, ConsoleColor) | Kopiuje określony obszar źródłowy buforu ekranu do określonego obszaru docelowego. |
OpenStandardError () | Uzyskuje standardowy strumień błędów. |
OpenStandardError (Int32) | Uzyskuje standardowy strumień błędów, który jest ustawiony na określony rozmiar buforu. |
OpenStandardInput () | Uzyskuje standardowy strumień wejściowy. |
OpenStandardInput (Int32) | Uzyskuje standardowy strumień wejściowy, który jest ustawiony na określony rozmiar buforu. |
OpenStandardOutput () | Uzyskuje standardowy strumień wyjściowy. |
OpenStandardOutput (Int32) | Uzyskuje standardowy strumień wyjściowy, który jest ustawiony na określony rozmiar buforu. |
Czytać | Odczytuje następny znak ze standardowego strumienia wejściowego. |
Kluczem przeczytać() | Uzyskuje następny znak lub klawisz funkcyjny naciśnięty przez użytkownika. Wciśnięty klawisz jest wyświetlany w oknie konsoli. |
ReadKey (wartość logiczna) | Uzyskuje następny znak lub klawisz funkcyjny naciśnięty przez użytkownika. Wciśnięty klawisz jest opcjonalnie wyświetlany w oknie konsoli. |
Czytaj linię | Odczytuje następny wiersz znaków ze standardowego strumienia wejściowego. |
ResetColor | Ustawia domyślne kolory konsoli pierwszego planu i tła. |
SetBufferSize | Ustawia wysokość i szerokość obszaru bufora ekranu na określone wartości. |
SetCursorPosition | Ustawia pozycję kursora. |
SetError | Ustawia właściwość Error na określony obiekt TextWriter . |
SetIn | Ustawia właściwość In na określony obiekt TextReader . |
SetOut | Ustawia właściwość Out na określony obiekt TextWriter . |
SetWindowPosition | Ustawia pozycję okna konsoli względem bufora ekranu. |
SetWindowSize | Ustawia wysokość i szerokość okna konsoli na określone wartości. |
Napisz (wartość logiczna) | Zapisuje tekstową reprezentację określonej wartości logicznej w standardowym strumieniu wyjściowym. |
Napisz (znak) | Zapisuje określoną wartość znaku Unicode w standardowym strumieniu wyjściowym. |
Napisz (Char []) | Zapisuje określoną tablicę znaków Unicode w standardowym strumieniu wyjściowym. |
Zapis (dziesiętny) | Zapisuje tekstową reprezentację określonej wartości Decimal w standardowym strumieniu wyjściowym. |
Napisz (podwójne) | Zapisuje tekstową reprezentację określonej wartości zmiennoprzecinkowej o podwójnej precyzji w standardowym strumieniu wyjściowym. |
Napisz (Int32) | Zapisuje tekstową reprezentację określonej 32-bitowej liczby całkowitej ze znakiem w standardowym strumieniu wyjściowym. |
Napisz (Int64) | Zapisuje tekstową reprezentację określonej 64-bitowej liczby całkowitej ze znakiem w standardowym strumieniu wyjściowym. |
Napisz (obiekt) | Zapisuje tekstową reprezentację określonego obiektu w standardowym strumieniu wyjściowym. |
Napisz (pojedynczy) | Zapisuje tekstową reprezentację określonej wartości zmiennoprzecinkowej o pojedynczej precyzji w standardowym strumieniu wyjściowym. |
Napisz (ciąg) | Zapisuje określoną wartość ciągu w standardowym strumieniu wyjściowym. |
Napisz (UInt32) | Zapisuje tekstową reprezentację określonej 32-bitowej liczby całkowitej bez znaku w standardowym strumieniu wyjściowym. |
Napisz (UInt64) | Zapisuje tekstową reprezentację określonej 64-bitowej liczby całkowitej bez znaku w standardowym strumieniu wyjściowym. |
Napisz (ciąg, obiekt) | Zapisuje tekstową reprezentację określonego obiektu w standardowym strumieniu wyjściowym przy użyciu określonych informacji o formacie. |
Napisz (ciąg, obiekt []) | Zapisuje tekstową reprezentację określonej tablicy obiektów w standardowym strumieniu wyjściowym przy użyciu określonych informacji o formacie. |
Napisz (Char [], Int32, Int32) | Zapisuje określoną podtablicę znaków Unicode w standardowym strumieniu wyjściowym. |
Napisz (ciąg, obiekt, obiekt) | Zapisuje tekstową reprezentację określonych obiektów w standardowym strumieniu wyjściowym przy użyciu określonych informacji o formacie. |
Napisz (ciąg, obiekt, obiekt, obiekt) | Zapisuje tekstową reprezentację określonych obiektów w standardowym strumieniu wyjściowym przy użyciu określonych informacji o formacie. |
Napisz (ciąg, obiekt, obiekt, obiekt, obiekt) | Zapisuje tekstową reprezentację określonych obiektów i listę parametrów o zmiennej długości w standardowym strumieniu wyjściowym przy użyciu określonych informacji o formacie. |
WriteLine () | Zapisuje bieżący terminator linii w standardowym strumieniu wyjściowym. |
WriteLine (Boolean) | Zapisuje tekstową reprezentację określonej wartości logicznej, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (znak) | Zapisuje określony znak Unicode, po którym następuje bieżący terminator wiersza, wartość w standardowym strumieniu wyjściowym. |
WriteLine (Char []) | Zapisuje określoną tablicę znaków Unicode, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (dziesiętny) | Zapisuje tekstową reprezentację określonej wartości Decimal, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (podwójne) | Zapisuje tekstową reprezentację określonej wartości zmiennoprzecinkowej o podwójnej precyzji, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (Int32) | Zapisuje tekstową reprezentację określonej 32-bitowej liczby całkowitej ze znakiem, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (Int64) | Zapisuje tekstową reprezentację określonej 64-bitowej wartości całkowitej ze znakiem, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (obiekt) | Zapisuje tekstową reprezentację określonego obiektu, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (pojedynczy) | Zapisuje tekstową reprezentację określonej wartości zmiennoprzecinkowej o pojedynczej precyzji, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (ciąg) | Zapisuje określoną wartość ciągu, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (UInt32) | Zapisuje tekstową reprezentację określonej 32-bitowej liczby całkowitej bez znaku, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (UInt64) | Zapisuje tekstową reprezentację określonej 64-bitowej wartości całkowitej bez znaku, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (ciąg, obiekt) | Zapisuje tekstową reprezentację określonego obiektu, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym przy użyciu określonych informacji o formacie. |
WriteLine (ciąg, obiekt []) | Zapisuje tekstową reprezentację określonej tablicy obiektów, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym przy użyciu określonych informacji o formacie. |
WriteLine (Char [], Int32, Int32) | Zapisuje określoną podtablicę znaków Unicode, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym. |
WriteLine (ciąg, obiekt, obiekt) | Zapisuje tekstową reprezentację określonych obiektów, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym przy użyciu określonych informacji o formacie. |
WriteLine (ciąg, obiekt, obiekt, obiekt) | Zapisuje tekstową reprezentację określonych obiektów, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym przy użyciu określonych informacji o formacie. |
WriteLine (ciąg, obiekt, obiekt, obiekt, obiekt) | Zapisuje tekstową reprezentację określonych obiektów i listę parametrów o zmiennej długości, po której następuje bieżący terminator wiersza, w standardowym strumieniu wyjściowym przy użyciu określonych informacji o formacie. |
Poniższy przykład demonstruje czytanie z konsoli i pisanie do niej -
Przykład
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()
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
What's your name? Kabir
Hello, Kabir
Big Greetings from TutorialsPoint and Absoulte Classes
|2015-Jan-05|
Przestrzeń nazw System.IO
Przestrzeń nazw System.IO zawiera wiele przydatnych klas do wykonywania podstawowych operacji we / wy.
Zawiera typy lub klasy, które umożliwiają odczytywanie i zapisywanie do plików i strumieni danych oraz typy, które zapewniają podstawową obsługę plików i katalogów.
Klasy przydatne przy pracy z systemem plików -
- Klasa System.IO.File służy do tworzenia, dołączania i usuwania plików.
- Klasa System.IO.Directory służy do tworzenia, przenoszenia i usuwania katalogów.
- Klasa System.IO.Path wykonuje operacje na łańcuchach, które reprezentują ścieżki plików.
- Klasa System.IO.FileSystemWatcher umożliwia użytkownikom nasłuchiwanie katalogu pod kątem zmian.
Klasy przydatne do pracy ze strumieniami (sekwencja bajtów) -
- Klasa System.IO.StreamReader służy do odczytywania znaków ze strumienia.
- Klasa System.IO.StreamWriter służy do zapisywania znaków w strumieniu.
- Klasa System.IO.MemoryStream tworzy w pamięci strumień bajtów.
Poniższa tabela przedstawia wszystkie klasy znajdujące się w przestrzeni nazw wraz z krótkim opisem -
Klasa | Opis |
---|---|
BinaryReader | Odczytuje pierwotne typy danych jako wartości binarne w określonym kodowaniu. |
BinaryWriter | Zapisuje typy pierwotne w postaci binarnej w strumieniu i obsługuje pisanie ciągów w określonym kodowaniu. |
BufferedStream | Dodaje warstwę buforującą do operacji odczytu i zapisu w innym strumieniu. |
Informator | Udostępnia statyczne metody tworzenia, przenoszenia i wyliczania w katalogach i podkatalogach. |
DirectoryInfo | Udostępnia metody instancji służące do tworzenia, przenoszenia i wyliczania w katalogach i podkatalogach. |
DirectoryNotFoundException | Wyjątek, który jest generowany, gdy nie można znaleźć części pliku lub katalogu. |
DriveInfo | Zapewnia dostęp do informacji na dysku. |
DriveNotFoundException | Wyjątek, który jest generowany podczas próby uzyskania dostępu do dysku lub udziału, który nie jest dostępny. |
EndOfStreamException | Wyjątek, który jest generowany podczas próby odczytu po zakończeniu strumienia. |
ErrorEventArgs | Zawiera dane dla zdarzenia FileSystemWatcher.Error. |
Plik | Zapewnia statyczne metody tworzenia, kopiowania, usuwania, przenoszenia i otwierania pojedynczego pliku oraz pomaga w tworzeniu obiektów FileStream. |
FileFormatException | Wyjątek, który jest generowany, gdy plik wejściowy lub strumień danych, który powinien być zgodny z określoną specyfikacją formatu pliku, jest nieprawidłowo sformułowany. |
Informacja o pliku | Zapewnia właściwości i metody instancji do tworzenia, kopiowania, usuwania, przenoszenia i otwierania plików oraz pomaga w tworzeniu obiektów FileStream. |
FileLoadException | Wyjątek, który jest generowany, gdy zostanie znaleziony zestaw zarządzany, ale nie można go załadować. |
FileNotFoundException | Wyjątek, który jest generowany, gdy próba uzyskania dostępu do pliku, który nie istnieje na dysku, kończy się niepowodzeniem. |
FileStream | Udostępnia Stream wokół pliku, obsługując synchroniczne i asynchroniczne operacje odczytu i zapisu. |
FileSystemEventArgs | Zawiera dane dotyczące zdarzeń w katalogu - Zmienione, Utworzone, Usunięte. |
FileSystemInfo | Udostępnia klasę bazową dla obiektów FileInfo i DirectoryInfo. |
FileSystemWatcher | Nasłuchuje powiadomień o zmianach systemu plików i zgłasza zdarzenia, gdy katalog lub plik w katalogu ulegają zmianie. |
InternalBufferOverflowException | Wyjątek zgłaszany w przypadku przepełnienia buforu wewnętrznego. |
InvalidDataException | Wyjątek, który jest generowany, gdy strumień danych ma nieprawidłowy format. |
IODescriptionAttribute | Ustawia opis, który projektanci wizualni mogą wyświetlać podczas odwoływania się do zdarzenia, rozszerzenia lub właściwości. |
IOException | Wyjątek, który jest generowany, gdy wystąpi błąd we / wy. |
MemoryStream | Tworzy strumień, którego magazynem zapasowym jest pamięć. |
Ścieżka | Wykonuje operacje na instancjach typu String, które zawierają informacje o ścieżce do pliku lub katalogu. Operacje te są wykonywane w sposób wieloplatformowy. |
PathTooLongException | Wyjątek, który jest generowany, gdy ścieżka lub nazwa pliku jest dłuższa niż maksymalna długość zdefiniowana przez system. |
PipeException | Zgłaszane, gdy wystąpi błąd w nazwanym potoku. |
RenamedEventArgs | Zawiera dane dla zdarzenia o zmienionej nazwie. |
Strumień | Zawiera ogólny widok sekwencji bajtów. To jest klasa abstrakcyjna. |
StreamReader | Implementuje TextReader, który odczytuje znaki ze strumienia bajtów w określonym kodowaniu. |
StreamWriter | Implementuje TextWriter do pisania znaków w strumieniu w określonym kodowaniu. Aby przeglądać kod źródłowy .NET Framework dla tego typu, zobacz źródło odniesienia. |
StringReader | Implementuje TextReader, który odczytuje ciąg. |
StringWriter | Implementuje TextWriter do zapisywania informacji w ciągu. Informacje są przechowywane w źródłowym StringBuilder. |
TextReader | Reprezentuje czytelnika, który może odczytać sekwencyjną serię znaków. |
TextWriter | Reprezentuje pisarza, który może pisać sekwencyjną serię znaków. Ta klasa jest abstrakcyjna. |
UnmanagedMemoryAccessor | Zapewnia losowy dostęp do niezarządzanych bloków pamięci z kodu zarządzanego. |
UnmanagedMemoryStream | Zapewnia dostęp do niezarządzanych bloków pamięci z kodu zarządzanego. |
WindowsRuntimeStorageExtensions | Zawiera metody rozszerzające dla interfejsów IStorageFile i IStorageFolder w środowisku wykonawczym systemu Windows podczas tworzenia aplikacji ze Sklepu Windows. |
WindowsRuntimeStreamExtensions | Zawiera metody rozszerzenia służące do konwertowania między strumieniami w środowisku wykonawczym systemu Windows i strumieniami zarządzanymi w aplikacji .NET for Windows Store. |
Przykład
Poniższy przykład tworzy plik o nazwie test.txt, zapisuje tam wiadomość, odczytuje tekst z pliku i drukuje go na konsoli.
Note - Ilość kodu potrzebnego do tego jest zaskakująco mniejsza!
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Hello There
Welcome to:
Tutorials Point
Generics pozwalają opóźnić specyfikację typu danych elementów programistycznych w klasie lub metodzie, dopóki nie zostaną one faktycznie użyte w programie. Innymi słowy, typy ogólne umożliwiają napisanie klasy lub metody, która może działać z dowolnym typem danych.
Piszesz specyfikacje dla klasy lub metody, zastępując parametry dla typów danych. Gdy kompilator napotka konstruktor dla klasy lub wywołanie funkcji dla metody, generuje kod obsługujący określony typ danych.
W języku F # wartości funkcji, metody, właściwości i typy agregatów, takie jak klasy, rekordy i związki rozłączne, mogą być ogólne.
Konstrukcje ogólne zawierają co najmniej jeden parametr typu. Funkcje i typy ogólne umożliwiają pisanie kodu, który działa z różnymi typami bez powtarzania kodu dla każdego typu.
Składnia
Składnia do pisania konstrukcji ogólnej jest następująca -
// 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
Przykłady
(* Generic Function *)
let printFunc<'T> x y =
printfn "%A, %A" x y
printFunc<float> 10.0 20.0
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
10.0, 20.0
Możesz również utworzyć funkcję ogólną, używając składni pojedynczego cudzysłowu -
(* Generic Function *)
let printFunction (x: 'a) (y: 'a) =
printfn "%A %A" x y
printFunction 10.0 20.0
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
10.0 20.0
Należy pamiętać, że podczas korzystania z funkcji lub metod ogólnych może nie być konieczne określanie argumentów typu. Jednak w przypadku niejednoznaczności można podać argumenty typu w nawiasach ostrych, tak jak to zrobiliśmy w pierwszym przykładzie.
Jeśli masz więcej niż jeden typ, oddziel argumenty wielu typów przecinkami.
Klasa ogólna
Podobnie jak funkcje ogólne, można również pisać klasy ogólne. Poniższy przykład demonstruje to -
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) } )
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
"zara"
seq [(1, 1); (2, 4); (3, 9); (4, 16); ...]
Delegat to zmienna typu referencyjnego, która przechowuje odwołanie do metody. Odniesienie można zmienić w czasie wykonywania. Delegaci F # są podobne do wskaźników do funkcji w C lub C ++.
Deklarowanie delegatów
Deklaracja delegata określa metody, do których może odwoływać się delegat. Delegat może odwoływać się do metody, która ma taki sam podpis, jak podpis delegata.
Składnia deklaracji delegata to -
type delegate-typename = delegate of type1 -> type2
Na przykład rozważmy delegatów -
// Delegate1 works with tuple arguments.
type Delegate1 = delegate of (int * int) -> int
// Delegate2 works with curried arguments.
type Delegate2 = delegate of int * int -> int
Obaj delegaci mogą służyć do odwoływania się do dowolnej metody, która ma dwa parametry int i zwraca zmienną typu int .
W składni -
type1 reprezentuje typ (y) argumentów.
type2 reprezentuje typ zwrotu.
Uwaga -
Typy argumentów są automatycznie przypisywane.
Delegatów można dołączyć do wartości funkcji i metod statycznych lub instancji.
Wartości funkcji F # można przekazywać bezpośrednio jako argumenty do konstruktorów delegatów.
W przypadku metody statycznej delegat jest wywoływany przy użyciu nazwy klasy i metody. W przypadku metody instancji używana jest nazwa instancji obiektu i metody.
Metoda Invoke dla typu delegata wywołuje hermetyzowaną funkcję.
Ponadto delegatów można przekazywać jako wartości funkcji, odwołując się do nazwy metody Invoke bez nawiasów.
Poniższy przykład ilustruje koncepcję -
Przykład
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)
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
400 + 200 = 600
400 - 200 = 200
400 + 200 = 600
400 - 200 = 200
100 + 45 = 145
100 - 45 = 55
100 + 45 = 145
100 - 45 = 55
Wyliczenie to zbiór nazwanych stałych całkowitych.
W F #, enumerations, znany również jako enums,są typami całkowitymi, w których etykiety są przypisane do podzbioru wartości. Możesz ich używać zamiast literałów, aby kod był bardziej czytelny i łatwiejszy w utrzymaniu.
Deklarowanie wyliczeń
Ogólna składnia deklarowania wyliczenia to -
type enum-name =
| value1 = integer-literal1
| value2 = integer-literal2
...
Poniższy przykład demonstruje użycie wyliczeń -
Przykład
// 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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Monday: Mon
Saturday: Sat
Sunday: Sun
Dopasowywanie wzorców umożliwia „porównywanie danych z logiczną strukturą lub strukturami, rozkładanie danych na części składowe lub wyodrębnianie informacji z danych na różne sposoby”.
Innymi słowy, zapewnia bardziej elastyczny i skuteczniejszy sposób testowania danych pod kątem szeregu warunków i wykonywania niektórych obliczeń w oparciu o spełniony warunek.
Koncepcyjnie przypomina serię stwierdzeń „jeśli… to”.
Składnia
Mówiąc ogólnie, dopasowanie wzorców jest zgodne z tą składnią w języku F # -
match expr with
| pat1 - result1
| pat2 -> result2
| pat3 when expr2 -> result3
| _ -> defaultResult
Gdzie,
- Każdy | symbol określa warunek.
- Symbol -> oznacza „jeśli warunek jest prawdziwy, zwróć tę wartość ...”.
- Symbol _ zapewnia domyślny wzorzec, co oznacza, że pasuje do wszystkich innych rzeczy, takich jak symbol wieloznaczny.
Przykład 1
Poniższy przykład oblicza liczby Fibonacciego przy użyciu składni dopasowania wzorców -
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)
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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
Możesz również połączyć wiele warunków, które zwracają tę samą wartość. Na przykład -
Przykład 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"
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Winter
Spring
Autumn
Rainy
Funkcje dopasowania wzorców
F # umożliwia pisanie funkcji dopasowywania wzorców przy użyciu function słowo kluczowe -
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")
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
10
20.5
21
8.75
15
Dodawanie filtrów lub osłon do wzorców
Możesz dodać filtry lub osłony do wzorców przy użyciu rozszerzenia when słowo kluczowe.
Przykład 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)
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
-1
1
0
Przykład 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)
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
11 is less than 25
72 is greater than 10
0 equals 0
Dopasowywanie wzorców z krotkami
Poniższy przykład ilustruje dopasowanie wzorca za pomocą krotek -
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"))
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Hello, Zara
Hello, Raman from the department of Computer Sc.
You are not registered into the system
Dopasowanie wzorców do rekordów
Poniższy przykład demonstruje dopasowanie wzorców z rekordami -
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 }
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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).
Wyjątkiem jest problem, który pojawia się podczas wykonywania programu. Wyjątek F # jest odpowiedzią na wyjątkowe okoliczności, które pojawiają się podczas działania programu, na przykład próbę podzielenia przez zero.
Wyjątki umożliwiają przekazanie kontroli z jednej części programu do drugiej. Obsługa wyjątków F # zapewnia następujące konstrukcje -
Zbudować | Opis |
---|---|
podnieść wyr | Podnosi podany wyjątek. |
failwith expr | Podnosi System.Exception wyjątek. |
spróbuj wyrażenie z regułami | Łapie wyrażenia pasujące do reguł wzorców. |
spróbuj wyrażenie w końcu wyr | Wykonanie finally wyrażenie zarówno w przypadku pomyślnego obliczenia, jak i zgłoszenia wyjątku. |
| :? ArgumentException | Reguła pasująca do danego typu wyjątku .NET. |
| :? ArgumentException jako e | Reguła pasująca do danego typu wyjątku .NET, wiążąca nazwę e do wartości obiektu wyjątku. |
| Błąd (msg) → wyr | Reguła pasująca do danego wyjątku F # przenoszącego dane. |
| exn → wyr | Reguła pasująca do każdego wyjątku, wiążąca nazwę exn do wartości obiektu wyjątku. |
| exn when expr → expr | Reguła pasująca do wyjątku pod zadanym warunkiem, wiążąca nazwę exn do wartości obiektu wyjątku. |
Zacznijmy od podstawowej składni obsługi wyjątków.
Składnia
Podstawowa składnia dla bloku obsługi wyjątków F # to -
exception exception-type of argument-type
Gdzie,
exception-type to nazwa nowego typu wyjątku F #.
argument-type reprezentuje typ argumentu, który można podać, gdy zgłosisz wyjątek tego typu.
Można określić wiele argumentów, używając typu krotki dla typu argumentu.
Plik try...with wyrażenie jest używane do obsługi wyjątków w języku F #.
Składnia try… z wyrażeniem to -
try
expression1
with
| pattern1 -> expression2
| pattern2 -> expression3
...
Plik try...finally wyrażenie umożliwia wykonanie czystego kodu, nawet jeśli blok kodu zgłasza wyjątek.
Składnia try… na końcu wyrażenie to -
try
expression1
finally
expression2
Plik raiseFunkcja służy do wskazania, że wystąpił błąd lub wyjątkowy stan. Przechwytuje również informacje o błędzie w obiekcie wyjątku.
Składnia funkcji podbicia to -
raise (expression)
Plik failwith funkcja generuje wyjątek F #.
Składnia funkcji failwith to -
failwith error-message-string
Plik invalidArg funkcja generuje wyjątek argumentu.
invalidArg parameter-name error-message-string
Przykład obsługi wyjątków
Przykład 1
Poniższy program przedstawia podstawową obsługę wyjątków za pomocą prostego try… with block -
let divisionprog x y =
try
Some (x / y)
with
| :? System.DivideByZeroException -> printfn "Division by zero!"; None
let result1 = divisionprog 100 0
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Division by zero!
Przykład 2
F # zapewnia exceptionwpisz do deklarowania wyjątków. Możesz użyć typu wyjątku bezpośrednio w filtrach w plikutry...with wyrażenie.
Poniższy przykład demonstruje to -
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Error2 Error Not detected 100
Error1 Equal Number Error
Przykład 3
Poniższy przykład demonstruje obsługę zagnieżdżonych wyjątków -
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
From the finally block.
Error: outer error
Error:inner error
From the finally block.
From the finally block.
Error: outer error
Przykład 4
Poniższa funkcja demonstruje failwith funkcja -
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Divisor cannot be zero.
0
25
Przykład 5
Plik invalidArgfunkcja generuje wyjątek argumentu. Poniższy program demonstruje to -
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)
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Sunday
Thursday
Unhandled Exception:
System.ArgumentException: You have entered 9.
…
W zależności od systemu zostaną również wyświetlone inne informacje o pliku i zmiennej powodującej błąd w systemie.
Klasy to typy reprezentujące obiekty, które mogą mieć właściwości, metody i zdarzenia. „Służą do modelowania działań, procesów i wszelkich bytów pojęciowych w aplikacjach”.
Składnia
Składnia definiowania typu klasy jest następująca -
// 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 ...
...
Gdzie,
Plik type-nameto dowolny prawidłowy identyfikator. Domyślnym modyfikatorem dostępu jestpublic.
Plik type-params opisuje opcjonalne parametry typu ogólnego.
Plik parameter-listopisuje parametry konstruktora. Domyślnym modyfikatorem dostępu dla głównego konstruktora jestpublic.
Plik identifier używany z opcjonalnym as słowo kluczowe nadaje nazwę zmiennej instancji lub self-identifier, których można użyć w definicji typu, aby odwołać się do wystąpienia typu.
Plik inherit słowo kluczowe umożliwia określenie klasy bazowej dla klasy.
Plik let powiązania umożliwiają deklarowanie pól lub wartości funkcji lokalnie dla klasy.
Plik do-bindings sekcja zawiera kod, który ma być wykonany podczas budowy obiektu.
Plik member-list składa się z dodatkowych konstruktorów, deklaracji instancji i metod statycznych, deklaracji interfejsów, powiązań abstrakcyjnych oraz deklaracji właściwości i zdarzeń.
Słowa kluczowe class i end zaznaczające początek i koniec definicji są opcjonalne.
Konstruktor klasy
Konstruktor to kod, który tworzy instancję typu klasy.
W języku F # konstruktory działają trochę inaczej niż inne języki .Net. W definicji klasy argumenty konstruktora podstawowego są opisane jako lista-parametrów.
Ciało konstruktora składa się z let i do wiązania.
Możesz dodać dodatkowe konstruktory, używając słowa kluczowego new, aby dodać członka -
new (argument-list) = constructor-body
Poniższy przykład ilustruje koncepcję -
Przykład
Poniższy program tworzy klasę linii wraz z konstruktorem, który oblicza długość linii podczas tworzenia obiektu klasy -
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)
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Creating Line: {(1, 1), (4, 5)}
Length: 5
Niech Bindings
Powiązania let w definicji klasy umożliwiają definiowanie pól prywatnych i funkcji prywatnych dla klas 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")
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Hello Zara
Zwróć uwagę na użycie własnego identyfikatora gr dla klasy Greetings .
Struktura w F # jest typem danych typu wartości. Pomaga tworzyć pojedynczą zmienną, przechowywać powiązane dane różnych typów danych. Plikstruct słowo kluczowe służy do tworzenia struktury.
Składnia
Składnia definiowania struktury jest następująca -
[ attributes ]
type [accessibility-modifier] type-name =
struct
type-definition-elements
end
// or
[ attributes ]
[<StructAttribute>]
type [accessibility-modifier] type-name =
type-definition-elements
Istnieją dwie składnie. Najczęściej używana jest pierwsza składnia, ponieważ jeśli używaszstruct i end słowa kluczowe, możesz pominąć StructAttribute atrybut.
Elementy definicji konstrukcji zapewniają -
- Deklaracje i definicje członków.
- Konstruktory oraz zmienne i niezmienne pola.
- Członkowie i implementacje interfejsów.
W przeciwieństwie do klas, struktury nie mogą być dziedziczone i nie mogą zawierać powiązań let lub do. Ponieważ struktury nie pozwalają na powiązania; musisz zadeklarować pola w strukturach przy użyciuval słowo kluczowe.
Podczas definiowania pola i jego typu za pomocą valsłowo kluczowe, nie można zainicjować wartości pola, zamiast tego są one inicjowane na zero lub null. Tak więc w przypadku struktury mającej niejawny konstruktor,val deklaracje należy opatrzyć adnotacją DefaultValue atrybut.
Przykład
Poniższy program tworzy strukturę liniową wraz z konstruktorem. Program oblicza długość linii na podstawie struktury -
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Length of the Line: 5
Możesz ponownie zdefiniować lub przeciążać większość wbudowanych operatorów dostępnych w języku F #. W ten sposób programista może również używać operatorów z typami zdefiniowanymi przez użytkownika.
Operatory to funkcje o specjalnych nazwach, umieszczonych w nawiasach. Muszą być zdefiniowane jako statyczne elementy klasy. Podobnie jak każda inna funkcja, przeciążony operator ma typ zwracany i listę parametrów.
Poniższy przykład przedstawia operator + na liczbach zespolonych -
//overloading + operator
static member (+) (a : Complex, b: Complex) =
Complex(a.x + b.x, a.y + b.y)
Powyższa funkcja implementuje operator dodawania (+) dla klasy Complex zdefiniowanej przez użytkownika. Dodaje atrybuty dwóch obiektów i zwraca wynikowy obiekt Complex.
Implementacja przeciążania operatorów
Poniższy program przedstawia pełną realizację -
//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())
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
7 5
4.2 3.1
11.2 8.1
2.8 1.9
Jedną z najważniejszych koncepcji programowania obiektowego jest dziedziczenie. Dziedziczenie pozwala nam zdefiniować klasę pod względem innej klasy, co ułatwia tworzenie i utrzymywanie aplikacji. Daje to również możliwość ponownego wykorzystania funkcjonalności kodu i szybkiego czasu implementacji.
Tworząc klasę, zamiast pisać zupełnie nowe składowe danych i funkcje składowe, programista może wyznaczyć, że nowa klasa powinna dziedziczyć składowe istniejącej klasy. Ta istniejąca klasa jest nazywana klasą bazową, a nowa klasa jest nazywana klasą pochodną.
Idea dziedziczenia implementuje relację IS-A. Na przykład, ssak JEST zwierzęciem, pies IS-A ssak, a więc pies również jest zwierzęciem IS-A i tak dalej.
Klasa podstawowa i podklasa
Podklasa pochodzi z klasy bazowej, która jest już zdefiniowana. Podklasa dziedziczy członków klasy bazowej, a także ma swoich własnych członków.
Podklasa jest definiowana przy użyciu inherit słowo kluczowe, jak pokazano poniżej -
type MyDerived(...) =
inherit MyBase(...)
W języku F # klasa może mieć co najwyżej jedną bezpośrednią klasę bazową. Jeśli nie określisz klasy bazowej przy użyciuinherit słowo kluczowe, klasa dziedziczy niejawnie po Object.
Uwaga -
Metody i elementy członkowskie klasy bazowej są dostępne dla użytkowników klasy pochodnej, podobnie jak bezpośredni członkowie klasy pochodnej.
Niech powiązania i parametry konstruktora są prywatne dla klasy i dlatego nie można uzyskać do nich dostępu z klas pochodnych.
Słowo kluczowe baseodnosi się do wystąpienia klasy bazowej. Jest używany jako własny identyfikator.
Przykład
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()
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Hi, I'm Mohan
Hi, I'm Zara
Hi, I'm Mariam
Metody zastępujące
Można przesłonić domyślne zachowanie metody klasy bazowej i zaimplementować je inaczej w podklasie lub klasie pochodnej.
Metody w języku F # nie są domyślnie zastępowalne.
Aby przesłonić metody w klasie pochodnej, musisz zadeklarować swoją metodę jako możliwą do zastąpienia przy użyciu abstract i default słowa kluczowe w następujący sposób -
type Person(name) =
member x.Name = name
abstract Greet : unit -> unit
default x.Greet() = printfn "Hi, I'm %s" x.Name
Teraz metodę Greet klasy Person można zastąpić w klasach pochodnych. Poniższy przykład demonstruje to -
Przykład
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()
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Hi, I'm Mohan
Student Zara
Teacher Mariam.
Klasa abstrakcyjna
Czasami trzeba zapewnić niepełną implementację obiektu, który w rzeczywistości nie powinien być implementowany. Później jakiś inny programista powinien utworzyć podklasy klasy abstrakcyjnej do pełnej implementacji.
Na przykład klasa Person nie będzie potrzebna w systemie zarządzania szkołą. Jednak klasa ucznia lub nauczyciela będzie potrzebna. W takich przypadkach można zadeklarować klasę Person jako klasę abstrakcyjną.
Plik AbstractClass atrybut mówi kompilatorowi, że klasa ma kilka abstrakcyjnych członków.
Nie można utworzyć wystąpienia klasy abstrakcyjnej, ponieważ klasa ta nie jest w pełni zaimplementowana.
Poniższy przykład demonstruje to -
Przykład
[<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()
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Student Zara
Teacher Mariam.
Interfejsy zapewniają abstrakcyjny sposób zapisywania szczegółów implementacji klasy. Jest to szablon, który deklaruje metody, które klasa musi zaimplementować i ujawnić publicznie.
Składnia
Interfejs określa zestawy powiązanych elementów, które implementują inne klasy. Ma następującą składnię -
// 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
Uwaga -
W deklaracji interfejsu członkowie nie są zaimplementowani.
Członkowie są abstrakcyjni, zadeklarowani przez abstractsłowo kluczowe. Możesz jednak podać domyślną implementację przy użyciudefault słowo kluczowe.
Interfejsy można zaimplementować za pomocą wyrażeń obiektów lub typów klas.
W implementacji klas lub obiektów musisz dostarczyć treści metod dla abstrakcyjnych metod interfejsu.
Słowa kluczowe interface i end, które oznaczają początek i koniec definicji, są opcjonalne.
Na przykład,
type IPerson =
abstract Name : string
abstract Enter : unit -> unit
abstract Leave : unit -> unit
Wywołanie metod interfejsu
Metody interfejsu są wywoływane za pośrednictwem interfejsu, a nie przez wystąpienie klasy lub typu implementującego interfejs. Aby wywołać metodę interfejsu, należy przesłać rzutowanie do typu interfejsu przy użyciu:> operator (operator upcast).
Na przykład,
(s :> IPerson).Enter()
(s :> IPerson).Leave()
Poniższy przykład ilustruje koncepcję -
Przykład
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()
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Student entering premises!
Student leaving premises!
Stuff member entering premises!
Stuff member leaving premises!
Dziedziczenie interfejsu
Interfejsy mogą dziedziczyć z jednego lub więcej interfejsów podstawowych.
Poniższy przykład przedstawia koncepcję -
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))
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
10
15
5
Zdarzenia umożliwiają klasom wysyłanie i odbieranie wiadomości między sobą.
W graficznym interfejsie użytkownika zdarzenia to działania użytkownika, takie jak naciśnięcie klawisza, kliknięcia, ruchy myszy itp. Lub pewne zdarzenia, takie jak powiadomienia generowane przez system. Aplikacje muszą reagować na pojawiające się zdarzenia. Na przykład przerywa. Zdarzenia służą do komunikacji między procesami.
Obiekty komunikują się ze sobą poprzez synchroniczne przekazywanie wiadomości.
Wydarzenia są powiązane z innymi funkcjami; rejestr obiektówcallback funkcje do zdarzenia, a te wywołania zwrotne są wykonywane, gdy (i jeśli) zdarzenie jest wyzwalane przez jakiś obiekt.
Klasa zdarzenia i moduł zdarzeń
Klasa Control.Event <'T> pomaga w tworzeniu obserwowalnego obiektu lub zdarzenia.
Ma następujących członków instancji do pracy ze zdarzeniami:
Członek | Opis |
---|---|
Publikować | Publikuje obserwację jako wartość pierwszej klasy. |
Cyngiel | Uruchamia obserwację przy użyciu podanych parametrów. |
Moduł Control.Event zapewnia funkcje do zarządzania strumieniami zdarzeń -
Wartość | Opis |
---|---|
dodaj: ('T → jednostka) → Zdarzenie <' Del, 'T> → jednostka | Uruchamia daną funkcję za każdym razem, gdy zostanie wyzwolone dane zdarzenie. |
wybierz: (opcja 'T →' U) → IEvent <'Del,' T> → IEvent <'U> | Zwraca nowe zdarzenie, które jest uruchamiane na wybranych wiadomościach z pierwotnego zdarzenia. Funkcja wyboru przenosi oryginalną wiadomość do opcjonalnej nowej wiadomości. |
filter: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> | Zwraca nowe zdarzenie, które nasłuchuje pierwotnego zdarzenia i wyzwala wynikowe zdarzenie tylko wtedy, gdy argument zdarzenia przekazuje daną funkcję. |
mapa: ('T →' U) → IEvent <'Del,' T> → IEvent <'U> | Zwraca nowe zdarzenie, które przekazuje wartości przekształcone przez daną funkcję. |
scal: IEvent <'Del1,' T> → IEvent <'Del2,' T> → IEvent <'T> | Uruchamia zdarzenie wyjściowe, gdy jedno ze zdarzeń wejściowych jest uruchamiane. |
parami: IEvent <'Del,' T> → IEvent <'T *' T> | Zwraca nowe zdarzenie, które jest wyzwalane przy drugim i kolejnym wyzwoleniu zdarzenia wejściowego. PlikNth wyzwolenie zdarzenia wejściowego powoduje przekazanie argumentów z N-1th i Nthwyzwalanie jako para. Argument przekazany doN-1th wyzwalanie jest utrzymywane w ukrytym stanie wewnętrznym do czasu Nth następuje wyzwalanie. |
partycja: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> * IEvent <'T> | Zwraca nowe zdarzenie, które nasłuchuje pierwotnego zdarzenia i wyzwala pierwsze zdarzenie wynikowe, jeśli zastosowanie predykatu do argumentów zdarzenia zwróciło wartość true, a drugie zdarzenie, jeśli zwróciło wartość false. |
skanowanie: ('U →' T → 'U) →' U → IEvent <'Del,' T> → IEvent <'U> | Zwraca nowe zdarzenie składające się z wyników zastosowania danej funkcji sumującej do kolejnych wartości wyzwalanych w zdarzeniu wejściowym. Pozycja stanu wewnętrznego rejestruje bieżącą wartość parametru stanu. Stan wewnętrzny nie jest blokowany podczas wykonywania funkcji akumulacji, dlatego należy uważać, aby wejście IEvent nie było wyzwalane przez wiele wątków jednocześnie. |
split: ('T → Wybór <' U1, 'U2>) → IEvent <' Del, 'T> → IEvent <' U1> * IEvent <'U2> | Zwraca nowe zdarzenie, które nasłuchuje oryginalnego zdarzenia i wyzwala pierwsze zdarzenie wynikowe, jeśli zastosowanie funkcji do argumentów zdarzenia zwróciło Choice1Of2, a drugie zdarzenie, jeśli zwróci Choice2Of2. |
Tworzenie wydarzeń
Zdarzenia są tworzone i używane za pośrednictwem Eventklasa. Konstruktor Event służy do tworzenia zdarzenia.
Przykład
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
Następnie musisz ujawnić pole nameChanged jako publiczny element członkowski, aby nasłuchujący mogli podłączyć się do zdarzenia, dla którego używasz Publish własność imprezy -
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 *)
Następnie dodajesz wywołania zwrotne do programów obsługi zdarzeń. Każdy program obsługi zdarzeń ma typ IEvent <'T>, który udostępnia kilka metod -
metoda | Opis |
---|---|
val Dodaj: zdarzenie :( 'T → jednostka) → jednostka | Łączy funkcję detektora ze zdarzeniem. Odbiornik zostanie wywołany po uruchomieniu zdarzenia. |
val AddHandler: 'del → unit | Łączy obiekt delegata programu obsługi ze zdarzeniem. Program obsługi można później usunąć za pomocą RemoveHandler. Odbiornik zostanie wywołany po uruchomieniu zdarzenia. |
val RemoveHandler: 'del → unit | Usuwa delegata nasłuchiwania z magazynu nasłuchiwania zdarzeń. |
Poniższa sekcja zawiera pełny przykład.
Przykład
Poniższy przykład demonstruje koncepcję i techniki omówione powyżej -
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"
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
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!
Zgodnie z biblioteką MSDN moduł F # to grupa konstrukcji kodu F #, takich jak typy, wartości, wartości funkcji i kod w powiązaniach do. Jest implementowana jako klasa środowiska uruchomieniowego języka wspólnego (CLR), która ma tylko statyczne elementy członkowskie.
W zależności od sytuacji, czy cały plik jest zawarty w module, istnieją dwa rodzaje deklaracji modułu -
- Deklaracja modułu najwyższego poziomu
- Deklaracja modułu lokalnego
W deklaracji modułu najwyższego poziomu cały plik jest zawarty w module. W tym przypadku pierwszą deklaracją w pliku jest deklaracja modułu. Nie musisz wciskać deklaracji w module najwyższego poziomu.
W deklaracji modułu lokalnego tylko deklaracje, które są wcięte w tej deklaracji modułu, są częścią modułu.
Składnia
Składnia deklaracji modułu jest następująca -
// Top-level module declaration.
module [accessibility-modifier] [qualified-namespace.]module-name
declarations
// Local module declaration.
module [accessibility-modifier] module-name =
declarations
Należy pamiętać, że modyfikatorem dostępności może być jeden z następujących - publiczny, prywatny, wewnętrzny. Wartość domyślna topublic.
Poniższe przykłady zademonstrują koncepcje -
Przykład 1
Plik modułu 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
Plik programu 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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
34
16
225
2
110
90
1000
10
Przykład 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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
125
325
ZA namespacema na celu zapewnienie sposobu na oddzielenie jednego zestawu nazw od drugiego. Nazwy klas zadeklarowane w jednej przestrzeni nazw nie będą kolidować z tymi samymi nazwami klas zadeklarowanymi w innej.
Zgodnie z biblioteką MSDN, plik namespace pozwala uporządkować kod w obszary powiązanych funkcji, umożliwiając dołączenie nazwy do grupy elementów programu.
Deklarowanie przestrzeni nazw
Aby zorganizować kod w przestrzeni nazw, musisz zadeklarować przestrzeń nazw jako pierwszą deklarację w pliku. Zawartość całego pliku staje się wtedy częścią przestrzeni nazw.
namespace [parent-namespaces.]identifier
Poniższy przykład ilustruje koncepcję -
Przykład
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
Kiedy kompilujesz i wykonujesz program, daje on następujący wynik -
Values from Module1: ("one", "two", "three") 150
Values from Module2: seq [1; 4; 9; 16; ...] 200