F # - Краткое руководство

F # - это функциональный язык программирования. Чтобы понять конструкции F #, вам нужно прочитать пару строк о парадигме программирования под названиемFunctional Programming.

Функциональное программирование рассматривает компьютерные программы как математические функции. В функциональном программировании основное внимание будет уделяться константам и функциям, а не переменным и состояниям. Потому что функции и константы не меняются.

В функциональном программировании вы будете писать модульные программы, т. Е. Программы будут состоять из функций, которые будут принимать другие функции в качестве входных данных.

Программы, написанные на языке функционального программирования, обычно краткие.

О F #

Ниже приводится основная информация о F # -

  • Он был разработан в 2005 году в Microsoft Research.
  • Это часть семейства языков Microsoft .Net.
  • Это функциональный язык программирования.
  • Он основан на функциональном языке программирования OCaml.

Особенности F #

  • Это реализация OCaml .Net.

  • Он компилирует байт-код .Net CLI (Common Language Interface) или MSIL (Microsoft Intermediate Language), который работает в CLR (Common Language Runtime).

  • Он обеспечивает вывод типа.

  • Он предоставляет богатые конструкции сопоставления с образцом.

  • Он имеет возможности интерактивного написания сценариев и отладки.

  • Это позволяет писать функции более высокого порядка.

  • Он предоставляет хорошо разработанную объектную модель.

Использование F #

F # обычно используется в следующих областях -

  • Создание научной модели
  • Решение математических задач
  • Исследования в области искусственного интеллекта
  • Финансовое моделирование
  • Графический дизайн
  • Конструкция процессора
  • Программирование компилятора
  • Telecommunications

Он также используется в приложениях CRUD, веб-страницах, играх с графическим интерфейсом и других программах общего назначения.

В этой главе обсуждаются инструменты, необходимые для программирования на F #.

Интегрированная среда разработки (IDE) для F #

Microsoft предоставляет Visual Studio 2013 для программирования на F #.

Бесплатная версия Visual Studio 2013 Community Edition доступна на официальном сайте Microsoft. Сообщество Visual Studio 2013 и выше поставляется с инструментами Visual F #. Подробные сведения об установке доступны на сайте Asp.net Tutorial . Visual F # Tools включает компилятор командной строки (fsc.exe) и F # Interactive (fsi.exe).

Используя эти инструменты, вы можете писать все виды программ на F # от простых приложений командной строки до более сложных приложений. Вы также можете писать файлы исходного кода F # с помощью простого текстового редактора, такого как Блокнот, и компилировать код в сборки с помощью компилятора командной строки.

Вы можете скачать его из Microsoft Visual Studio. Он автоматически устанавливается на ваш компьютер.

Написание программ на F # по ссылкам

Посетите официальный сайт F # для получения последних инструкций по получению инструментов в виде пакета Debian или их компиляции непосредственно из источника - https://fsharp.org/use/linux/.

F # - это язык функционального программирования.

В F # функции работают как типы данных. Вы можете объявить и использовать функцию так же, как любую другую переменную.

Как правило, приложение F # не имеет конкретной точки входа. Компилятор выполняет все операторы верхнего уровня в файле сверху вниз.

Однако, чтобы следовать процедурному стилю программирования, многие приложения сохраняют один оператор верхнего уровня, который вызывает основной цикл.

Следующий код показывает простую программу F # -

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

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

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

main()

Когда вы компилируете и выполняете программу, она дает следующий результат:

sign 5: positive

Обратите внимание, что -

  • Файл кода F # может начинаться с нескольких open операторы, которые используются для импорта пространств имен.

  • В теле файлов есть другие функции, реализующие бизнес-логику приложения.

  • Основной цикл содержит самые популярные исполняемые операторы.

Вы видели базовую структуру программы F #, поэтому вам будет легко понять другие базовые строительные блоки языка программирования F #.

Токены в F #

Программа F # состоит из различных токенов. Токеном может быть ключевое слово, идентификатор, константа, строковый литерал или символ. Мы можем разделить токены F # на два типа:

  • Keywords
  • Символ и операторы

Ключевые слова F #

В следующей таблице показаны ключевые слова и краткие описания ключевых слов. Мы обсудим использование этих ключевых слов в следующих главах.

Ключевое слово Описание
abstract Указывает на метод, который либо не имеет реализации в том типе, в котором он объявлен, либо является виртуальным и имеет реализацию по умолчанию.
and Используется во взаимно рекурсивных привязках, в объявлениях свойств и с несколькими ограничениями на общие параметры.
as Используется для присвоения текущему объекту класса имени объекта. Также используется для присвоения имени целому шаблону в соответствии с шаблоном.
assert Используется для проверки кода во время отладки.
base Используется как имя объекта базового класса.
begin В подробном синтаксисе указывает на начало блока кода.
class В подробном синтаксисе указывает на начало определения класса.
default Указывает на реализацию абстрактного метода; используется вместе с объявлением абстрактного метода для создания виртуального метода.
delegate Используется для объявления делегата.
do Используется в конструкциях цикла или для выполнения императивного кода.
done В подробном синтаксисе указывает конец блока кода в выражении цикла.
downcast Используется для преобразования в тип, который находится ниже в цепочке наследования.
downto В for выражение, используемое при обратном счете.
elif Используется в условном ветвлении. Краткая форма else if.
else Используется в условном ветвлении.
end

В определениях типов и расширениях типов указывает конец раздела определений элементов.

В подробном синтаксисе используется для указания конца блока кода, который начинается с ключевого слова begin.

exception Используется для объявления типа исключения.
extern Указывает, что объявленный программный элемент определен в другом двоичном файле или сборке.
false Используется как логический литерал.
finally Используется вместе с попыткой ввести блок кода, который выполняется независимо от того, возникает ли исключение.
for Используется в циклических конструкциях.
fun Используется в лямбда-выражениях, также известных как анонимные функции.
function Используется как более короткая альтернатива ключевому слову fun и выражению соответствия в лямбда-выражении, которое имеет сопоставление с образцом для одного аргумента.
global Используется для ссылки на пространство имен .NET верхнего уровня.
if Используется в конструкциях условного ветвления.
in Используется для выражений последовательности и, в подробном синтаксисе, для отделения выражений от привязок.
inherit Используется для указания базового класса или базового интерфейса.
inline Используется для обозначения функции, которую следует интегрировать непосредственно в код вызывающего абонента.
interface Используется для объявления и реализации интерфейсов.
internal Используется для указания того, что элемент виден внутри сборки, но не за ее пределами.
lazy Используется для указания вычисления, которое должно выполняться только тогда, когда требуется результат.
let Используется для связывания или привязки имени к значению или функции.
let! Используется в асинхронных рабочих процессах для привязки имени к результату асинхронного вычисления или, в других выражениях вычислений, используется для привязки имени к результату, имеющему тип вычисления.
match Используется для перехода путем сравнения значения с шаблоном.
member Используется для объявления свойства или метода в типе объекта.
module Используется для связывания имени с группой связанных типов, значений и функций, чтобы логически отделить его от другого кода.
mutable Используется для объявления переменной, то есть значения, которое можно изменить.
namespace Используется для связывания имени с группой связанных типов и модулей, чтобы логически отделить его от другого кода.
new

Используется для объявления, определения или вызова конструктора, который создает или может создавать объект.

Также используется в общих ограничениях параметров, чтобы указать, что у типа должен быть определенный конструктор.

not На самом деле это не ключевое слово. Однако комбинация "не структура" используется в качестве ограничения общего параметра.
null

Указывает на отсутствие объекта.

Также используется в общих ограничениях параметров.

of Используется в дискриминируемых объединениях для указания типа категорий значений, а также в объявлениях делегатов и исключений.
open Используется, чтобы сделать содержимое пространства имен или модуля доступным без уточнения.
or

Используется с логическими условиями как логический оператор или. Эквивалентно ||.

Также используется в ограничениях членов.

override Используется для реализации версии абстрактного или виртуального метода, которая отличается от базовой версии.
private Ограничивает доступ члена к коду того же типа или модуля.
public Разрешает доступ к члену извне типа.
rec Используется, чтобы указать, что функция рекурсивна.
return Используется для обозначения значения, предоставляемого как результат вычислительного выражения.
return! Используется для обозначения выражения вычисления, которое при оценке предоставляет результат содержащего выражения вычисления.
select Используется в выражениях запроса, чтобы указать, какие поля или столбцы нужно извлечь. Обратите внимание, что это контекстное ключевое слово, что означает, что на самом деле это не зарезервированное слово, и оно действует только как ключевое слово в соответствующем контексте.
static Используется для обозначения метода или свойства, которые могут быть вызваны без экземпляра типа, или члена значения, который является общим для всех экземпляров типа.
struct

Используется для объявления типа структуры.

Также используется в общих ограничениях параметров.

Используется для совместимости с OCaml в определениях модулей.

then

Используется в условных выражениях.

Также используется для выполнения побочных эффектов после создания объекта.

to Используется в циклах for для обозначения диапазона.
true Используется как логический литерал.
try Используется для представления блока кода, который может генерировать исключение. Используется вместе с или finally.
type Используется для объявления класса, записи, структуры, различаемого объединения, типа перечисления, единицы измерения или аббревиатуры типа.
upcast Используется для преобразования в тип, который находится выше в цепочке наследования.
use Используется вместо let для значений, требующих вызова Dispose для освобождения ресурсов.
use! Используется вместо let! в асинхронных рабочих процессах и других выражениях вычислений для значений, требующих вызова Dispose для освобождения ресурсов.
val Используется в подписи для указания значения или в типе для объявления члена в ограниченных ситуациях.
void Указывает тип пустоты .NET. Используется при взаимодействии с другими языками .NET.
when Используется для логических условий (когда охранники) при совпадении с шаблоном и для введения предложения ограничения для параметра универсального типа.
while Представляет конструкцию цикла.
with Используется вместе с ключевым словом match в выражениях сопоставления с образцом. Также используется в выражениях объектов, выражениях копирования записей и расширениях типов для введения определений членов и обработчиков исключений.
yield Используется в выражении последовательности для получения значения для последовательности.
yield! Используется в выражении вычисления для добавления результата данного выражения вычисления к коллекции результатов для содержащего выражения вычисления.

Некоторые зарезервированные ключевые слова пришли из языка OCaml -

asr земля лор lsl lsr lxor мод сиг

Некоторые другие зарезервированные ключевые слова сохранены для будущего расширения F #.

атомный сломать проверил составная часть const ограничение constructor
continue eager event external fixed functor include
method mixin object parallel process protected pure
sealed tailcall trait virtual volatile

Comments in F#

F# provides two types of comments −

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

A Basic Program and Application Entry Point in F#

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

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

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

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

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

Hello World!

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

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

Integral Data Type

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

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

42y

-11y

8-bit signed integer
byte 1 byte 0 to 255

42uy

200uy

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

42s

-11s

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

42us

200us

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

42

-11

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

42u

200u

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

42L

-11L

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

42UL

200UL

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

42I

1499999

9999999

9999999

9999999

9999I

arbitrary precision integer

Example

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

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

(* unsigned 8-bit natural number *)

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

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

(* signed 16-bit integer *)

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

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

(* signed 32-bit integer *)

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

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

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

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

Floating Point Data Types

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

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

42.0F

-11.0F

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

42.0

-11.0

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

42.0M

-11.0M

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

42N

-11N

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

Example

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

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

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

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

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

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

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

Text Data Types

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

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

'x'

'\t'

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

"Hello"

"World"

Unicode text

Example

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

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

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

Choice: y
Name: Zara Ali
Organisation: Tutorials Point

Other Data Types

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

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

true

false

Stores boolean values

Example

let trueVal = true
let falseVal = false

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

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

True Value: true
False Value: false

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

Variable Declaration in F#

The let keyword is used for variable declaration −

For example,

let x = 10

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

You can also assign an expression to a variable −

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

The following example illustrates the concept −

Example

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

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

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

x: 10
y: 20
z: 30

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

The following example demonstrates this.

Example

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

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

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

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

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

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

Variable Definition With Type Declaration

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

Example

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

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

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

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

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

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

Mutable Variables

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

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

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

For example,

let mutable x = 10
x ← 15

The following example will clear the concept −

Example

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

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

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

x <- 15
z <- x + y

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

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

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

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

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

Arithmetic Operators

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

Show Example

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

Comparison Operators

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

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

Show Example

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

Boolean Operators

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

Show Example

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

Bitwise Operators

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

Show Example

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

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

A = 0011 1100

B = 0000 1101

A&&&B = 0000 1100

A|||B = 0011 1101

A^^^B = 0011 0001

~~~A = 1100 0011

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

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

Operators Precedence

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

Show Example

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

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

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

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

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

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

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

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

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

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

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

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

Defining a Function

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

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

Where,

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

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

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

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

Parameters of a Function

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

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

For example −

let doubleIt (x : int) = 2 * x

Calling a Function

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

For example −

let vol = cylinderVolume 3.0 5.0

The following programs illustrate the concepts.

Example 1

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

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

let cylinderVolume radius length : float =

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

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

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

Volume: 141.372

Example 2

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

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

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

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

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

Max Value: 52

Example 3

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

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

Double 19: 38

Recursive Functions

Recursive functions are functions that call themselves.

You define a recursive using the let rec keyword combination.

Syntax for defining a recursive function is −

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

For example −

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

Example 1

The following program returns Fibonacci 1 to 10 −

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

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

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

Example 2

The following program returns factorial 8 −

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

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

40320

Arrow Notations in F#

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

int -> string

Data types are read from left to right.

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

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

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

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

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

Some more examples −

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

Lambda Expressions

A lambda expression is an unnamed function.

Let us take an example of two functions −

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

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

35

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

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

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

35

Function Composition and Pipelining

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

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

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

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

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

55

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

The following example shows that −

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

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

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

55

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

String Literals

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

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

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

Ways of lgnoring the Escape Sequence

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

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

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

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

Example

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

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

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

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

Basic Operators on Strings

The following table shows the basic operations on strings −

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

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

Example 1

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

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

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

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

Example 2

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

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

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

Tutorials Point
Coding Ground
Absolute Classes

Example 3

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

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

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

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

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

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

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

Using Options

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

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

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

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

Result: 4

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

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

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

Unhandled Exception:
System.DivideByZeroException: Division by zero

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

The following example demonstrates the use of options −

Example

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

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

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

Result: Some 5

Option Properties and Methods

The option type supports the following properties and methods −

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

Example 1

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

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

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

Result: <null>

Example 2

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

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

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

Result: Some 5
Result: 5

Example 3

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

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

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

false
true
false

А tupleпредставляет собой набор значений, разделенных запятыми. Они используются для создания специальных структур данных, которые группируют связанные значения.

Например, («Зара Али», «Хайдарабад», 10) - это 3-кортеж с двумя строковыми значениями и значением int, он имеет тип (строка * строка * int).

Кортежи могут быть парами, тройками и т. Д. Одного или разных типов.

Здесь приведены некоторые примеры -

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

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

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

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

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

пример

В этой программе есть функция, которая принимает кортеж из четырех значений с плавающей запятой и возвращает среднее значение -

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

Avg of four numbers: 7.275000

Доступ к отдельным членам кортежа

Отдельные члены кортежа могут быть оценены и распечатаны с использованием сопоставления с образцом.

Следующий пример иллюстрирует концепцию -

пример

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

Detail Info: "Zara Ali" "Hyderabad" 10

F # имеет две встроенные функции, fst и snd, которые возвращают первый и второй элементы в 2-кортеже.

Следующий пример иллюстрирует концепцию -

пример

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

А recordпохож на кортеж, но содержит именованные поля. Например,

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

Определение записи

Запись определяется как тип с использованием type ключевое слово, а поля записи определяются как список, разделенный точкой с запятой.

Синтаксис для определения записи -

type recordName =
   { [ fieldName : dataType ] + }

Создание записи

Вы можете создать запись, указав поля записи. Например, давайте создадим запись веб-сайта с именем домашняя страница -

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

Следующие примеры объяснят концепции -

Пример 1

Эта программа определяет тип записи с именем веб-сайт. Затем он создает несколько записей типа веб-сайт и распечатывает записи.

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пример 2

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

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

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

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

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

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

main()

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

В F # список - это упорядоченная неизменяемая серия элементов одного типа. В некоторой степени это эквивалентно структуре данных связанного списка.

Модуль F #, Microsoft.FSharp.Collections.List,имеет общие операции со списками. Однако F # автоматически импортирует этот модуль и делает его доступным для каждого приложения F #.

Создание и инициализация списка

Ниже приведены различные способы создания списков.

  • Использование списка literals.

  • С помощью cons (: :) оператор.

  • Используя List.init метод модуля List.

  • Используя некоторые syntactic constructs называется List Comprehensions.

Список литералов

В этом методе вы просто указываете последовательность значений, разделенных точкой с запятой, в квадратных скобках. Например -

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

Минусы (: :) Оператор

С помощью этого метода вы можете добавить некоторые значения, добавив или cons-ingв существующий список с помощью оператора ::. Например -

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

[] обозначает пустой список.

Список методов инициализации

Метод List.init модуля List часто используется для создания списков. Этот метод имеет тип -

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

Первый аргумент - это желаемая длина нового списка, а второй аргумент - это функция инициализатора, которая генерирует элементы в списке.

Например,

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

Здесь функция индекса генерирует список.

Составить список

Понимания списков - это специальные синтаксические конструкции, используемые для создания списков.

Синтаксис понимания списков F # бывает двух форм - диапазонов и генераторов.

У диапазонов есть конструкции - [начало .. конец] и [начало .. шаг .. конец]

Например,

let list3 = [1 .. 10]

У генераторов есть конструкция - [для x в коллекции do ... yield expr]

Например,

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

Поскольку yield ключевое слово помещает одно значение в список, ключевое слово, yield!, помещает в список набор значений.

Следующая функция демонстрирует вышеуказанные методы -

пример

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

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

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

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

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Свойства типа данных списка

В следующей таблице показаны различные свойства типа данных списка -

Свойство Тип Описание
Голова Первый элемент.
Пустой 'T список Статическое свойство, возвращающее пустой список соответствующего типа.
Пусто bool true если в списке нет элементов.
Вещь Элемент по указанному индексу (с нуля).
Длина int Количество элементов.
Хвост 'T список Список без первого элемента.

В следующем примере показано использование этих свойств -

пример

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Основные операторы в списке

В следующей таблице показаны основные операции с типом данных списка -

Значение Описание
добавить: 'T список →' T список → 'T список Возвращает новый список, содержащий элементы первого списка, за которыми следуют элементы второго.
среднее: 'T список → ^ T Возвращает среднее значение элементов в списке.
averageBy: ('T → ^ U) →' T список → ^ U Возвращает среднее значение элементов, сгенерированных применением функции к каждому элементу списка.
выберите: ('T →' U опция) → 'T список →' U список Применяет данную функцию к каждому элементу списка. Возвращает список, состоящий из результатов для каждого элемента, в котором функция возвращаетSome.
собрать: ('T →' U список) → 'T список →' U список Для каждого элемента списка применяет данную функцию. Объединяет все результаты и возвращает объединенный список.
concat: seq <'T список> →' T список Возвращает новый список, который содержит элементы каждого списка по порядку.
пустой: 'T список Возвращает пустой список заданного типа.
существует: ('T → bool) →' T list → bool Проверяет, удовлетворяет ли какой-либо элемент списка заданному предикату.
существует2: ('T1 →' T2 → bool) → 'T1 список →' T2 список → bool Проверяет, удовлетворяет ли любая пара соответствующих элементов списков заданному предикату.
фильтр: ('T → bool) →' T список → 'T список Возвращает новую коллекцию, содержащую только элементы коллекции, для которой данный предикат возвращает true.
найти: ('T → bool) →' T список → 'T Возвращает первый элемент, для которого данная функция возвращает true.
findIndex: ('T → bool) →' T список → int Возвращает индекс первого элемента в списке, который удовлетворяет заданному предикату.
свёртка: ('Состояние →' T → 'Состояние) →' Состояние → 'Список T →' Состояние Применяет функцию к каждому элементу коллекции, передавая аргумент аккумулятора через вычисление. Эта функция принимает второй аргумент и применяет функцию к нему и первому элементу списка. Затем он передает этот результат в функцию вместе со вторым элементом и так далее. Наконец, он возвращает окончательный результат. Если входная функция - f, а элементы - i0 ... iN, то эта функция вычисляет f (... (fs i0) i1 ...) iN.
fold2: ('Состояние →' T1 → 'T2 →' Состояние) → 'Состояние →' Список T1 → 'Список T2 →' Состояние Применяет функцию к соответствующим элементам двух коллекций, передавая аргумент аккумулятора через вычисление. Коллекции должны иметь одинаковые размеры. Если входной функцией является f, а элементами являются i0 ... iN и j0 ... jN, то эта функция вычисляет f (... (fs i0 j0) ...) iN jN.
foldBack: ('T →' Состояние → 'Состояние) →' Список T → 'Состояние →' Состояние Применяет функцию к каждому элементу коллекции, передавая аргумент аккумулятора через вычисление. Если входная функция равна f, а элементы - i0 ... iN, тогда вычисляет f i0 (... (f iN s)).
foldBack2: ('T1 →' T2 → 'State →' State) → 'T1 list →' T2 list → 'State →' Состояние Применяет функцию к соответствующим элементам двух коллекций, передавая аргумент аккумулятора через вычисление. Коллекции должны иметь одинаковые размеры. Если входной функцией является f, а элементами являются i0 ... iN и j0 ... jN, то эта функция вычисляет f i0 j0 (... (f iN jN s)).
forall: ('T → bool) →' T список → bool Проверяет, удовлетворяют ли все элементы коллекции заданному предикату.
forall2: ('T1 →' T2 → bool) → 'T1 список →' T2 список → bool Проверяет, все ли соответствующие элементы коллекции попарно удовлетворяют заданному предикату.
head: 'T список →' T Возвращает первый элемент списка.
init: int → (int → 'T) →' T список Создает список, вызывая данный генератор для каждого индекса.
isEmpty: 'T список → bool Возврат true если список не содержит элементов, false иначе.
iter: ('T → единица) →' T список → единица Применяет данную функцию к каждому элементу коллекции.
iter2: ('T1 →' T2 → unit) → 'T1 list →' T2 list → unit Применяет данную функцию к двум коллекциям одновременно. Коллекции должны быть одинакового размера.
iteri: (int → 'T → unit) →' T список → unit Применяет данную функцию к каждому элементу коллекции. Целое число, переданное в функцию, указывает индекс элемента.
iteri2: (int → 'T1 →' T2 → unit) → 'T1 list →' T2 list → unit Применяет данную функцию к двум коллекциям одновременно. Коллекции должны быть одинакового размера. Целое число, переданное в функцию, указывает индекс элемента.
длина: 'T список → int Возвращает длину списка.
карта: ('T →' U) → 'T список →' U список Создает новую коллекцию, элементы которой являются результатом применения данной функции к каждому из элементов коллекции.
map2: ('T1 →' T2 → 'U) →' T1 список → 'T2 список →' U список Создает новую коллекцию, элементы которой являются результатами попарного применения данной функции к соответствующим элементам двух коллекций.
map3: ('T1 →' T2 → 'T3 →' U) → 'T1 список →' T2 список → 'T3 список →' U список Создает новую коллекцию, элементы которой являются результатом применения данной функции одновременно к соответствующим элементам трех коллекций.
mapi: (int → 'T →' U) → 'T список →' U список Создает новую коллекцию, элементы которой являются результатом применения данной функции к каждому из элементов коллекции. Целочисленный индекс, переданный в функцию, указывает индекс (от 0) преобразуемого элемента.
mapi2: (int → 'T1 →' T2 → 'U) →' T1 список → 'T2 список →' U список Подобно List.mapi, но отображает соответствующие элементы из двух списков равной длины.
max: 'T список →' T Возвращает наибольший из всех элементов списка, по сравнению с использованием Operators.max.
maxBy: ('T →' U) → 'T список →' T Возвращает наибольший из всех элементов списка, по сравнению с использованием Operators.max для результата функции.
min: 'T список →' T Возвращает самый низкий из всех элементов списка, по сравнению с использованием Operators.min.
minBy: ('T →' U) → 'T список →' T Возвращает самый низкий из всех элементов списка, по сравнению с использованием Operators.min в результате функции.
nth: 'T список → int →' T Индексы в список. Первый элемент имеет индекс 0.
ofArray: 'T [] →' T список Создает список из заданного массива.
ofSeq: seq <'T> →' T список Создает новый список из заданного перечислимого объекта.
раздел: ('T → bool) →' T список * 'T список Разделяет коллекцию на две коллекции, содержащие элементы, для которых данный предикат возвращает true и false соответственно.
перестановка: (int → int) → 'T список →' T список Возвращает список со всеми элементами, переставленными в соответствии с указанной перестановкой.
выберите: ('T →' U опция) → 'T список →' U Применяет данную функцию к последовательным элементам, возвращая первый результат, в котором функция возвращает Some за некоторую ценность.
уменьшить: ('T →' T → 'T) →' T список → 'T Применяет функцию к каждому элементу коллекции, передавая аргумент аккумулятора через вычисление. Эта функция применяет указанную функцию к первым двум элементам списка. Затем он передает этот результат в функцию вместе с третьим элементом и так далее. Наконец, он возвращает окончательный результат. Если входная функция - f, а элементы - i0 ... iN, то эта функция вычисляет f (... (f i0 i1) i2 ...) iN.
reduceBack: ('T →' T → 'T) →' T список → 'T Применяет функцию к каждому элементу коллекции, передавая аргумент аккумулятора через вычисление. Если входная функция равна f, а элементы - i0 ... iN, то эта функция вычисляет f i0 (... (f iN-1 iN)).
реплицировать: (int → 'T →' T список) Создает список, вызывая данный генератор для каждого индекса.
rev: 'T список →' T список Возвращает новый список с элементами в обратном порядке.
сканирование: ('Состояние →' T → 'Состояние) →' Состояние → 'Список T →' Список состояний Применяет функцию к каждому элементу коллекции, передавая аргумент аккумулятора через вычисление. Эта функция принимает второй аргумент и применяет указанную функцию к нему и первому элементу списка. Затем он передает этот результат в функцию вместе со вторым элементом и так далее. Наконец, он возвращает список промежуточных результатов и окончательный результат.
scanBack: ('T →' Состояние → 'Состояние) →' T-список → 'Состояние →' Список состояний Как foldBack, но возвращает как промежуточные, так и окончательные результаты
sort: 'T список →' T список Сортирует данный список с помощью Operators.compare.
sortBy: ('T →' Key) → 'T список →' T список Сортирует данный список, используя ключи, заданные данной проекцией. Ключи сравниваются с помощью Operators.compare.
sortWith: ('T →' T → int) → 'T список →' T список Сортирует данный список, используя данную функцию сравнения.
сумма: ^ T список → ^ T Возвращает сумму элементов в списке.
sumBy: ('T → ^ U) →' T список → ^ U Возвращает сумму результатов, полученных при применении функции к каждому элементу списка.
хвост: 'T список →' T список Возвращает список ввода без первого элемента.
toArray: 'T список →' T [] Создает массив из заданного списка.
toSeq: 'T список → seq <' T> Рассматривает данный список как последовательность.
tryFind: ('T → bool) →' T список → 'T вариант Возвращает первый элемент, для которого данная функция возвращает true. ВозвращениеNone если такого элемента нет.
tryFindIndex: ('T → bool) →' T список → параметр int Возвращает индекс первого элемента в списке, который удовлетворяет заданному предикату. ВозвращениеNone если такого элемента нет.
tryPick: ('T →' U опция) → 'T список →' U опция Применяет данную функцию к последовательным элементам, возвращая первый результат, в котором функция возвращает Someза некоторую ценность. Если такого элемента нет, вернитеNone.
распаковать: ('T1 *' T2) список → 'T1 список *' T2 список Разбивает список пар на два списка.
unzip3: ('T1 *' T2 * 'T3) list →' T1 list * 'T2 list *' T3 list Разбивает список троек на три списка.
zip: 'Список T1 → Список T2 → (' T1 * 'T2) список Объединяет два списка в список пар. Два списка должны иметь одинаковую длину.
zip3: 'Список T1 → Список T2 → Список T3 → (' T1 * 'T2 *' T3) список Объединяет три списка в список троек. Списки должны иметь одинаковую длину.

Следующие примеры демонстрируют использование вышеуказанных функций -

Пример 1

Эта программа показывает рекурсивное реверсирование списка -

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Однако вы можете использовать rev функция модуля для той же цели -

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пример 2

Эта программа показывает фильтрацию списка с помощью List.filter метод -

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пример 3

В List.map метод отображает список из одного типа в другой -

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пример 4

В List.append метод, а оператор @ добавляет один список в другой -

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пример 5

В List.sortметод сортирует список. ВList.sum метод дает сумму элементов в списке и List.average метод дает среднее значение элементов в списке -

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Операция «сворачивания» применяет функцию к каждому элементу в списке, объединяет результат функции в переменной аккумулятора и возвращает аккумулятор как результат операции сворачивания.

Пример 6

В List.fold метод применяет функцию к каждому элементу слева направо, а List.foldBack применяет функцию к каждому элементу справа налево.

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Последовательности, как и списки, также представляют собой упорядоченный набор значений. Однако при необходимости вычисляются элементы последовательности или выражения последовательности. Они не вычисляются сразу и по этой причине используются для представления бесконечных структур данных.

Определение последовательностей

Последовательности определяются с использованием следующего синтаксиса -

seq { expr }

Например,

let seq1 = seq { 1 .. 10 }

Создание последовательностей и выражений последовательностей

Как и в случае со списками, вы можете создавать последовательности, используя диапазоны и понимания.

Выражения последовательности - это выражения, которые вы можете написать для создания последовательностей. Это можно сделать -

  • Указав диапазон.
  • Указав диапазон с увеличением или уменьшением.
  • Используя yield ключевое слово для создания значений, которые становятся частью последовательности.
  • С помощью оператора →.

Следующие примеры демонстрируют концепцию -

Пример 1

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пример 2

Следующая программа печатает простые числа от 1 до 50 -

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Основные операции с последовательностью

В следующей таблице показаны основные операции с типом данных последовательности -

Значение Описание
добавить: seq <'T> → seq <' T> → seq <'T> Оборачивает два заданных перечисления как одно сцепленное перечисление.
среднее: seq <^ T> → ^ T Возвращает среднее значение элементов в последовательности.
среднийBy: ('T → ^ U) → seq <' T> → ^ U Возвращает среднее значение результатов, полученных при применении функции к каждому элементу последовательности.
кеш: seq <'T> → seq <' T> Возвращает последовательность, соответствующую кэшированной версии входной последовательности.
приведение: IEnumerable → seq <'T> Оборачивает свободно типизированный System. Последовательность коллекций как типизированная последовательность.
выберите: (опция 'T →' U) → seq <'T> → seq <' U> Применяет данную функцию к каждому элементу списка. Вернуть список, состоящий из результатов для каждого элемента, в котором функция возвращаетSome.
собирать: ('T →' Коллекция) → seq <'T> → seq <' U> Применяет данную функцию к каждому элементу последовательности и объединяет все результаты.
compareWith: ('T →' T → int) → seq <'T> → seq <' T> → int Сравнивает две последовательности, используя заданную функцию сравнения, элемент за элементом.
concat: seq <'Коллекция> → seq <' T> Объединяет заданное перечисление перечислений как одно сцепленное перечисление.
countBy: ('T →' Key) → seq <'T> → seq <' Key * int> Применяет функцию генерации ключей к каждому элементу последовательности и возвращает последовательность, дающую уникальные ключи и их количество вхождений в исходную последовательность.
задержка: (единица → seq <'T>) → seq <' T> Возвращает последовательность, которая построена из заданной отложенной спецификации последовательности.
различные: seq <'T> → seq <' T> Возвращает последовательность, не содержащую повторяющихся записей, в соответствии с общим хешем и сравнениями на равенство для записей. Если элемент встречается в последовательности несколько раз, более поздние вхождения отбрасываются.
ОтдельныйBy: ('T →' Key) → seq <'T> → seq <' T> Возвращает последовательность, не содержащую повторяющихся записей, в соответствии с общим хешем и сравнениями на равенство для ключей, возвращаемых данной функцией создания ключей. Если элемент встречается в последовательности несколько раз, более поздние вхождения отбрасываются.
пустой: seq <'T> Создает пустую последовательность.
точно один: seq <'T> →' T Возвращает единственный элемент последовательности.
существует: ('T → bool) → seq <' T> → bool Проверяет, удовлетворяет ли какой-либо элемент последовательности заданному предикату.
существует2: ('T1 →' T2 → bool) → seq <'T1> → seq <' T2> → bool Проверяет, удовлетворяет ли любая пара соответствующих элементов входных последовательностей заданному предикату.
фильтр: ('T → bool) → seq <' T> → seq <'T> Возвращает новую коллекцию, содержащую только элементы коллекции, для которой данный предикат возвращает true.
найти: ('T → bool) → seq <' T> → 'T Возвращает первый элемент, для которого данная функция возвращает true.
findIndex: ('T → bool) → seq <' T> → int Возвращает индекс первого элемента, для которого данная функция возвращает true.
свёртка: ('Состояние →' T → 'Состояние) →' Состояние → seq <'T> →' Состояние Применяет функцию к каждому элементу коллекции, передавая аргумент аккумулятора через вычисление. Если входная функция - f, а элементы - i0 ... iN, то эта функция вычисляет f (... (fs i0) ...) iN.
forall: ('T → bool) → seq <' T> → bool Проверяет, все ли элементы последовательности удовлетворяют заданному предикату.
forall2: ('T1 →' T2 → bool) → seq <'T1> → seq <' T2> → bool Проверяет, что все пары элементов, взятые из двух последовательностей, удовлетворяют заданному предикату. Если одна последовательность короче другой, то остальные элементы более длинной последовательности игнорируются.
groupBy: ('T →' Key) → seq <'T> → seq <' Key * seq <'T >> Применяет функцию генерации ключей к каждому элементу последовательности и выдает последовательность уникальных ключей. Каждый уникальный ключ также содержит последовательность всех элементов, соответствующих этому ключу.
голова: seq <'T> →' T Возвращает первый элемент последовательности.
init: int → (int → 'T) → seq <' T> Создает новую последовательность, которая при повторении возвращает последовательные элементы, вызывая заданную функцию до заданного счетчика. Результаты вызова функции не сохраняются, то есть функция повторно применяется по мере необходимости для регенерации элементов. В функцию передается индекс создаваемого элемента.
initInfinite: (интервал → 'T) → seq <' T> Создает новую последовательность, которая при повторении будет возвращать последовательные элементы путем вызова данной функции. Результаты вызова функции не сохраняются, то есть функция будет повторно применена по мере необходимости для регенерации элементов. В функцию передается индекс создаваемого элемента.
isEmpty: seq <'T> → bool Проверяет, есть ли в последовательности какие-либо элементы.
iter: ('T → единица) → seq <' T> → единица Применяет данную функцию к каждому элементу коллекции.
iter2: ('T1 →' T2 → unit) → seq <'T1> → seq <' T2> → unit Применяет данную функцию к двум коллекциям одновременно. Если одна последовательность короче другой, то остальные элементы более длинной последовательности игнорируются.
iteri: (int → 'T → unit) → seq <' T> → единица Применяет данную функцию к каждому элементу коллекции. Целое число, переданное в функцию, указывает индекс элемента.
последний: seq <'T> →' T Возвращает последний элемент последовательности.
длина: seq <'T> → int Возвращает длину последовательности.
карта: ('T →' U) → seq <'T> → seq <' U> Создает новую коллекцию, элементы которой являются результатом применения данной функции к каждому из элементов коллекции. Данная функция будет применяться по мере того, как элементы требуются с использованием метода MoveNext для счетчиков, полученных из объекта.
карта2: ('T1 →' T2 → 'U) → seq <' T1> → seq <'T2> → seq <' U> Создает новую коллекцию, элементы которой являются результатом применения данной функции к соответствующим парам элементов из двух последовательностей. Если одна входная последовательность короче другой, то остальные элементы более длинной последовательности игнорируются.
mapi: (интервал → 'T →' U) → seq <'T> → seq <' U> Создает новую коллекцию, элементы которой являются результатом применения данной функции к каждому из элементов коллекции. Целочисленный индекс, переданный в функцию, указывает индекс (от 0) преобразуемого элемента.
макс: seq <'T> →' T Возвращает наибольший из всех элементов последовательности, по сравнению с использованием Operators.max.
maxBy: ('T →' U) → seq <'T> →' T Возвращает наибольший из всех элементов последовательности, по сравнению с использованием Operators.max для результата функции.
мин: seq <'T> →' T Возвращает наименьший из всех элементов последовательности по сравнению с использованием Operators.min.
minBy: ('T →' U) → seq <'T> →' T Возвращает наименьший из всех элементов последовательности, по сравнению с использованием Operators.min для результата функции.
nth: int → seq <'T> →' T Вычисляет n-й элемент в коллекции.
ofArray: 'T массив → seq <' T> Рассматривает данный массив как последовательность.
ofList: 'T список → seq <' T> Рассматривает данный список как последовательность.
попарно: seq <'T> → seq <' T * 'T> Возвращает последовательность каждого элемента во входной последовательности и ее предшественника, за исключением первого элемента, который возвращается только как предшественник второго элемента.
выберите: (опция 'T →' U) → seq <'T> →' U Применяет данную функцию к последовательным элементам, возвращая первое значение, в котором функция возвращает Some значение.
только чтение: seq <'T> → seq <' T> Создает новый объект последовательности, который делегирует данный объект последовательности. Это гарантирует, что исходная последовательность не может быть повторно обнаружена и изменена посредством приведения типа. Например, если задан массив, возвращаемая последовательность будет возвращать элементы массива, но вы не можете преобразовать возвращенный объект последовательности в массив.
уменьшить: ('T →' T → 'T) → seq <' T> → 'T Применяет функцию к каждому элементу последовательности, передавая аргумент аккумулятора через вычисление. Начните с применения функции к первым двум элементам. Затем передайте этот результат в функцию вместе с третьим элементом и так далее. Верните окончательный результат.
сканирование: ('Состояние →' T → 'Состояние) →' Состояние → seq <'T> → seq <' Состояние> Как Seq.fold, но вычисляет по запросу и возвращает последовательность промежуточных и окончательных результатов.
одиночный: 'T → seq <' T> Возвращает последовательность, которая дает только один элемент.
пропустить: int → seq <'T> → seq <' T> Returns a sequence that skips a specified number of elements of the underlying sequence and then yields the remaining elements of the sequence.
skipWhile : ('T → bool) → seq<'T> → seq<'T> Returns a sequence that, when iterated, skips elements of the underlying sequence while the given predicate returns true, and then yields the remaining elements of the sequence.
sort : seq<'T> → seq<'T> Yields a sequence ordered by keys.
sortBy : ('T → 'Key) → seq<'T> → seq<'T> Applies a key-generating function to each element of a sequence and yield a sequence ordered by keys. The keys are compared using generic comparison as implemented by Operators.compare.
sum : seq<^T> → ^T Returns the sum of the elements in the sequence.
sumBy Returns the sum of the results generated by applying the function to each element of the sequence.
take : int → seq<'T> → seq<'T> Returns the first elements of the sequence up to a specified count.
takeWhile : ('T → bool) → seq<'T> → seq<'T> Returns a sequence that, when iterated, yields elements of the underlying sequence while the given predicate returns true, and then returns no further elements.
toArray : seq<'T> → 'T[] Creates an array from the given collection.
toList : seq<'T> → 'T list Creates a list from the given collection.
truncate : int → seq<'T> → seq<'T> Returns a sequence that when enumerated returns no more than a specified number of elements.
tryFind : ('T → bool) → seq<'T> → 'T option Returns the first element for which the given function returns true, or None if no such element exists.
tryFindIndex : ('T → bool) → seq<'T> → int option Returns the index of the first element in the sequence that satisfies the given predicate, or None if no such element exists.
tryPick : ('T → 'U option) → seq<'T> → 'U option Applies the given function to successive elements, returning the first value where the function returns a Some value.
unfold : ('State → 'T * 'State option) → 'State → seq<'T> Returns a sequence that contains the elements generated by the given computation.
where : ('T → bool) → seq<'T> → seq<'T> Returns a new collection containing only the elements of the collection for which the given predicate returns true. A synonym for Seq.filter.
windowed : int → seq<'T> → seq<'T []> Returns a sequence that yields sliding windows of containing elements drawn from the input sequence. Each window is returned as a fresh array.
zip : seq<'T1> → seq<'T2> → seq<'T1 * 'T2> Combines the two sequences into a list of pairs. The two sequences need not have equal lengths − when one sequence is exhausted any remaining elements in the other sequence are ignored.
zip3 : seq<'T1> → seq<'T2> → seq<'T3> → seq<'T1 * 'T2 * 'T3> Combines the three sequences into a list of triples. The sequences need not have equal lengths − when one sequence is exhausted any remaining elements in the other sequences are ignored.

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

Example 1

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

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

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

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

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

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

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

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

Please note that −

  • The Seq.empty method creates an empty sequence.

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

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

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

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

Пример 2

Метод Seq.unfold генерирует последовательность из функции вычисления, которая принимает состояние и преобразует его для создания каждого последующего элемента в последовательности.

Следующая функция производит первые 20 натуральных чисел -

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пример 3

Метод Seq.truncate создает последовательность из другой последовательности, но ограничивает последовательность указанным числом элементов.

Метод Seq.take создает новую последовательность, содержащую указанное количество элементов с начала последовательности.

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Набор в F # - это структура данных, которая действует как набор элементов без сохранения порядка, в котором элементы вставляются. Наборы не позволяют вставлять повторяющиеся записи в коллекцию.

Создание наборов

Наборы могут быть созданы следующими способами -

  • Создав пустой набор с помощью Set.empty и добавив элементы с помощью функции добавления.
  • Преобразование последовательностей и списков в наборы.

Следующая программа демонстрирует методы -

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Основные операции с наборами

В следующей таблице показаны основные операции с наборами -

Значение Описание
добавить: 'T → Установить <' T> → Установить <'T> Возвращает новый набор с добавленным к нему элементом. Исключение не возникает, если набор уже содержит данный элемент.
содержит: 'T → Set <' T> → bool Оценивает до true если данный элемент находится в данном наборе.
count: Set <'T> → int Возвращает количество элементов в наборе.
разница: Установить <'T> → Установить <' T> → Установить <'T> Возвращает новый набор, в котором элементы второго набора удалены из первого.
пустой: Установить <'T> Пустой набор для указанного типа.
существует: ('T → bool) → Set <' T> → bool Проверяет, удовлетворяет ли какой-либо элемент коллекции заданному предикату. Если входная функция является предикатом, а элементы - i0 ... iN, то эта функция вычисляет предикат i0 или ... или предикат iN.
фильтр: ('T → bool) → Установить <' T> → Установить <'T> Возвращает новую коллекцию, содержащую только элементы коллекции, для которой данный предикат возвращает true.
свёртка: ('Состояние →' T → 'Состояние) →' Состояние → Установить <'T> →' Состояние Применяет данную функцию накопления ко всем элементам набора.
foldBack: ('T →' Состояние → 'Состояние) → Установить <' T> → 'Состояние →' Состояние Применяет данную функцию накопления ко всем элементам набора.
forall: ('T → bool) → Установить <' T> → bool Проверяет, удовлетворяют ли все элементы коллекции заданному предикату. Если входная функция - p, а элементы - i0 ... iN, то эта функция вычисляет p i0 && ... && p iN.
пересечение: Установить <'T> → Установить <' T> → Установить <'T> Вычисляет пересечение двух наборов.
IntercctMany: seq <Установить <'T >> → Установить <' T> Вычисляет пересечение последовательности наборов. Последовательность не должна быть пустой.
isEmpty: Set <'T> → bool Возврат true если набор пуст.
isProperSubset: Установить <'T> → Установить <' T> → bool Оценивает до true если все элементы первого набора находятся во втором, и хотя бы один элемент второго не находится в первом.
isProperSuperset: Установить <'T> → Установить <' T> → bool Оценивает до true если все элементы второго набора находятся в первом, и хотя бы один элемент первого не находится во втором.
isSubset: Set <'T> → Set <' T> → bool Оценивает до true если все элементы первого набора находятся во втором.
isSuperset: Установить <'T> → Установить <' T> → bool Оценивает до true если все элементы второго набора находятся в первом.
iter: ('T → единица) → Установить <' T> → единица Применяет данную функцию к каждому элементу набора в порядке, соответствующем функции сравнения.
карта: ('T →' U) → Установить <'T> → Установить <' U> Возвращает новую коллекцию, содержащую результаты применения данной функции к каждому элементу входного набора.
maxElement: Установить <'T> →' T Возвращает наивысший элемент в наборе в соответствии с порядком, используемым для набора.
minElement: Установить <'T> →' T Возвращает самый низкий элемент в наборе в соответствии с порядком, используемым для набора.
ofArray: 'T массив → Установить <' T> Создает набор, содержащий те же элементы, что и данный массив.
ofList: 'T список → Установить <' T> Создает набор, содержащий те же элементы, что и данный список.
ofSeq: seq <'T> → Установить <' T> Создает новую коллекцию из заданного перечислимого объекта.
раздел: ('T → bool) → Установить <' T> → Установить <'T> * Установить <' T> Разбивает набор на два набора, содержащих элементы, для которых данный предикат возвращает истину и ложь соответственно.
удалить: 'T → Установить <' T> → Установить <'T> Возвращает новый набор с удаленным элементом. Исключение не возникает, если набор не содержит данный элемент.
одиночный: 'T → Установить <' T> Набор, содержащий данный элемент.
toArray: Установить массив <'T> →' T Создает массив, содержащий элементы набора по порядку.
toList: Установить список <'T> →' T Создает список, содержащий по порядку элементы набора.
toSeq: установить <'T> → seq <' T> Возвращает упорядоченное представление коллекции в виде перечисляемого объекта.
объединение: Set <'T> → Set <' T> → Set <'T> Вычисляет объединение двух наборов.
unionMany: seq <Установить <'T >> → Установить <' T> Вычисляет объединение последовательности наборов.

В следующем примере демонстрируется использование некоторых из вышеперечисленных функций -

пример

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

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

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

В F # карта - это особый вид набора, который связывает значения с ключом. Карта создается аналогично созданию наборов.

Создание карт

Карты создаются путем создания пустой карты с помощью Map.empty и добавления элементов с помощью функции Добавить. Следующий пример демонстрирует это -

пример

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Вы можете получить доступ к отдельным элементам на карте с помощью клавиши.

пример

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Основные операции на картах

Добавить название модуля

В следующей таблице показаны основные операции на картах -

Член Описание
Добавить Возвращает новую карту с привязкой, добавленной к данной карте.
ContainsKey Проверяет, находится ли элемент в домене карты.
Считать Количество привязок на карте.
Пусто Возвращает true, если на карте нет привязок.
Вещь Найдите элемент на карте. Вызывает исключение KeyNotFoundException, если на карте нет привязки.
удалять Удаляет элемент из домена карты. Если элемент отсутствует, исключение не возникает.
Попробуйте найти Искать элемент на карте, возвращая Some значение, если элемент находится в домене карты и None если не.

В следующем примере демонстрируется использование некоторых из вышеперечисленных функций -

пример

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Союзы, или различаемые союзы, позволяют создавать сложные структуры данных, представляющие четко определенный набор вариантов. Например, вам нужно создать реализацию переменной выбора , которая имеет два значения: да и нет. Используя инструмент Unions, вы можете создать это.

Синтаксис

Дискриминационные союзы определяются с использованием следующего синтаксиса -

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

Наша простая реализация выбора будет выглядеть следующим образом:

type choice =
   | Yes
   | No

В следующем примере используется выбор типа -

type choice =
   | Yes
   | No

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

x: Yes
y: No

Пример 1

В следующем примере показана реализация состояний напряжения, которые устанавливают бит на высокое или низкое:

type VoltageState =
   | High
   | Low

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

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

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

main()

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пример 2

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

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

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

let pi = 3.141592654

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Переменные в F # immutable,Это означает, что после того, как переменная привязана к значению, его нельзя изменить. Фактически они скомпилированы как статические свойства, доступные только для чтения.

Следующий пример демонстрирует это.

пример

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

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

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

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

Когда вы компилируете и выполняете программу, она показывает следующее сообщение об ошибке -

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

Изменяемые переменные

Иногда вам нужно изменить значения, хранящиеся в переменной. Чтобы указать, что может произойти изменение значения объявленной и назначенной переменной в более поздней части программы, F # предоставляетmutableключевое слово. Вы можете объявлять и назначать изменяемые переменные с помощью этого ключевого слова, значения которых вы будете изменять.

В mutable ключевое слово позволяет объявлять и присваивать значения изменяемой переменной.

Вы можете присвоить некоторое начальное значение изменяемой переменной, используя letключевое слово. Однако, чтобы присвоить ему новое последующее значение, вам нужно использовать<- оператор.

Например,

let mutable x = 10
x <- 15

Следующий пример проясняет концепцию -

пример

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

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

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

x <- 15
z <- x + y

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Использование изменяемых данных

Изменяемые данные часто требуются и используются при обработке данных, особенно с записью структуры данных. Следующий пример демонстрирует это -

open System

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

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

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

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

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

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

   printfn "Before Process:"
   printData students

   printfn "After process:"
   registerStudents students
   printData students

   Console.ReadKey(true) |> ignore

main()

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Массивы - это изменяемые коллекции фиксированного размера с отсчетом от нуля последовательных элементов данных одного типа.

Создание массивов

Вы можете создавать массивы, используя различные синтаксисы и способы или используя функции из модуля Array. В этом разделе мы обсудим создание массивов без использования функций модуля.

Есть три синтаксических способа создания массивов без функций:

  • Путем перечисления последовательных значений между [| и |] через точку с запятой.
  • Помещая каждый элемент в отдельную строку, и в этом случае разделитель точкой с запятой не является обязательным.
  • Используя выражения последовательности.

Вы можете получить доступ к элементам массива, используя оператор точки (.) И скобки ([и]).

В следующем примере демонстрируется создание массивов -

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Основные операции с массивами

Библиотечный модуль Microsoft.FSharp.Collections.Array поддерживает операции с одномерными массивами.

В следующей таблице показаны основные операции с массивами -

Значение Описание
добавить: 'T [] →' T [] → 'T [] Создает массив, содержащий элементы одного массива, за которыми следуют элементы другого массива.
среднее: ^ T [] → ^ T Возвращает среднее значение элементов в массиве.
averageBy: ('T → ^ U) →' T [] → ^ U Возвращает среднее значение элементов, созданных путем применения функции к каждому элементу массива.
blit: 'T [] → int →' T [] → int → int → unit Считывает диапазон элементов из одного массива и записывает их в другой.
выберите: ('T → U опция) →' T [] → 'U [] Применяет предоставленную функцию к каждому элементу массива. Возвращает массив, содержащий результаты x для каждого элемента, для которого функция возвращает Some (x).
собрать: ('T →' U []) → T [] → 'U [] Применяет предоставленную функцию к каждому элементу массива, объединяет результаты и возвращает объединенный массив.
concat: seq <'T []> →' T [] Создает массив, содержащий элементы каждой из предоставленных последовательностей массивов.
копировать: 'T →' T [] Создает массив, содержащий элементы предоставленного массива.
создать: int → 'T →' T [] Создает массив, все элементы которого изначально являются предоставленным значением.
пусто: 'T [] Возвращает пустой массив заданного типа.
существует: ('T → bool) →' T [] → bool Проверяет, удовлетворяет ли какой-либо элемент массива указанному предикату.
существует2: ('T1 →' T2 → bool) → 'T1 [] →' T2 [] → bool Проверяет, удовлетворяет ли любая пара соответствующих элементов двух массивов заданному условию.
заполнить: 'T [] → int → int →' T → unit Заполняет диапазон элементов массива предоставленным значением.
фильтр: ('T → bool) →' T [] → 'T [] Возвращает коллекцию, содержащую только элементы предоставленного массива, для которых предоставленное условие возвращает true.
найти: ('T → bool) →' T [] → 'T Возвращает первый элемент, для которого предоставленная функция возвращает true. Вызывает исключение KeyNotFoundException, если такой элемент не существует.
findIndex: ('T → bool) →' T [] → int Возвращает индекс первого элемента в массиве, который удовлетворяет заданному условию. Вызывает исключение KeyNotFoundException, если ни один из элементов не удовлетворяет условию.
свёртка: ('Состояние →' T → 'Состояние) →' Состояние → 'T [] →' Состояние Применяет функцию к каждому элементу массива, передавая аргумент аккумулятора через вычисление. Если входная функция - f, а элементы массива - i0 ... iN, эта функция вычисляет f (... (fs i0) ...) iN.
fold2: ('Состояние →' T1 → 'T2 →' Состояние) → 'Состояние →' T1 [] → 'T2 [] →' Состояние Применяет функцию к парам элементов из двух предоставленных массивов слева направо, передавая аргумент аккумулятора через вычисления. Два входных массива должны иметь одинаковую длину; в противном случае возникает исключение ArgumentException.
foldBack: ('T →' Состояние → 'Состояние) →' T [] → 'Состояние →' Состояние Применяет функцию к каждому элементу массива, передавая аргумент аккумулятора через вычисление. Если входная функция - f, а элементы массива - i0 ... iN, эта функция вычисляет f i0 (... (f iN s)).
foldBack2: ('T1 →' T2 → 'State →' State) → 'T1 [] →' T2 [] → 'State →' Состояние Применяет функцию к парам элементов из двух предоставленных массивов справа налево, передавая аргумент аккумулятора через вычисление. Два входных массива должны иметь одинаковую длину; в противном случае возникает исключение ArgumentException.
forall: ('T → bool) →' T [] → bool Проверяет, все ли элементы массива удовлетворяют заданному условию.
forall2: ('T1 →' T2 → bool) → 'T1 [] →' T2 [] → bool Проверяет, удовлетворяют ли все соответствующие элементы двух предоставленных массивов поставленному условию.
получить: 'T [] → int →' T Получает элемент из массива.
init: int → (int → 'T) →' T [] Использует предоставленную функцию для создания массива предоставленного измерения.
isEmpty: 'T [] → bool Проверяет, есть ли в массиве какие-либо элементы.
iter: ('T → единица) →' T [] → единица Применяет предоставленную функцию к каждому элементу массива.
iter2: ('T1 →' T2 → блок) → 'T1 [] →' T2 [] → блок) Применяет предоставленную функцию к паре элементов из совпадающих индексов в двух массивах. Два массива должны иметь одинаковую длину; в противном случае возникает исключение ArgumentException.
iteri: (int → 'T → unit) →' T [] → unit Применяет предоставленную функцию к каждому элементу массива. Целое число, переданное в функцию, указывает индекс элемента.
iteri2: (int → 'T1 →' T2 → unit) → 'T1 [] →' T2 [] → unit Применяет предоставленную функцию к паре элементов из соответствующих индексов в двух массивах, также передавая индекс элементов. Два массива должны иметь одинаковую длину; в противном случае возникает исключение ArgumentException.
длина: 'T [] → int Возвращает длину массива. Свойство Length делает то же самое.
карта: ('T →' U) → 'T [] →' U [] Создает массив, элементы которого являются результатом применения предоставленной функции к каждому из элементов предоставленного массива.
map2: ('T1 →' T2 → 'U) →' T1 [] → 'T2 [] →' U [] Создает массив, элементы которого являются результатом применения предоставленной функции к соответствующим элементам двух предоставленных массивов. Два входных массива должны иметь одинаковую длину; в противном случае возникает исключение ArgumentException.
mapi: (int → 'T →' U) → 'T [] →' U [] Создает массив, элементы которого являются результатом применения предоставленной функции к каждому из элементов предоставленного массива. Целочисленный индекс, переданный в функцию, указывает индекс преобразуемого элемента.
mapi2: (int → 'T1 →' T2 → 'U) →' T1 [] → 'T2 [] →' U [] Создает массив, элементы которого являются результатами попарного применения предоставленной функции к соответствующим элементам двух коллекций, также передавая индекс элементов. Два входных массива должны иметь одинаковую длину; в противном случае возникает исключение ArgumentException.
макс: 'T [] →' T Возвращает наибольший из всех элементов массива. Operators.max используется для сравнения элементов.
maxBy: ('T →' U) → 'T [] →' T Возвращает наибольший из всех элементов массива по сравнению с помощью Operators.max в результате функции.
мин: ('T [] →' T Возвращает наименьший из всех элементов массива. Operators.min используется для сравнения элементов.
minBy: ('T →' U) → 'T [] →' T Возвращает наименьший из всех элементов массива. Operators.min используется для сравнения элементов.
ofList: 'T список →' T [] Создает массив из предоставленного списка.
ofSeq: seq <'T> →' T [] Создает массив из предоставленного перечислимого объекта.
раздел: ('T → bool) →' T [] → 'T [] *' T [] Разбивает массив на два массива, один из которых содержит элементы, для которых предоставленное условие возвращает true, а другой содержит те, для которых он возвращается false.
перестановка: (int → int) → 'T [] →' T [] Переставляет элементы массива в соответствии с указанной перестановкой.
выберите: ('T →' U опция) → 'T [] →' U Применяет предоставленную функцию к последовательным элементам предоставленного массива, возвращая первый результат, где функция возвращает Some (x) для некоторого x. Если функция никогда не возвращает Some (x), возникает исключение KeyNotFoundException.
уменьшить: ('T →' T → 'T) →' T [] → 'T Применяет функцию к каждому элементу массива, передавая аргумент аккумулятора через вычисление. Если входная функция - f, а элементы массива - i0 ... iN, эта функция вычисляет f (... (f i0 i1) ...) iN. Если размер массива равен нулю, возникает исключение ArgumentException.
reduceBack: ('T →' T → 'T) →' T [] → 'T Применяет функцию к каждому элементу массива, передавая аргумент аккумулятора через вычисление. Если входная функция - f, а элементы - i0 ... iN, эта функция вычисляет f i0 (... (f iN-1 iN)). Если размер массива равен нулю, возникает исключение ArgumentException.
rev: 'T [] →' T [] Изменяет порядок элементов в предоставленном массиве.
сканирование: ('Состояние →' T → 'Состояние) →' Состояние → 'T [] →' Состояние []) Действует как fold, но возвращает промежуточные результаты вместе с окончательными.
scanBack: ('T →' Состояние → 'Состояние) →' T [] → 'Состояние →' Состояние [] Действует как foldBack, но возвращает промежуточные результаты вместе с окончательными.
установить: 'T [] → int →' T → unit Устанавливает элемент массива.
сортировать: 'T [] →' T [] Сортирует элементы массива и возвращает новый массив. Operators.compare используется для сравнения элементов.
sortBy: ('T →' Key) → 'T [] →' T [] Сортирует элементы массива, используя предоставленную функцию для преобразования элементов в тип, на котором основана операция сортировки, и возвращает новый массив. Operators.compare используется для сравнения элементов.
sortInPlace: 'T [] → unit Сортирует элементы массива, изменяя массив на месте, используя предоставленную функцию сравнения. Operators.compare используется для сравнения элементов.
sortInPlaceBy: ('T →' Key) → 'T [] → unit Сортирует элементы массива, изменяя массив на месте, используя предоставленную проекцию для ключей. Operators.compare используется для сравнения элементов.
sortInPlaceWith: ('T →' T → int) → 'T [] → единица измерения Сортирует элементы массива, используя предоставленную функцию сравнения для изменения массива на месте.
sortWith: ('T →' T → int) → 'T [] →' T [] Сортирует элементы массива с помощью предоставленной функции сравнения и возвращает новый массив.
sub: 'T [] → int → int →' T [] Создает массив, содержащий предоставленный поддиапазон, который определяется начальным индексом и длиной.
сумма: 'T [] → ^ T Возвращает сумму элементов в массиве.
sumBy: ('T → ^ U) →' T [] → ^ U Возвращает сумму результатов, полученных при применении функции к каждому элементу массива.
toList: 'T [] →' T список Преобразует предоставленный массив в список.
toSeq: 'T [] → seq <' T> Рассматривает предоставленный массив как последовательность.
tryFind: ('T → bool) →' T [] → 'T опция Возвращает первый элемент в предоставленном массиве, для которого предоставленная функция возвращает true. ВозвратNone если такого элемента нет.
tryFindIndex: ('T → bool) →' T [] → параметр int Возвращает индекс первого элемента в массиве, который удовлетворяет заданному условию.
tryPick: ('T →' U опция) → 'T [] →' U опция Применяет предоставленную функцию к последовательным элементам предоставленного массива и возвращает первый результат, в котором функция возвращает Some (x) для некоторого x. Если функция никогда не возвращает Some (x),None возвращается.
разархивировать: ('T1 *' T2) [] → 'T1 [] *' T2 [] Разбивает массив пар кортежей на кортеж из двух массивов.
unzip3: ('T1 *' T2 * 'T3) [] →' T1 [] * 'T2 [] *' T3 [] Разбивает массив кортежей из трех элементов на кортеж из трех массивов.
zeroCreate: int → 'T [] Создает массив, для элементов которого изначально задано значение по умолчанию Unchecked.defaultof <'T>.
zip: 'T1 [] →' T2 [] → ('T1 *' T2) [] Объединяет два массива в массив кортежей, состоящих из двух элементов. Два массива должны иметь одинаковую длину; в противном случае возникает исключение ArgumentException.
zip3: 'T1 [] →' T2 [] → 'T3 [] → (' T1 * 'T2 * 113' T3) [] Объединяет три массива в массив кортежей, состоящих из трех элементов. Три массива должны иметь одинаковую длину; в противном случае возникает исключение ArgumentException.

В следующем разделе мы увидим использование некоторых из этих функций.

Создание массивов с использованием функций

Модуль Array предоставляет несколько функций, которые создают массив с нуля.

  • В Array.empty функция создает новый пустой массив.

  • В Array.create Функция создает массив указанного размера и устанавливает для всех элементов заданные значения.

  • В Array.init Функция создает массив с заданным размером и функцией для генерации элементов.

  • В Array.zeroCreate Функция создает массив, в котором все элементы инициализируются нулевым значением.

  • В Array.copy Функция создает новый массив, содержащий элементы, скопированные из существующего массива.

  • В Array.sub функция генерирует новый массив из поддиапазона массива.

  • В Array.append функция создает новый массив, объединяя два существующих массива.

  • В Array.choose функция выбирает элементы массива для включения в новый массив.

  • В Array.collect функция запускает указанную функцию для каждого элемента массива существующего массива, а затем собирает элементы, созданные функцией, и объединяет их в новый массив.

  • В Array.concat Функция принимает последовательность массивов и объединяет их в один массив.

  • В Array.filter Функция принимает логическую функцию условия и генерирует новый массив, содержащий только те элементы из входного массива, для которых условие истинно.

  • В Array.rev Функция генерирует новый массив, изменяя порядок существующего массива на противоположный.

Следующие примеры демонстрируют эти функции -

Пример 1

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

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пример 2

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

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Поиск в массивах

В Array.find функция принимает логическую функцию и возвращает первый элемент, для которого функция возвращает истину, иначе вызывает KeyNotFoundException.

В Array.findIndex функция работает аналогично, за исключением того, что она возвращает индекс элемента вместо самого элемента.

Следующий пример демонстрирует это.

Microsoft предоставляет этот интересный пример программы, который находит первый элемент в диапазоне заданного числа, который является как полным квадратом, так и идеальным кубом:

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

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

В List<'T> class представляет собой строго типизированный список объектов, к которым можно получить доступ по индексу.

Это изменяемый аналог класса List. Он похож на массивы, так как к нему можно получить доступ по индексу, однако, в отличие от массивов, списки могут быть изменены. Поэтому при декларировании размер указывать не нужно.

Создание изменяемого списка

Списки создаются с использованием newключевое слово и вызов конструктора списка. Следующий пример демонстрирует это -

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Класс List (T)

Класс List (T) представляет собой строго типизированный список объектов, к которым можно получить доступ по индексу. Он предоставляет методы для поиска, сортировки и управления списками.

В следующих таблицах представлены свойства, конструкторы и методы класса List (T):

Свойства

Свойство Описание
Вместимость Возвращает или задает общее количество элементов, которые внутренняя структура данных может содержать без изменения размера.
Считать Получает количество элементов, содержащихся в списке (T).
Вещь Получает или задает элемент по указанному индексу.

Конструкторы

Конструктор Описание
Список (T) () Инициализирует новый пустой экземпляр класса List (T) с начальной емкостью по умолчанию.
Список (T) (IEnumerable (T)) Инициализирует новый экземпляр класса List (T), который содержит элементы, скопированные из указанной коллекции, и имеет достаточную емкость, чтобы вместить количество скопированных элементов.
Список (T) (Int32) Инициализирует новый пустой экземпляр класса List (T) с указанной начальной емкостью.

Метод

Методы Описание
Добавить Добавляет объект в конец списка (T).
AddRange Добавляет элементы указанной коллекции в конец списка (T).
AsReadOnly Возвращает доступную только для чтения оболочку IList (T) для текущей коллекции.
BinarySearch (T) Выполняет поиск элемента во всем отсортированном списке (T), используя компаратор по умолчанию, и возвращает отсчитываемый от нуля индекс элемента.
BinarySearch (T, IComparer (T)) Выполняет поиск элемента во всем отсортированном списке (T) с помощью указанного компаратора и возвращает отсчитываемый от нуля индекс элемента.
Бинарный поиск (Int32, Int32, T, IComparer (T)) Выполняет поиск элемента в диапазоне элементов в отсортированном списке (T), используя указанный компаратор, и возвращает отсчитываемый от нуля индекс элемента.
Очистить Удаляет все элементы из списка (T).
Содержит Определяет, находится ли элемент в списке (T).
ConvertAll (TOutput) Преобразует элементы в текущем списке (T) в другой тип и возвращает список, содержащий преобразованные элементы.
CopyTo (T []) Копирует весь список (T) в совместимый одномерный массив, начиная с начала целевого массива.
CopyTo (T [], Int32) Копирует весь список (T) в совместимый одномерный массив, начиная с указанного индекса целевого массива.
CopyTo (Int32, T [], Int32, Int32) Копирует диапазон элементов из списка (T) в совместимый одномерный массив, начиная с указанного индекса целевого массива.
Равно (объект) Определяет, равен ли указанный объект текущему объекту. (Унаследовано от Object.)
Существует Определяет, содержит ли список (T) элементы, которые соответствуют условиям, определенным указанным предикатом.
Завершить Позволяет объекту попытаться освободить ресурсы и выполнить другие операции очистки, прежде чем он будет освобожден сборкой мусора (Унаследовано от Object).
найти Ищет элемент, который соответствует условиям, определенным указанным предикатом, и возвращает первое вхождение во всем списке (T).
Найти все Извлекает все элементы, соответствующие условиям, определенным указанным предикатом.
FindIndex (предикат (T)) Ищет элемент, который соответствует условиям, определенным указанным предикатом, и возвращает отсчитываемый от нуля индекс первого вхождения во всем списке (T).
FindIndex (Int32, Предикат (T)) Ищет элемент, который соответствует условиям, определенным указанным предикатом, и возвращает отсчитываемый от нуля индекс первого вхождения в диапазоне элементов в списке (T), который простирается от указанного индекса до последнего элемента.
FindIndex (Int32, Int32, предикат (T)) Ищет элемент, который соответствует условиям, определенным указанным предикатом, и возвращает отсчитываемый от нуля индекс первого вхождения в диапазоне элементов в списке (T), который начинается с указанного индекса и содержит указанное количество элементов.
FindLast Ищет элемент, который соответствует условиям, определенным указанным предикатом, и возвращает последнее вхождение во всем списке (T).
FindLastIndex (Предикат (T)) Ищет элемент, который соответствует условиям, определенным указанным предикатом, и возвращает отсчитываемый от нуля индекс последнего вхождения во всем списке (T).
FindLastIndex (Int32, предикат (T)) Ищет элемент, который соответствует условиям, определенным указанным предикатом, и возвращает отсчитываемый от нуля индекс последнего вхождения в диапазоне элементов в списке (T), который простирается от первого элемента до указанного индекса.
FindLastIndex (Int32, Int32, предикат (T)) Ищет элемент, который соответствует условиям, определенным указанным предикатом, и возвращает отсчитываемый от нуля индекс последнего вхождения в диапазоне элементов в списке (T), который содержит указанное количество элементов и заканчивается на указанном индексе.
Для каждого Выполняет указанное действие с каждым элементом списка (T).
GetEnumerator Возвращает перечислитель, который выполняет итерацию по списку (T).
GetHashCode Служит хеш-функцией по умолчанию. (Унаследовано от Object.)
GetRange Создает неглубокую копию ряда элементов в исходном списке (T).
GetType Получает тип текущего экземпляра. (Унаследовано от Object.)
IndexOf (T) Выполняет поиск указанного объекта и возвращает отсчитываемый от нуля индекс первого вхождения во всем списке (T).
IndexOf (T, Int32) Выполняет поиск указанного объекта и возвращает отсчитываемый от нуля индекс первого вхождения в диапазоне элементов в списке (T), который простирается от указанного индекса до последнего элемента.
IndexOf (T, Int32, Int32) Выполняет поиск указанного объекта и возвращает отсчитываемый от нуля индекс первого вхождения в диапазоне элементов в списке (T), который начинается с указанного индекса и содержит указанное количество элементов.
Вставить Вставляет элемент в список (T) по указанному индексу.
InsertRange Вставляет элементы коллекции в список (T) по указанному индексу.
LastIndexOf (T) Выполняет поиск указанного объекта и возвращает отсчитываемый от нуля индекс последнего вхождения во всем списке (T).
LastIndexOf (T, Int32) Выполняет поиск указанного объекта и возвращает отсчитываемый от нуля индекс последнего вхождения в диапазоне элементов в списке (T), который простирается от первого элемента до указанного индекса.
LastIndexOf (T, Int32, Int32) Выполняет поиск указанного объекта и возвращает отсчитываемый от нуля индекс последнего вхождения в диапазоне элементов в списке (T), который содержит указанное количество элементов и заканчивается указанным индексом.
MemberwiseClone Создает неглубокую копию текущего объекта. (Унаследовано от Object.)
удалять Удаляет первое вхождение определенного объекта из списка (T).
Убрать все Удаляет все элементы, соответствующие условиям, определенным указанным предикатом.
RemoveAt Удаляет элемент по указанному индексу списка (T).
RemoveRange Удаляет ряд элементов из списка (T).
Обеспечить регресс() Изменяет порядок элементов во всем списке (T).
Обратный (Int32, Int32) Изменяет порядок элементов в указанном диапазоне на обратный.
Сортировать() Сортирует элементы во всем списке (T), используя компаратор по умолчанию.
Сортировать (Сравнение (T)) Сортирует элементы во всем списке (T), используя указанную систему. Сравнение (T).
Сортировка (IComparer (T)) Сортирует элементы во всем списке (T) с использованием указанного компаратора.
Сортировка (Int32, Int32, IComparer (T)) Сортирует элементы в диапазоне элементов в списке (T) с использованием указанного компаратора.
ToArray Копирует элементы списка (T) в новый массив.
Нанизывать Возвращает строку, которая представляет текущий объект. (Унаследовано от Object.)
TrimExcess Устанавливает емкость равной фактическому количеству элементов в списке (T), если это число меньше порогового значения.
TrueForAll Определяет, соответствует ли каждый элемент в списке (T) условиям, определенным указанным предикатом.

пример

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

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

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

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

В Dictionary<'TKey, 'TValue> class является изменяемым аналогом структуры данных карты F # и содержит многие из тех же функций.

Резюмируя из главы «Карты» в F #, карта - это особый вид набора, который связывает значения с ключом.

Создание изменяемого словаря

Изменяемые словари создаются с использованием newключевое слово и вызов конструктора списка. Следующий пример демонстрирует это -

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Словарь (TKey, TValue) Класс

Класс Dictionary (TKey, TValue) представляет собой набор ключей и значений.

В следующих таблицах представлены свойства, конструкторы и методы класса List (T):

Свойства

Свойство Описание
Сравнить Получает IEqualityComparer (T), который используется для определения равенства ключей для словаря.
Считать Получает количество пар ключ / значение, содержащихся в Словаре (TKey, TValue).
Вещь Получает или задает значение, связанное с указанным ключом.
Ключи Получает коллекцию, содержащую ключи в словаре (TKey, TValue).
Значения Получает коллекцию, содержащую значения в словаре (TKey, TValue).

Конструкторы

Конструкторы Описание
Словарь (TKey, TValue) () Инициализирует новый экземпляр Dictionary(TKey, TValue) пуст, имеет начальную емкость по умолчанию и использует компаратор проверки на равенство по умолчанию для типа ключа.
Словарь (TKey, TValue) (IDictionary (TKey, TValue)) Инициализирует новый экземпляр Dictionary(TKey, TValue) класс, содержащий элементы, скопированные из указанного IDictionary(TKey, TValue) и использует компаратор проверки на равенство по умолчанию для типа ключа.
Словарь (TKey, TValue) (IEqualityComparer (TKey)) Инициализирует новый экземпляр Dictionary(TKey, TValue) пустой класс, имеющий начальную емкость по умолчанию и использующий указанную IEqualityComparer(T).
Словарь (TKey, TValue) (Int32) Инициализирует новый экземпляр Dictionary(TKey, TValue) Пустой класс, имеющий указанную начальную емкость и использующий компаратор проверки на равенство по умолчанию для типа ключа.
Словарь (TKey, TValue) (IDictionary (TKey, TValue), IEqualityComparer (TKey)) Инициализирует новый экземпляр Dictionary(TKey, TValue) класс, содержащий элементы, скопированные из указанного IDictionary(TKey, TValue) и использует указанные IEqualityComparer(T).
Словарь (TKey, TValue) (Int32, IEqualityComparer (TKey)) Инициализирует новый экземпляр Dictionary(TKey, TValue) пустой класс, имеющий указанную начальную емкость и использующий указанную IEqualityComparer(T).
Словарь (TKey, TValue) (SerializationInfo, StreamingContext) Инициализирует новый экземпляр ictionary(TKey, TValue) класс с сериализованными данными.

Методы

Метод Описание
Добавить Добавляет указанный ключ и значение в словарь.
Очистить Удаляет все ключи и значения из Словаря (TKey, TValue).
ContainsKey Определяет, содержит ли Dictionary (TKey, TValue) указанный ключ.
ContainsValue Определяет, содержит ли Dictionary (TKey, TValue) определенное значение.
Равно (объект) Определяет, равен ли указанный объект текущему объекту. (Унаследовано от Object.)
Завершить Позволяет объекту попытаться освободить ресурсы и выполнить другие операции очистки, прежде чем он будет освобожден сборкой мусора. (Унаследовано от Object.)
GetEnumerator Возвращает перечислитель, который выполняет итерацию по словарю (TKey, TValue).
GetHashCode Служит хеш-функцией по умолчанию. (Унаследовано от Object.)
GetObjectData Реализует интерфейс System.Runtime.Serialization.ISerializable и возвращает данные, необходимые для сериализации экземпляра Dictionary (TKey, TValue).
GetType Получает тип текущего экземпляра. (Унаследовано от Object.)
MemberwiseClone Создает неглубокую копию текущего объекта. (Унаследовано от Object.)
OnDeserialization Реализует интерфейс System.Runtime.Serialization.ISerializable и вызывает событие десериализации, когда десериализация завершена.
удалять Удаляет значение с указанным ключом из Словаря (TKey, TValue).
Нанизывать Возвращает строку, которая представляет текущий объект. (Унаследовано от Object.)
TryGetValue Получает значение, связанное с указанным ключом.

пример

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Базовый ввод-вывод включает -

  • Чтение и запись в консоль.
  • Чтение и запись в файл.

Модуль Core.Printf

Мы использовали функции printf и printfn для записи в консоль. В этом разделе мы подробно рассмотримPrintf модуль F #.

Помимо перечисленных выше функций, модуль Core.Printf F # имеет различные другие методы печати и форматирования с использованием маркеров% в качестве заполнителей. В следующей таблице показаны методы с кратким описанием -

Значение Описание
bprintf: StringBuilder → BuilderFormat <'T> →' T Печатает в StringBuilder.
eprintf: TextWriterFormat <'T> →' T Печатает отформатированный вывод в stderr.
eprintfn: TextWriterFormat <'T> →' T Печатает форматированный вывод в stderr, добавляя новую строку.
failwithf: StringFormat <'T,' Результат> → 'T Печатает в строковый буфер и вызывает исключение с заданным результатом.
fprintf: TextWriter → TextWriterFormat <'T> →' T Печатает автору текста.
fprintfn: TextWriter → TextWriterFormat <'T> →' T Печатает автору текста с добавлением новой строки.
kbprintf: (unit → 'Результат) → StringBuilder → BuilderFormat <' T, 'Результат> →' T Подобно bprintf, но вызывает указанную функцию для генерации результата.
kfprintf: (unit → 'Результат) → TextWriter → TextWriterFormat <' T, 'Результат> →' T Подобно fprintf, но вызывает указанную функцию для генерации результата.
kprintf: (строка → 'Результат) → StringFormat <' T, 'Результат> →' T Подобен printf, но вызывает указанную функцию для генерации результата. Например, они позволяют принудительно смывать печать после того, как весь вывод был введен в канал, но не раньше.
ksprintf: (строка → 'Результат) → StringFormat <' T, 'Результат> →' T Подобно sprintf, но вызывает указанную функцию для генерации результата.
printf: TextWriterFormat <'T> →' T Выводит форматированный вывод на стандартный вывод.
printfn: TextWriterFormat <'T> →' T Печатает форматированный вывод в стандартный вывод, добавляя новую строку.
sprintf: StringFormat <'T> →' T Печатает в строку с использованием внутреннего строкового буфера и возвращает результат в виде строки.

Спецификации формата

Спецификации формата используются для форматирования ввода или вывода в соответствии с потребностями программистов.

Это строки с маркерами%, указывающими заполнители формата.

Синтаксис заполнителей формата:

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

В type интерпретируется как -

Тип Описание
% b Форматы a bool, отформатирован как true или же false.
% c Форматирует символ.
% s Форматы a string, форматируется как его содержимое, без интерпретации каких-либо escape-символов.
% d,% i Форматирует любой базовый целочисленный тип в формате десятичного целого числа со знаком, если основной целочисленный тип подписан.
% u Форматирует любой базовый целочисленный тип в виде десятичного целого числа без знака.
%Икс Форматирует любой базовый целочисленный тип в виде шестнадцатеричного целого числа без знака, используя строчные буквы от a до f.
%ИКС Форматирует любой базовый целочисленный тип в виде шестнадцатеричного целого числа без знака с использованием прописных букв от A до F.
% o Форматирует любой базовый целочисленный тип как восьмеричное целое число без знака.
% e,% E,% f,% F,% g,% G Форматирует любой базовый тип с плавающей запятой (float, float32) форматируется с использованием спецификаций формата с плавающей запятой в стиле C.
% e,% E Форматирует знаковое значение в форме [-] d.dddde [sign] ddd, где d - одна десятичная цифра, dddd - одна или несколько десятичных цифр, ddd - ровно три десятичных цифры, а знак - + или -.
% f Форматирует значение со знаком в форме [-] dddd.dddd, где dddd - одна или несколько десятичных цифр. Количество цифр перед десятичной точкой зависит от величины числа, а количество цифр после десятичной точки зависит от требуемой точности.
% г,% G Форматирует значение со знаком, напечатанное в формате f или e, в зависимости от того, какой из них более компактный для данного значения и точности.
% M Форматирует десятичное значение.
% O Форматирует любое значение, напечатанное, помещая объект в рамку и используя его ToString метод.
% А,% + А Форматирует любое значение, напечатанное с настройками макета по умолчанию. Используйте% + A, чтобы распечатать структуру размеченных объединений с внутренними и частными представлениями.
% а

Спецификатор общего формата требует двух аргументов. Первый аргумент - это функция, которая принимает два аргумента: во-первых, параметр контекста соответствующего типа для данной функции форматирования (например, TextWriter), а во-вторых, значение для печати, которое либо выводит, либо возвращает соответствующий текст.

Второй аргумент - это конкретное значение для печати.

% t Для спецификатора общего формата требуется один аргумент: функция, которая принимает параметр контекста соответствующего типа для данной функции форматирования (aTextWriter) и которая либо выводит, либо возвращает соответствующий текст. Основные целочисленные типы:byte, sbyte, int16, uint16, int32, uint32, int64, uint64, nativeint, и unativeint. Основные типы с плавающей запятой: float и float32.

В widthнеобязательный параметр. Это целое число, указывающее минимальную ширину результата. Например,% 5d печатает целое число с пробелами не менее 5 символов.

Действительный flags описаны в следующей таблице -

Значение Описание
0 Задает добавление нулей вместо пробелов для получения необходимой ширины.
- Задает выравнивание результата по левому краю в пределах указанной ширины.
+ Задает добавление символа +, если число положительное (чтобы соответствовать знаку - для отрицательных чисел).
' ' (пространство) Задает добавление дополнительного пробела, если число положительное (чтобы соответствовать знаку - для отрицательных чисел).
# Недействительным.

пример

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Консольный класс

Этот класс является частью платформы .NET. Он представляет собой стандартные потоки ввода, вывода и ошибок для консольных приложений.

Он предоставляет различные методы для чтения и записи в консоль. В следующей таблице показаны методы -

Метод Описание
Звуковой сигнал () Воспроизводит звуковой сигнал через динамик консоли.
Звуковой сигнал (Int32, Int32) Воспроизводит звуковой сигнал определенной частоты и длительности через динамик консоли.
Очистить Очищает буфер консоли и соответствующее окно консоли от отображаемой информации.
MoveBufferArea (Int32, Int32, Int32, Int32, Int32, Int32) Копирует указанную исходную область экранного буфера в указанную целевую область.
MoveBufferArea (Int32, Int32, Int32, Int32, Int32, Int32, Char, ConsoleColor, ConsoleColor) Копирует указанную исходную область экранного буфера в указанную целевую область.
OpenStandardError () Получает стандартный поток ошибок.
OpenStandardError (Int32) Получает стандартный поток ошибок, для которого задан указанный размер буфера.
OpenStandardInput () Получает стандартный входной поток.
OpenStandardInput (Int32) Получает стандартный входной поток, для которого задан размер буфера.
OpenStandardOutput () Получает стандартный выходной поток.
OpenStandardOutput (Int32) Получает стандартный выходной поток, для которого задан указанный размер буфера.
Читать Читает следующий символ из стандартного входного потока.
ReadKey () Получает следующий символ или функциональную клавишу, нажатую пользователем. Нажатая клавиша отображается в окне консоли.
ReadKey (логический) Получает следующий символ или функциональную клавишу, нажатую пользователем. Нажатая клавиша дополнительно отображается в окне консоли.
ReadLine Читает следующую строку символов из стандартного входного потока.
ResetColor Устанавливает цвета консоли переднего плана и фона по умолчанию.
SetBufferSize Устанавливает высоту и ширину буферной области экрана на указанные значения.
SetCursorPosition Устанавливает позицию курсора.
SetError Устанавливает свойство Error для указанного объекта TextWriter .
SetIn Устанавливает свойство In для указанного объекта TextReader .
SetOut Устанавливает свойство Out для указанного объекта TextWriter .
SetWindowPosition Устанавливает положение окна консоли относительно экранного буфера.
SetWindowSize Устанавливает заданные значения высоты и ширины окна консоли.
Запись (логическое значение) Записывает текстовое представление указанного логического значения в стандартный выходной поток.
Написать (Char) Записывает указанное значение символа Юникода в стандартный выходной поток.
Написать (Char []) Записывает указанный массив символов Юникода в стандартный выходной поток.
Написать (десятичный) Записывает текстовое представление указанного значения Decimal в стандартный выходной поток.
Написать (двойной) Записывает текстовое представление указанного значения с плавающей запятой двойной точности в стандартный выходной поток.
Написать (Int32) Записывает текстовое представление указанного 32-разрядного целого числа со знаком в стандартный выходной поток.
Запись (Int64) Записывает текстовое представление указанного 64-битового целого числа со знаком в стандартный выходной поток.
Написать (объект) Записывает текстовое представление указанного объекта в стандартный поток вывода.
Написать (Single) Записывает текстовое представление указанного значения с плавающей запятой одинарной точности в стандартный выходной поток.
Написать (строка) Записывает указанное строковое значение в стандартный выходной поток.
Написать (UInt32) Записывает текстовое представление указанного 32-разрядного целого числа без знака в стандартный поток вывода.
Написать (UInt64) Записывает текстовое представление указанного 64-битового целого числа без знака в стандартный поток вывода.
Написать (Строка, Объект) Записывает текстовое представление указанного объекта в стандартный поток вывода, используя информацию указанного формата.
Написать (Строка, Объект []) Записывает текстовое представление указанного массива объектов в стандартный выходной поток, используя указанную информацию о формате.
Запись (Char [], Int32, Int32) Записывает указанный подмассив символов Юникода в стандартный выходной поток.
Запись (строка, объект, объект) Записывает текстовое представление указанных объектов в стандартный поток вывода, используя информацию указанного формата.
Запись (строка, объект, объект, объект) Записывает текстовое представление указанных объектов в стандартный поток вывода, используя информацию указанного формата.
Запись (строка, объект, объект, объект, объект) Записывает текстовое представление указанных объектов и список параметров переменной длины в стандартный поток вывода с использованием информации указанного формата.
WriteLine () Записывает терминатор текущей строки в стандартный поток вывода.
WriteLine (логический) Записывает текстовое представление указанного логического значения, за которым следует признак конца текущей строки, в стандартный поток вывода.
WriteLine (симв.) Записывает указанный символ Юникода, за которым следует текущий признак конца строки, в стандартный выходной поток.
WriteLine (Char []) Записывает указанный массив символов Юникода, за которым следует признак конца текущей строки, в стандартный поток вывода.
WriteLine (десятичный) Записывает текстовое представление указанного значения Decimal, за которым следует признак конца текущей строки, в стандартный поток вывода.
WriteLine (двойной) Записывает текстовое представление указанного значения с плавающей запятой двойной точности, за которым следует текущий признак конца строки, в стандартный выходной поток.
WriteLine (Int32) Записывает текстовое представление указанного 32-разрядного целого числа со знаком, за которым следует текущий признак конца строки, в стандартный поток вывода.
WriteLine (Int64) Записывает текстовое представление указанного 64-битового целого числа со знаком, за которым следует текущий признак конца строки, в стандартный поток вывода.
WriteLine (объект) Записывает текстовое представление указанного объекта, за которым следует признак конца текущей строки, в стандартный поток вывода.
WriteLine (одиночный) Записывает текстовое представление указанного значения с плавающей запятой одинарной точности, за которым следует текущий признак конца строки, в стандартный поток вывода.
WriteLine (строка) Записывает указанное строковое значение, за которым следует текущий признак конца строки, в стандартный выходной поток.
WriteLine (UInt32) Записывает текстовое представление указанного 32-битового целого числа без знака, за которым следует текущий признак конца строки, в стандартный поток вывода.
WriteLine (UInt64) Записывает текстовое представление указанного 64-битового целого числа без знака, за которым следует текущий признак конца строки, в стандартный поток вывода.
WriteLine (строка, объект) Записывает текстовое представление указанного объекта, за которым следует признак конца текущей строки, в стандартный выходной поток, используя указанную информацию о формате.
WriteLine (String, Object []) Записывает текстовое представление указанного массива объектов, за которым следует признак конца текущей строки, в стандартный поток вывода, используя указанную информацию о формате.
WriteLine (Char [], Int32, Int32) Записывает указанный подмассив символов Юникода, за которым следует текущий признак конца строки, в стандартный поток вывода.
WriteLine (строка, объект, объект) Записывает текстовое представление указанных объектов, за которым следует признак конца текущей строки, в стандартный поток вывода, используя указанную информацию о формате.
WriteLine (строка, объект, объект, объект) Записывает текстовое представление указанных объектов, за которым следует признак конца текущей строки, в стандартный поток вывода, используя указанную информацию о формате.
WriteLine (строка, объект, объект, объект, объект) Записывает текстовое представление указанных объектов и список параметров переменной длины, за которым следует признак конца текущей строки, в стандартный поток вывода с использованием информации указанного формата.

В следующем примере демонстрируется чтение с консоли и запись в нее -

пример

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пространство имен System.IO

Пространство имен System.IO содержит множество полезных классов для выполнения базового ввода-вывода.

Он содержит типы или классы, которые позволяют читать и записывать файлы и потоки данных, а также типы, которые обеспечивают базовую поддержку файлов и каталогов.

Классы, полезные для работы с файловой системой -

  • Класс System.IO.File используется для создания, добавления и удаления файлов.
  • Класс System.IO.Directory используется для создания, перемещения и удаления каталогов.
  • Класс System.IO.Path выполняет операции со строками, которые представляют пути к файлам.
  • System.IO.FileSystemWatcher класс позволяет пользователям прослушивать каталог на предмет изменений.

Классы, полезные для работы с потоками (последовательность байтов) -

  • Класс System.IO.StreamReader используется для чтения символов из потока.
  • Класс System.IO.StreamWriter используется для записи символов в поток.
  • Класс System.IO.MemoryStream создает поток байтов в памяти.

В следующей таблице показаны все классы, представленные в пространстве имен, вместе с кратким описанием.

Класс Описание
BinaryReader Считывает примитивные типы данных как двоичные значения в определенной кодировке.
BinaryWriter Записывает примитивные типы в двоичном формате в поток и поддерживает запись строк в определенной кодировке.
Буферизованный поток Добавляет слой буферизации для операций чтения и записи в другом потоке.
Каталог Предоставляет статические методы для создания, перемещения и перечисления каталогов и подкаталогов.
DirectoryInfo Предоставляет методы экземпляра для создания, перемещения и перечисления по каталогам и подкаталогам.
DirectoryNotFoundException Исключение, которое выдается, когда не удается найти часть файла или каталога.
DriveInfo Предоставляет доступ к информации о диске.
DriveNotFoundException Исключение, возникающее при попытке получить доступ к недоступному диску или общему ресурсу.
EndOfStreamException Исключение, которое выдается при попытке чтения после конца потока.
ErrorEventArgs Предоставляет данные для события FileSystemWatcher.Error.
файл Предоставляет статические методы для создания, копирования, удаления, перемещения и открытия одного файла, а также помогает в создании объектов FileStream.
FileFormatException Исключение, которое выдается, когда входной файл или поток данных, который должен соответствовать определенной спецификации формата файла, имеет неправильный формат.
FileInfo Предоставляет свойства и методы экземпляра для создания, копирования, удаления, перемещения и открытия файлов, а также помогает в создании объектов FileStream.
FileLoadException Исключение, которое выдается, когда управляемая сборка обнаружена, но не может быть загружена.
FileNotFoundException Исключение, которое выдается при неудачной попытке доступа к файлу, которого нет на диске.
FileStream Предоставляет поток вокруг файла, поддерживая как синхронные, так и асинхронные операции чтения и записи.
FileSystemEventArgs Предоставляет данные для событий каталога - Изменено, Создано, Удалено.
FileSystemInfo Предоставляет базовый класс для объектов FileInfo и DirectoryInfo.
FileSystemWatcher Прослушивает уведомления об изменении файловой системы и генерирует события при изменении каталога или файла в каталоге.
InternalBufferOverflowException Исключение возникает при переполнении внутреннего буфера.
InvalidDataException Исключение, которое выдается, когда поток данных имеет недопустимый формат.
IODescriptionAttribute Задает описание, которое визуальные дизайнеры могут отображать при ссылке на событие, расширитель или свойство.
IOException Исключение, которое выдается при возникновении ошибки ввода-вывода.
MemoryStream Создает поток, резервным хранилищем которого является память.
Путь Выполняет операции с экземплярами String, которые содержат информацию о пути к файлу или каталогу. Эти операции выполняются кроссплатформенным образом.
PathTooLongException Исключение, которое выдается, когда путь или имя файла длиннее максимальной длины, определенной системой.
PipeException Вызывается, когда в именованном канале возникает ошибка.
RenamedEventArgs Предоставляет данные для события Renamed.
Поток Предоставляет общее представление о последовательности байтов. Это абстрактный класс.
StreamReader Реализует TextReader, который считывает символы из байтового потока в определенной кодировке.
StreamWriter Реализует TextWriter для записи символов в поток в определенной кодировке. Чтобы просмотреть исходный код .NET Framework для этого типа, см. Справочный источник.
StringReader Реализует TextReader, который читает из строки.
StringWriter Реализует TextWriter для записи информации в строку. Информация хранится в базовом StringBuilder.
TextReader Представляет средство чтения, которое может читать последовательные серии символов.
TextWriter Представляет писателя, который может писать последовательные серии символов. Этот класс абстрактный.
UnmanagedMemoryAccessor Предоставляет произвольный доступ к неуправляемым блокам памяти из управляемого кода.
НеуправляемыйMemoryStream Предоставляет доступ к неуправляемым блокам памяти из управляемого кода.
WindowsRuntimeStorageExtensions Содержит методы расширения для интерфейсов IStorageFile и IStorageFolder в среде выполнения Windows при разработке приложений Магазина Windows.
WindowsRuntimeStreamExtensions Содержит методы расширения для преобразования между потоками в среде выполнения Windows и управляемыми потоками в .NET для приложений Магазина Windows.

пример

В следующем примере создается файл с именем test.txt, записывается в него сообщение, считывается текст из файла и печатается его на консоли.

Note - Количество кода, необходимого для этого, на удивление меньше!

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

Hello There
Welcome to:
Tutorials Point

Обобщения позволяют отложить спецификацию типа данных элементов программирования в классе или методе до тех пор, пока он не будет фактически использован в программе. Другими словами, универсальные шаблоны позволяют вам написать класс или метод, который может работать с любым типом данных.

Вы пишете спецификации для класса или метода с заменяющими параметрами для типов данных. Когда компилятор встречает конструктор для класса или вызов функции для метода, он генерирует код для обработки определенного типа данных.

В F # значения функций, методы, свойства и агрегированные типы, такие как классы, записи и размеченные объединения, могут быть общими.

Универсальные конструкции содержат по крайней мере один параметр типа. Универсальные функции и типы позволяют писать код, работающий с различными типами, без повторения кода для каждого типа.

Синтаксис

Синтаксис для написания общей конструкции следующий:

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

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

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

Примеры

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

printFunc<float> 10.0 20.0

Когда вы компилируете и выполняете программу, она дает следующий результат:

10.0, 20.0

Вы также можете сделать функцию универсальной, используя синтаксис одинарных кавычек -

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

printFunction 10.0 20.0

Когда вы компилируете и выполняете программу, она дает следующий результат:

10.0 20.0

Обратите внимание, что при использовании общих функций или методов может не потребоваться указывать аргументы типа. Однако в случае двусмысленности вы можете указать аргументы типа в угловых скобках, как мы это сделали в первом примере.

Если у вас более одного типа, вы разделяете несколько аргументов типа запятыми.

Общий класс

Подобно универсальным функциям, вы также можете писать универсальные классы. Следующий пример демонстрирует это -

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Делегат - это переменная ссылочного типа, которая содержит ссылку на метод. Ссылку можно изменить во время выполнения. Делегаты F # похожи на указатели на функции в C или C ++.

Объявление делегатов

Объявление делегата определяет методы, на которые может ссылаться делегат. Делегат может ссылаться на метод, имеющий ту же сигнатуру, что и у делегата.

Синтаксис для объявления делегата -

type delegate-typename = delegate of type1 -> type2

Например, рассмотрим делегатов -

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

Оба делегата могут использоваться для ссылки на любой метод, который имеет два параметра int и возвращает переменную типа int .

В синтаксисе -

  • type1 представляет тип (ы) аргумента.

  • type2 представляет возвращаемый тип.

Обратите внимание -

  • Типы аргументов каррируются автоматически.

  • Делегаты могут быть прикреплены к значениям функций и статическим методам или методам экземпляра.

  • Значения функции F # могут быть переданы непосредственно в качестве аргументов конструкторам делегатов.

  • Для статического метода делегат вызывается с использованием имени класса и метода. Для метода экземпляра используется имя экземпляра объекта и метода.

  • Метод Invoke для типа делегата вызывает инкапсулированную функцию.

  • Кроме того, делегаты могут быть переданы как значения функции, указав имя метода Invoke без скобок.

Следующий пример демонстрирует концепцию -

пример

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

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

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

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

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Перечисление - это набор именованных целочисленных констант.

В F #, enumerations, также известный как enums,являются целыми типами, в которых метки присваиваются подмножеству значений. Вы можете использовать их вместо литералов, чтобы сделать код более читабельным и поддерживаемым.

Объявление перечислений

Общий синтаксис объявления перечисления -

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

В следующем примере демонстрируется использование перечислений -

пример

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

Monday: Mon
Saturday: Sat
Sunday: Sun

Сопоставление с образцом позволяет «сравнивать данные с логической структурой или структурами, разлагать данные на составные части или извлекать информацию из данных различными способами».

Другими словами, он обеспечивает более гибкий и мощный способ проверки данных на соответствие ряду условий и выполнения некоторых вычислений на основе выполненного условия.

Концептуально это похоже на серию утверждений «если… то».

Синтаксис

В терминах высокого уровня сопоставление с образцом следует этому синтаксису в F # -

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

Где,

  • Каждый | символ определяет состояние.
  • Символ -> означает «если условие верно, вернуть это значение ...».
  • Символ _ обеспечивает шаблон по умолчанию, что означает, что он соответствует всем остальным вещам, например подстановочным знакам.

Пример 1

В следующем примере вычисляются числа Фибоначчи с использованием синтаксиса сопоставления с образцом -

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Вы также можете объединить несколько условий в цепочку, которые возвращают одно и то же значение. Например -

Пример 2

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

Winter
Spring
Autumn
Rainy

Функции сопоставления с образцом

F # позволяет писать функции сопоставления с образцом, используя function ключевое слово -

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

10
20.5
21
8.75
15

Добавление фильтров или охранников к узорам

Вы можете добавить фильтры или охранники к узорам, используя when ключевое слово.

Пример 1

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

-1
1
0

Пример 2

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Сопоставление с образцом с кортежами

В следующем примере демонстрируется сопоставление с образцом с кортежами -

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Сопоставление шаблонов с записями

В следующем примере демонстрируется сопоставление шаблонов с записями -

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Исключением является проблема, возникающая во время выполнения программы. Исключение F # - это реакция на исключительное обстоятельство, которое возникает во время работы программы, например, попытка деления на ноль.

Исключения позволяют передавать управление от одной части программы к другой. Обработка исключений F # предоставляет следующие конструкции:

Построить Описание
поднять выражение Вызывает данное исключение.
failwith expr Поднимает System.Exception исключение.
попробуйте выражение с правилами Отлавливает выражения, соответствующие шаблонным правилам.
попробуйте expr, наконец, expr Выполнение finally выражение как при успешном вычислении, так и при возникновении исключения.
| :? ArgumentException Правило, соответствующее данному типу исключения .NET.
| :? ArgumentException как e Правило, соответствующее данному типу исключения .NET, привязка имени e к значению объекта исключения.
| Ошибка (сообщение) → выражение Правило, соответствующее данному исключению F #, несущему данные.
| exn → expr Правило, соответствующее любому исключению, привязка имени exn к значению объекта исключения.
| exn, когда expr → expr Правило, соответствующее исключению при заданном условии, связывающее имя exn к значению объекта исключения.

Начнем с базового синтаксиса обработки исключений.

Синтаксис

Базовый синтаксис для блока обработки исключений F # -

exception exception-type of argument-type

Где,

  • exception-type - это имя нового типа исключения F #.

  • argument-type представляет тип аргумента, который может быть предоставлен при возникновении исключения этого типа.

  • Можно указать несколько аргументов, используя тип кортежа для типа аргумента.

В try...with выражение используется для обработки исключений в языке F #.

Синтаксис для попытки… с выражением -

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

В try...finally выражение позволяет выполнять код очистки, даже если блок кода вызывает исключение.

Синтаксис для выражения try… finally -

try
   expression1
finally
   expression2

В raiseФункция используется, чтобы указать, что произошла ошибка или исключительное состояние. Он также фиксирует информацию об ошибке в объекте исключения.

Синтаксис функции повышения -

raise (expression)

В failwith функция генерирует исключение F #.

Синтаксис функции failwith -

failwith error-message-string

В invalidArg функция генерирует исключение аргумента.

invalidArg parameter-name error-message-string

Пример обработки исключений

Пример 1

Следующая программа показывает базовую обработку исключений с помощью простой попытки ... с блоком -

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

let result1 = divisionprog 100 0

Когда вы компилируете и выполняете программу, она дает следующий результат:

Division by zero!

Пример 2

F # предоставляет exceptionтип объявления исключений. Вы можете использовать тип исключения непосредственно в фильтрах вtry...with выражение.

Следующий пример демонстрирует это -

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

Error2 Error Not detected 100
Error1 Equal Number Error

Пример 3

В следующем примере демонстрируется обработка вложенных исключений -

exception InnerError of string
exception OuterError of string

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

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

func2 100 150
func2 100 100
func2 100 120

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пример 4

Следующая функция демонстрирует failwith функция -

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

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

Divisor cannot be zero.
0
25

Пример 5

В invalidArgфункция генерирует исключение аргумента. Следующая программа демонстрирует это -

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

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Некоторая другая информация о файле и переменной, вызывающих ошибку в системе, также будет отображаться в зависимости от системы.

Классы - это типы, представляющие объекты, которые могут иметь свойства, методы и события. «Они используются для моделирования действий, процессов и любых концептуальных объектов в приложениях».

Синтаксис

Синтаксис для определения типа класса следующий:

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

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

Где,

  • В type-nameлюбой допустимый идентификатор. Модификатор доступа по умолчанию для этого:public.

  • В type-params описывает необязательные параметры универсального типа.

  • В parameter-listописывает параметры конструктора. Модификатор доступа по умолчанию для основного конструктора:public.

  • В identifier используется с необязательным as ключевое слово дает имя переменной экземпляра, или self-identifier, который можно использовать в определении типа для ссылки на экземпляр типа.

  • В inherit ключевое слово позволяет указать базовый класс для класса.

  • В let привязки позволяют объявлять поля или значения функций, локальные для класса.

  • В do-bindings Раздел включает код, который будет выполняться при построении объекта.

  • В member-list состоит из дополнительных конструкторов, объявлений экземпляров и статических методов, объявлений интерфейсов, абстрактных привязок и объявлений свойств и событий.

  • Ключевые слова class и end обозначающие начало и конец определения не являются обязательными.

Конструктор класса

Конструктор - это код, который создает экземпляр типа класса.

В F # конструкторы работают немного иначе, чем в других языках .Net. В определении класса аргументы основного конструктора описываются как список параметров.

Тело конструктора состоит из let и do привязки.

Вы можете добавить дополнительные конструкторы, используя ключевое слово new для добавления члена -

new (argument-list) = constructor-body

Следующий пример иллюстрирует концепцию -

пример

Следующая программа создает класс линии вместе с конструктором, который вычисляет длину линии при создании объекта класса:

type Line = class
   val X1 : float
   val Y1 : float
   val X2 : float
   val Y2 : float

   new (x1, y1, x2, y2) as this =
      { X1 = x1; Y1 = y1; X2 = x2; Y2 = y2;}
      then
         printfn " Creating Line: {(%g, %g), (%g, %g)}\nLength: %g"
            this.X1 this.Y1 this.X2 this.Y2 this.Length

   member x.Length =
      let sqr x = x * x
      sqrt(sqr(x.X1 - x.X2) + sqr(x.Y1 - x.Y2) )
end
let aLine = new Line(1.0, 1.0, 4.0, 5.0)

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Пусть привязки

Привязки let в определении класса позволяют определять частные поля и частные функции для классов F #.

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

Hello Zara

Обратите внимание на использование собственного идентификатора gr для класса Greetings .

Структура в F # - это тип данных типа значения. Это помогает вам создать единую переменную, хранить связанные данные различных типов данных. Вstruct ключевое слово используется для создания структуры.

Синтаксис

Синтаксис для определения структуры следующий:

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

Есть два синтаксиса. В основном используется первый синтаксис, потому что, если вы используетеstruct и end ключевые слова, вы можете опустить StructAttribute атрибут.

Элементы определения структуры обеспечивают:

  • Объявления и определения участников.
  • Конструкторы и изменяемые и неизменяемые поля.
  • Члены и реализации интерфейса.

В отличие от классов, структуры не могут быть унаследованы и не могут содержать привязки let или do. Так как структуры не имеют привязок let; вы должны объявлять поля в структурах, используяval ключевое слово.

Когда вы определяете поле и его тип с помощью valключевое слово, вы не можете инициализировать значение поля, вместо этого они инициализируются нулем или нулем. Итак, для структуры, имеющей неявный конструктор,val объявления должны быть аннотированы DefaultValue атрибут.

пример

Следующая программа создает линейную структуру вместе с конструктором. Программа рассчитывает длину линии, используя структуру -

type Line = struct
   val X1 : float
   val Y1 : float
   val X2 : float
   val Y2 : float

   new (x1, y1, x2, y2) =
      {X1 = x1; Y1 = y1; X2 = x2; Y2 = y2;}
end
let calcLength(a : Line)=
   let sqr a = a * a
   sqrt(sqr(a.X1 - a.X2) + sqr(a.Y1 - a.Y2) )

let aLine = new Line(1.0, 1.0, 4.0, 5.0)
let length = calcLength aLine
printfn "Length of the Line: %g " length

Когда вы компилируете и выполняете программу, она дает следующий результат:

Length of the Line: 5

Вы можете переопределить или перегрузить большинство встроенных операторов, доступных в F #. Таким образом, программист может использовать операторы и с пользовательскими типами.

Операторы - это функции со специальными именами, заключенными в квадратные скобки. Они должны быть определены как статические члены класса. Как и любая другая функция, перегруженный оператор имеет возвращаемый тип и список параметров.

В следующем примере показан оператор + для комплексных чисел -

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

Вышеупомянутая функция реализует оператор сложения (+) для пользовательского класса Complex. Он добавляет атрибуты двух объектов и возвращает результирующий объект Complex.

Реализация перегрузки оператора

Следующая программа показывает полную реализацию -

//implementing a complex class with +, and - operators
//overloaded
type Complex(x: float, y : float) =
   member this.x = x
   member this.y = y
   //overloading + operator
   static member (+) (a : Complex, b: Complex) =
      Complex(a.x + b.x, a.y + b.y)

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

   // overriding the ToString method
   override this.ToString() =
      this.x.ToString() + " " + this.y.ToString()

//Creating two complex numbers
let c1 = Complex(7.0, 5.0)
let c2 = Complex(4.2, 3.1)

// addition and subtraction using the
//overloaded operators
let c3 = c1 + c2
let c4 = c1 - c2

//printing the complex numbers
printfn "%s" (c1.ToString())
printfn "%s" (c2.ToString())
printfn "%s" (c3.ToString())
printfn "%s" (c4.ToString())

Когда вы компилируете и выполняете программу, она дает следующий результат:

7 5
4.2 3.1
11.2 8.1
2.8 1.9

Одна из наиболее важных концепций объектно-ориентированного программирования - это наследование. Наследование позволяет нам определять класс в терминах другого класса, что упрощает создание и поддержку приложения. Это также дает возможность повторно использовать функциональность кода и быстрое время реализации.

При создании класса вместо написания полностью новых элементов данных и функций-членов программист может указать, что новый класс должен наследовать члены существующего класса. Этот существующий класс называется базовым классом, а новый класс - производным классом.

Идея наследования реализует отношения IS-A. Например, млекопитающее - это животное, собака - это млекопитающее, следовательно, собака - это тоже животное, и так далее.

Базовый класс и подкласс

Подкласс происходит от уже определенного базового класса. Подкласс наследует члены базового класса, а также имеет свои собственные члены.

Подкласс определяется с помощью inherit ключевое слово, как показано ниже -

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

В F # класс может иметь не более одного прямого базового класса. Если вы не укажете базовый класс с помощьюinherit ключевое слово, класс неявно наследуется от Object.

Обратите внимание -

  • Методы и члены базового класса доступны пользователям производного класса, как прямые члены производного класса.

  • Пусть привязки и параметры конструктора являются частными для класса и, следовательно, не могут быть доступны из производных классов.

  • Ключевое слово baseотносится к экземпляру базового класса. Он используется как самоидентификатор.

пример

type Person(name) =
   member x.Name = name
   member x.Greet() = printfn "Hi, I'm %s" x.Name

type Student(name, studentID : int) =
   inherit Person(name)
   let mutable _GPA = 0.0
   member x.StudentID = studentID
   member x.GPA
      with get() = _GPA
      and set value = _GPA <- value

type Teacher(name, expertise : string) =
   inherit Person(name)

   let mutable _salary = 0.0
   member x.Salary
      with get() = _salary
      and set value = _salary <- value
   member x.Expertise = expertise

//using the subclasses
let p = new Person("Mohan")
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")

p.Greet()
st.Greet()
tr.Greet()

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Переопределение методов

Вы можете переопределить поведение метода базового класса по умолчанию и по-другому реализовать его в подклассе или производном классе.

По умолчанию методы в F # не переопределяются.

Чтобы переопределить методы в производном классе, вы должны объявить свой метод как переопределяемый с помощью abstract и default ключевые слова следующим образом -

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

Теперь метод Greet класса Person можно переопределить в производных классах. Следующий пример демонстрирует это -

пример

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

type Student(name, studentID : int) =
   inherit Person(name)

   let mutable _GPA = 0.0

   member x.StudentID = studentID
   member x.GPA
      with get() = _GPA
      and set value = _GPA <- value
   override x.Greet() = printfn "Student %s" x.Name

type Teacher(name, expertise : string) =
   inherit Person(name)
   let mutable _salary = 0.0
   member x.Salary
      with get() = _salary
      and set value = _salary <- value

   member x.Expertise = expertise
   override x.Greet() = printfn "Teacher %s." x.Name

//using the subclasses
let p = new Person("Mohan")
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")

//default Greet
p.Greet()

//Overriden Greet
st.Greet()
tr.Greet()

Когда вы компилируете и выполняете программу, она дает следующий результат:

Hi, I'm Mohan
Student Zara
Teacher Mariam.

Абстрактный класс

Иногда вам необходимо предоставить неполную реализацию объекта, что не должно быть реализовано в реальности. Позже другой программист должен создать подклассы абстрактного класса для полной реализации.

Например, класс Person не понадобится в системе управления школой. Тем не менее, понадобится класс ученика или учителя. В таких случаях вы можете объявить класс Person как абстрактный класс.

В AbstractClass Атрибут сообщает компилятору, что у класса есть некоторые абстрактные члены.

Вы не можете создать экземпляр абстрактного класса, потому что класс реализован не полностью.

Следующий пример демонстрирует это -

пример

[<AbstractClass>]
type Person(name) =
   member x.Name = name
   abstract Greet : unit -> unit

type Student(name, studentID : int) =
   inherit Person(name)
   let mutable _GPA = 0.0
   member x.StudentID = studentID
   member x.GPA
      with get() = _GPA
      and set value = _GPA <- value
   override x.Greet() = printfn "Student %s" x.Name

type Teacher(name, expertise : string) =
   inherit Person(name)
   let mutable _salary = 0.0
   member x.Salary
      with get() = _salary
      and set value = _salary <- value
   member x.Expertise = expertise
   override x.Greet() = printfn "Teacher %s." x.Name

let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")

//Overriden Greet
st.Greet()
tr.Greet()

Когда вы компилируете и выполняете программу, она дает следующий результат:

Student Zara
Teacher Mariam.

Интерфейсы предоставляют абстрактный способ записи деталей реализации класса. Это шаблон, который объявляет методы, которые класс должен реализовать и публично раскрыть.

Синтаксис

Интерфейс определяет наборы связанных членов, которые реализуют другие классы. Он имеет следующий синтаксис -

// Interface declaration:
[ attributes ]
type interface-name =
   [ interface ]
      [ inherit base-interface-name ...]
      abstract member1 : [ argument-types1 -> ] return-type1
      abstract member2 : [ argument-types2 -> ] return-type2
      ...
   [ end ]
	
// Implementing, inside a class type definition:
interface interface-name with
   member self-identifier.member1 argument-list = method-body1
   member self-identifier.member2 argument-list = method-body2
// Implementing, by using an object expression:
[ attributes ]
let class-name (argument-list) =
   { new interface-name with
      member self-identifier.member1 argument-list = method-body1
      member self-identifier.member2 argument-list = method-body2
      [ base-interface-definitions ]
   }
member-list

Обратите внимание -

  • В объявлении интерфейса члены не реализованы.

  • Члены абстрактны, объявлены abstractключевое слово. Однако вы можете предоставить реализацию по умолчанию, используяdefault ключевое слово.

  • Вы можете реализовать интерфейсы либо с помощью объектных выражений, либо с помощью типов классов.

  • В реализации класса или объекта вам необходимо предоставить тела методов для абстрактных методов интерфейса.

  • Ключевые слова interface и end, которые отмечают начало и конец определения, не являются обязательными.

Например,

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

Вызов методов интерфейса

Методы интерфейса вызываются через интерфейс, а не через экземпляр класса или типа, реализующего интерфейс. Чтобы вызвать метод интерфейса, вы выполняете приведение к типу интерфейса с помощью:> оператор (оператор восходящего преобразования).

Например,

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

Следующий пример иллюстрирует концепцию -

пример

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

type Student(name : string, id : int) =
   member this.ID = id
   interface IPerson with
      member this.Name = name
      member this.Enter() = printfn "Student entering premises!"
      member this.Leave() = printfn "Student leaving premises!"

type StuffMember(name : string, id : int, salary : float) =
   let mutable _salary = salary

   member this.Salary
      with get() = _salary
      and set(value) = _salary <- value

   interface IPerson with
      member this.Name = name
      member this.Enter() = printfn "Stuff member entering premises!"
      member this.Leave() = printfn "Stuff member leaving premises!"

let s = new Student("Zara", 1234)
let st = new StuffMember("Rohit", 34, 50000.0)

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

Когда вы компилируете и выполняете программу, она дает следующий результат:

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

Наследование интерфейса

Интерфейсы могут наследовать от одного или нескольких базовых интерфейсов.

В следующем примере показана концепция -

type Interface1 =
   abstract member doubleIt: int -> int

type Interface2 =
   abstract member tripleIt: int -> int

type Interface3 =
   inherit Interface1
   inherit Interface2
   abstract member printIt: int -> string

type multiplierClass() =
   interface Interface3 with
      member this.doubleIt(a) = 2 * a
      member this.tripleIt(a) = 3 * a
      member this.printIt(a) = a.ToString()

let ml = multiplierClass()
printfn "%d" ((ml:>Interface3).doubleIt(5))
printfn "%d" ((ml:>Interface3).tripleIt(5))
printfn "%s" ((ml:>Interface3).printIt(5))

Когда вы компилируете и выполняете программу, она дает следующий результат:

10
15
5

События позволяют классам отправлять и получать сообщения между собой.

В графическом интерфейсе событиями являются действия пользователя, такие как нажатие клавиш, щелчки, движения мыши и т. Д., Или некоторые события, такие как уведомления, созданные системой. Приложениям необходимо реагировать на события, когда они происходят. Например, прерывания. События используются для межпроцессного взаимодействия.

Объекты общаются друг с другом посредством синхронной передачи сообщений.

События привязаны к другим функциям; реестр объектовcallback функции для события, и эти обратные вызовы выполняются, когда (и если) событие запускается каким-либо объектом.

Класс событий и модуль событий

Класс Control.Event <'T> помогает в создании наблюдаемого объекта или события.

У него есть следующие члены экземпляра для работы с событиями:

Член Описание
Публиковать Публикует наблюдение как первоклассную ценность.
Спусковой крючок Запускает наблюдение с использованием заданных параметров.

Модуль Control.Event предоставляет функции для управления потоками событий -

Значение Описание
добавить: ('T → unit) → Event <' Del, 'T> → unit Запускает данную функцию каждый раз, когда инициируется данное событие.
выберите: ('T →' U option) → IEvent <'Del,' T> → IEvent <'U> Возвращает новое событие, которое запускается при выборе сообщений из исходного события. Функция выбора преобразует исходное сообщение в необязательное новое сообщение.
фильтр: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> Возвращает новое событие, которое прослушивает исходное событие и запускает результирующее событие только тогда, когда аргумент события передает данную функцию.
карта: ('T →' U) → IEvent <'Del,' T> → IEvent <'U> Возвращает новое событие, которое передает значения, преобразованные данной функцией.
слияние: IEvent <'Del1,' T> → IEvent <'Del2,' T> → IEvent <'T> Запускает событие вывода, когда возникает одно из событий ввода.
попарно: IEvent <'Del,' T> → IEvent <'T *' T> Возвращает новое событие, которое запускается при втором и последующих запусках входного события. ВNth запуск входного события передает аргументы из N-1th и Nthзапускается как пара. Аргумент, переданный вN-1th запуск сохраняется в скрытом внутреннем состоянии до тех пор, пока Nth происходит срабатывание.
раздел: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> * IEvent <'T> Возвращает новое событие, которое прослушивает исходное событие и запускает первое результирующее событие, если применение предиката к аргументам события вернуло значение true, и второе событие, если оно вернуло false.
сканирование: ('U →' T → 'U) →' U → IEvent <'Del,' T> → IEvent <'U> Возвращает новое событие, состоящее из результатов применения данной функции накопления к последовательным значениям, инициированным для входного события. Элемент внутреннего состояния записывает текущее значение параметра состояния. Внутреннее состояние не блокируется во время выполнения функции накопления, поэтому следует позаботиться о том, чтобы входное событие IEvent не запускалось несколькими потоками одновременно.
split: ('T → Выбор <' U1, 'U2>) → IEvent <' Del, 'T> → IEvent <' U1> * IEvent <'U2> Возвращает новое событие, которое прослушивает исходное событие и запускает первое результирующее событие, если приложение функции к аргументам события вернуло Choice1Of2, и второе событие, если оно возвращает Choice2Of2.

Создание событий

События создаются и используются через Eventкласс. Конструктор событий используется для создания события.

пример

type Worker(name : string, shift : string) =
   let mutable _name = name;
   let mutable _shift = shift;
   let nameChanged = new Event<unit>() (* creates event *)
   let shiftChanged = new Event<unit>() (* creates event *)

   member this.Name
      with get() = _name
      and set(value) = _name <- value

   member this.Shift
      with get() = _shift
      and set(value) = _shift <- value

После этого вам нужно предоставить поле nameChanged как публичный член, чтобы слушатели могли подключиться к событию, для которого вы используете Publish свойство события -

type Worker(name : string, shift : string) =
   let mutable _name = name;
   let mutable _shift = shift;

   let nameChanged = new Event<unit>() (* creates event *)
   let shiftChanged = new Event<unit>() (* creates event *)

   member this.NameChanged = nameChanged.Publish (* exposed event handler *)
   member this.ShiftChanged = shiftChanged.Publish (* exposed event handler *)

   member this.Name
      with get() = _name
      and set(value) = _name <- value
      nameChanged.Trigger() (* invokes event handler *)

   member this.Shift
      with get() = _shift
      and set(value) = _shift <- value
   shiftChanged.Trigger() (* invokes event handler *)

Затем вы добавляете обратные вызовы в обработчики событий. Каждый обработчик событий имеет тип IEvent <'T>, который предоставляет несколько методов:

Метод Описание
val Add: event :( 'T → unit) → unit Подключает функцию прослушивателя к событию. Слушатель будет вызываться при срабатывании события.
val AddHandler: 'del → unit Подключает объект делегата обработчика к событию. Позднее обработчик можно удалить с помощью RemoveHandler. Слушатель будет вызываться при срабатывании события.
val RemoveHandler: 'del → unit Удаляет делегата слушателя из хранилища слушателей событий.

В следующем разделе представлен полный пример.

пример

Следующий пример демонстрирует концепцию и методы, обсужденные выше.

type Worker(name : string, shift : string) =
   let mutable _name = name;
   let mutable _shift = shift;

   let nameChanged = new Event<unit>() (* creates event *)
   let shiftChanged = new Event<unit>() (* creates event *)

   member this.NameChanged = nameChanged.Publish (* exposed event handler *)
   member this.ShiftChanged = shiftChanged.Publish (* exposed event handler *)

   member this.Name
      with get() = _name
      and set(value) = 
         _name <- value
         nameChanged.Trigger() (* invokes event handler *)

   member this.Shift
      with get() = _shift
      and set(value) = 
         _shift <- value
         shiftChanged.Trigger() (* invokes event handler *)

let wk = new Worker("Wilson", "Evening")
wk.NameChanged.Add(fun () -> printfn "Worker changed name! New name: %s" wk.Name)
wk.Name <- "William"
wk.NameChanged.Add(fun () -> printfn "-- Another handler attached to NameChanged!")
wk.Name <- "Bill"

wk.ShiftChanged.Add(fun () -> printfn "Worker changed shift! New shift: %s" wk.Shift)
wk.Shift <- "Morning"
wk.ShiftChanged.Add(fun () -> printfn "-- Another handler attached to ShiftChanged!")
wk.Shift <- "Night"

Когда вы компилируете и выполняете программу, она дает следующий результат:

Worker changed name! New name: William
Worker changed name! New name: Bill
-- Another handler attached to NameChanged!
Worker changed shift! New shift: Morning
Worker changed shift! New shift: Night
-- Another handler attached to ShiftChanged!

Согласно библиотеке MSDN, модуль F # представляет собой группу конструкций кода F #, таких как типы, значения, значения функций и код в привязках do. Он реализован как класс общеязыковой среды выполнения (CLR), который имеет только статические члены.

В зависимости от ситуации, включен ли в модуль весь файл, есть два типа объявлений модуля:

  • Объявление модуля верхнего уровня
  • Объявление локального модуля

В объявлении модуля верхнего уровня в модуль включается весь файл. В этом случае первое объявление в файле - это объявление модуля. Вам не нужно делать отступы в объявлениях в модуле верхнего уровня.

В объявлении локального модуля только объявления с отступом под этим объявлением модуля являются частью модуля.

Синтаксис

Синтаксис для объявления модуля следующий -

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

Обратите внимание, что модификатор доступности может быть одним из следующих: публичный, частный, внутренний. По умолчаниюpublic.

Следующие примеры продемонстрируют концепции -

Пример 1

Файл модуля Arithmetic.fs -

module Arithmetic
let add x y =
   x + y

let sub x y =
   x - y
	
let mult x y =
   x * y
	
let div x y =
   x / y

Программный файл main.fs -

// Fully qualify the function name.
open Arithmetic
let addRes = Arithmetic.add 25 9
let subRes = Arithmetic.sub 25 9
let multRes = Arithmetic.mult 25 9
let divRes = Arithmetic.div 25 9

printfn "%d" addRes
printfn "%d" subRes
printfn "%d" multRes
printfn "%d" divRes

Когда вы компилируете и выполняете программу, она дает следующий результат:

34
16
225
2
110
90
1000
10

Пример 2

// Module1
module module1 =
   // Indent all program elements within modules that are declared with an equal sign.
   let value1 = 100
   let module1Function x =
      x + value1

// Module2
module module2 =
   let value2 = 200

   // Use a qualified name to access the function.
   // from module1.
   let module2Function x =
      x + (module1.module1Function value2)

let result = module1.module1Function 25
printfn "%d" result

let result2 = module2.module2Function 25
printfn "%d" result2

Когда вы компилируете и выполняете программу, она дает следующий результат:

125
325

А namespaceпредназначен для обеспечения возможности отделения одного набора имен от другого. Имена классов, объявленные в одном пространстве имен, не будут конфликтовать с такими же именами классов, объявленными в другом.

Согласно библиотеке MSDN, namespace позволяет организовать код в области связанных функций, позволяя прикрепить имя к группе элементов программы.

Объявление пространства имен

Чтобы организовать свой код в пространстве имен, вы должны объявить пространство имен как первое объявление в файле. Затем содержимое всего файла становится частью пространства имен.

namespace [parent-namespaces.]identifier

Следующий пример иллюстрирует концепцию -

пример

namespace testing

module testmodule1 =
   let testFunction x y =
      printfn "Values from Module1: %A %A" x y
module testmodule2 =
   let testFunction x y =
      printfn "Values from Module2: %A %A" x y

module usermodule =
   do
      testmodule1.testFunction ( "one", "two", "three" ) 150
      testmodule2.testFunction (seq { for i in 1 .. 10 do yield i * i }) 200

Когда вы компилируете и выполняете программу, она дает следующий результат:

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