F # - Guia rápido
F # é uma linguagem de programação funcional. Para entender as construções do F #, você precisa ler algumas linhas sobre o paradigma de programação denominadoFunctional Programming.
A programação funcional trata os programas de computador como funções matemáticas. Na programação funcional, o foco seria em constantes e funções, em vez de variáveis e estados. Porque funções e constantes são coisas que não mudam.
Na programação funcional, você escreverá programas modulares, ou seja, os programas consistiriam em funções que tomarão outras funções como entrada.
Programas escritos em linguagem de programação funcional tendem a ser concisos.
Sobre F #
A seguir estão as informações básicas sobre F # -
- Foi desenvolvido em 2005 na Microsoft Research.
- É uma parte da família da linguagem .Net da Microsoft.
- É uma linguagem de programação funcional.
- É baseado na linguagem de programação funcional OCaml.
Características do F #
É uma implementação .Net do OCaml.
Compila o código de byte .Net CLI (Common Language Interface) ou MSIL (Microsoft Intermediate Language) que é executado em CLR (Common Language Runtime).
Ele fornece inferência de tipo.
Ele fornece construções ricas de correspondência de padrões.
Possui scripts interativos e recursos de depuração.
Permite escrever funções de ordem superior.
Ele fornece um modelo de objeto bem desenvolvido.
Uso de F #
F # é normalmente usado nas seguintes áreas -
- Fazendo modelo científico
- Resolução de problemas matemáticos
- Trabalho de pesquisa de inteligência artificial
- Modelagem financeira
- Design gráfico
- Design de CPU
- Programação de compilador
- Telecommunications
Ele também é usado em aplicativos CRUD, páginas da web, jogos de GUI e outros programas de uso geral.
As ferramentas necessárias para a programação em F # são discutidas neste capítulo.
Ambiente de desenvolvimento integrado (IDE) para F #
A Microsoft fornece o Visual Studio 2013 para programação em F #.
O Visual Studio 2013 Community Edition gratuito está disponível no site oficial da Microsoft. Comunidade do Visual Studio 2013 e superior vem com o Visual F # Tools. Detalhes de instalação disponíveis em Asp.net Tutorial . As ferramentas do Visual F # incluem o compilador de linha de comando (fsc.exe) e F # interativo (fsi.exe).
Usando essas ferramentas, você pode escrever todos os tipos de programas F #, desde aplicativos simples de linha de comando até aplicativos mais complexos. Você também pode escrever arquivos de código-fonte em F # usando um editor de texto básico, como o Bloco de notas, e compilar o código em assemblies usando o compilador de linha de comando.
Você pode baixá-lo do Microsoft Visual Studio. Ele é instalado automaticamente em sua máquina.
Escrever programas F # em links
Visite o site oficial do F # para obter as instruções mais recentes sobre como obter as ferramentas como um pacote Debian ou compilá-las diretamente da fonte - https://fsharp.org/use/linux/.
F # é uma linguagem de programação funcional.
Em F #, as funções funcionam como tipos de dados. Você pode declarar e usar uma função da mesma forma que qualquer outra variável.
Em geral, um aplicativo F # não possui nenhum ponto de entrada específico. O compilador executa todas as instruções de nível superior no arquivo de cima para baixo.
No entanto, para seguir o estilo de programação procedural, muitos aplicativos mantêm uma única instrução de nível superior que chama o loop principal.
O código a seguir mostra um programa F # simples -
open System
(* This is a multi-line comment *)
// This is a single-line comment
let sign num =
if num > 0 then "positive"
elif num < 0 then "negative"
else "zero"
let main() =
Console.WriteLine("sign 5: {0}", (sign 5))
main()
Quando você compila e executa o programa, ele produz a seguinte saída -
sign 5: positive
Observe que -
Um arquivo de código F # pode começar com vários open instruções que são usadas para importar namespaces.
O corpo dos arquivos inclui outras funções que implementam a lógica de negócios do aplicativo.
O loop principal contém as principais instruções executáveis.
Você viu a estrutura básica de um programa F #, portanto, será fácil entender outros blocos de construção básicos da linguagem de programação F #.
Tokens em F #
Um programa F # consiste em vários tokens. Um token pode ser uma palavra-chave, um identificador, uma constante, um literal de string ou um símbolo. Podemos categorizar os tokens F # em dois tipos -
- Keywords
- Símbolo e operadores
Palavras-chave F #
A tabela a seguir mostra as palavras-chave e breves descrições das palavras-chave. Discutiremos o uso dessas palavras-chave nos capítulos subsequentes.
Palavra-chave | Descrição |
---|---|
abstract | Indica um método que não possui implementação no tipo em que foi declarado ou que é virtual e possui uma implementação padrão. |
and | Usado em associações mutuamente recursivas, em declarações de propriedade e com várias restrições em parâmetros genéricos. |
as | Usado para dar ao objeto de classe atual um nome de objeto. Também usado para dar um nome a um padrão inteiro dentro de uma correspondência de padrão. |
assert | Usado para verificar o código durante a depuração. |
base | Usado como o nome do objeto da classe base. |
begin | Na sintaxe detalhada, indica o início de um bloco de código. |
class | Na sintaxe detalhada, indica o início de uma definição de classe. |
default | Indica uma implementação de um método abstrato; usado junto com uma declaração de método abstrato para criar um método virtual. |
delegate | Usado para declarar um delegado. |
do | Usado em construções de loop ou para executar código imperativo. |
done | Na sintaxe detalhada, indica o fim de um bloco de código em uma expressão de loop. |
downcast | Usado para converter para um tipo que é inferior na cadeia de herança. |
downto | Em um for expressão, usada na contagem reversa. |
elif | Usado em ramificação condicional. Uma forma abreviada de else if. |
else | Usado em ramificação condicional. |
end | Em definições de tipo e extensões de tipo, indica o fim de uma seção de definições de membro. Na sintaxe detalhada, usada para especificar o final de um bloco de código que começa com a palavra-chave begin. |
exception | Usado para declarar um tipo de exceção. |
extern | Indica que um elemento de programa declarado é definido em outro binário ou assembly. |
false | Usado como um literal booleano. |
finally | Usado junto com tente introduzir um bloco de código que é executado independentemente da ocorrência de uma exceção. |
for | Usado em construções de loop. |
fun | Usado em expressões lambda, também conhecidas como funções anônimas. |
function | Usado como uma alternativa mais curta para a palavra-chave fun e uma expressão de correspondência em uma expressão lambda que possui correspondência de padrão em um único argumento. |
global | Usado para fazer referência ao namespace .NET de nível superior. |
if | Usado em construções de ramificação condicional. |
in | Usado para expressões de sequência e, em sintaxe detalhada, para separar expressões de ligações. |
inherit | Usado para especificar uma classe base ou interface base. |
inline | Usado para indicar uma função que deve ser integrada diretamente no código do chamador. |
interface | Usado para declarar e implementar interfaces. |
internal | Usado para especificar que um membro é visível dentro de uma montagem, mas não fora dela. |
lazy | Usado para especificar um cálculo que deve ser executado apenas quando um resultado é necessário. |
let | Usado para associar ou vincular um nome a um valor ou função. |
let! | Usado em fluxos de trabalho assíncronos para vincular um nome ao resultado de uma computação assíncrona ou, em outras expressões de computação, usado para vincular um nome a um resultado, que é do tipo de computação. |
match | Usado para ramificar comparando um valor a um padrão. |
member | Usado para declarar uma propriedade ou método em um tipo de objeto. |
module | Usado para associar um nome a um grupo de tipos, valores e funções relacionados, para separá-lo logicamente de outro código. |
mutable | Usado para declarar uma variável, ou seja, um valor que pode ser alterado. |
namespace | Usado para associar um nome a um grupo de tipos e módulos relacionados, para separá-lo logicamente de outro código. |
new | Usado para declarar, definir ou invocar um construtor que cria ou pode criar um objeto. Também usado em restrições de parâmetro genérico para indicar que um tipo deve ter um determinado construtor. |
not | Na verdade, não é uma palavra-chave. No entanto, nenhuma estrutura em combinação é usada como uma restrição de parâmetro genérico. |
null | Indica a ausência de um objeto. Também usado em restrições de parâmetros genéricos. |
of | Usado em uniões discriminadas para indicar o tipo de categorias de valores e em declarações de delegado e exceção. |
open | Usado para disponibilizar o conteúdo de um namespace ou módulo sem qualificação. |
or | Usado com condições booleanas como um booleano ou operador. Equivalente a ||. Também usado em restrições de membros. |
override | Usado para implementar uma versão de um método abstrato ou virtual que difere da versão base. |
private | Restringe o acesso a um membro para codificar no mesmo tipo ou módulo. |
public | Permite acesso a um membro de fora do tipo. |
rec | Usado para indicar que uma função é recursiva. |
return | Usado para indicar um valor a ser fornecido como resultado de uma expressão de cálculo. |
return! | Usado para indicar uma expressão de cálculo que, quando avaliada, fornece o resultado da expressão de cálculo que contém. |
select | Usado em expressões de consulta para especificar quais campos ou colunas extrair. Observe que esta é uma palavra-chave contextual, o que significa que não é realmente uma palavra reservada e apenas atua como uma palavra-chave no contexto apropriado. |
static | Usado para indicar um método ou propriedade que pode ser chamada sem uma instância de um tipo, ou um membro de valor que é compartilhado entre todas as instâncias de um tipo. |
struct | Usado para declarar um tipo de estrutura. Também usado em restrições de parâmetros genéricos. Usado para compatibilidade OCaml em definições de módulo. |
then | Usado em expressões condicionais. Também usado para realizar efeitos colaterais após a construção do objeto. |
to | Usado em loops for para indicar um intervalo. |
true | Usado como um literal booleano. |
try | Usado para introduzir um bloco de código que pode gerar uma exceção. Usado em conjunto com com ou finalmente. |
type | Usado para declarar uma classe, registro, estrutura, união discriminada, tipo de enumeração, unidade de medida ou abreviação de tipo. |
upcast | Usado para converter para um tipo que é mais alto na cadeia de herança. |
use | Usado em vez de let para valores que requerem que Dispose seja chamado para liberar recursos. |
use! | Usado em vez de let! em fluxos de trabalho assíncronos e outras expressões de computação para valores que requerem Dispose para ser chamado para liberar recursos. |
val | Usado em uma assinatura para indicar um valor, ou em um tipo para declarar um membro, em situações limitadas. |
void | Indica o tipo de vazio do .NET. Usado ao interoperar com outras linguagens .NET. |
when | Usado para condições booleanas (quando guarda) em correspondências de padrão e para introduzir uma cláusula de restrição para um parâmetro de tipo genérico. |
while | Apresenta uma construção de loop. |
with | Usado junto com a palavra-chave match em expressões de correspondência de padrões. Também usado em expressões de objeto, expressões de cópia de registro e extensões de tipo para apresentar definições de membro e para introduzir manipuladores de exceção. |
yield | Usado em uma expressão de sequência para produzir um valor para uma sequência. |
yield! | Usado em uma expressão de computação para anexar o resultado de uma determinada expressão de computação a uma coleção de resultados para a expressão de computação contida. |
Algumas palavras-chave reservadas vêm da linguagem OCaml -
asr | terra | lor | lsl | lsr | lxor | mod | sig |
Algumas outras palavras-chave reservadas são mantidas para expansão futura do F #.
atômico | pausa | verificado | componente | const | restrição | 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
UMA tupleé uma coleção de valores separados por vírgulas. Eles são usados para criar estruturas de dados ad hoc, que agrupam valores relacionados.
Por exemplo, (“Zara Ali”, “Hyderabad”, 10) é um 3-tupla com dois valores de string e um valor int, tem o tipo (string * string * int).
As tuplas podem ser pares, triplos e assim por diante, do mesmo tipo ou de tipos diferentes.
Alguns exemplos são fornecidos aqui -
// 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)
Exemplo
Este programa tem uma função que pega uma tupla de quatro valores flutuantes e retorna a média -
let averageFour (a, b, c, d) =
let sum = a + b + c + d
sum / 4.0
let avg:float = averageFour (4.0, 5.1, 8.0, 12.0)
printfn "Avg of four numbers: %f" avg
Quando você compila e executa o programa, ele produz a seguinte saída -
Avg of four numbers: 7.275000
Acessando membros individuais da tupla
Os membros individuais de uma tupla podem ser avaliados e impressos usando correspondência de padrões.
O exemplo a seguir ilustra o conceito -
Exemplo
let display tuple1 =
match tuple1 with
| (a, b, c) -> printfn "Detail Info: %A %A %A" a b c
display ("Zara Ali", "Hyderabad", 10 )
Quando você compila e executa o programa, ele produz a seguinte saída -
Detail Info: "Zara Ali" "Hyderabad" 10
F # tem duas funções integradas, fst e snd, que retornam o primeiro e o segundo itens em uma tupla de 2.
O exemplo a seguir ilustra o conceito -
Exemplo
printfn "First member: %A" (fst(23, 30))
printfn "Second member: %A" (snd(23, 30))
printfn "First member: %A" (fst("Hello", "World!"))
printfn "Second member: %A" (snd("Hello", "World!"))
let nameTuple = ("Zara", "Ali")
printfn "First Name: %A" (fst nameTuple)
printfn "Second Name: %A" (snd nameTuple)
Quando você compila e executa o programa, ele produz a seguinte saída -
First member: 23
Second member: 30
First member: "Hello"
Second member: "World!"
First Name: "Zara"
Second Name: "Ali"
UMA recordé semelhante a uma tupla, porém contém campos nomeados. Por exemplo,
type website =
{ title : string;
url : string }
Definindo Registro
Um registro é definido como um tipo usando o type palavra-chave e os campos do registro são definidos como uma lista separada por ponto e vírgula.
A sintaxe para definir um registro é -
type recordName =
{ [ fieldName : dataType ] + }
Criação de um registro
Você pode criar um registro especificando os campos do registro. Por exemplo, vamos criar um registro de site chamado homepage -
let homepage = { Title = "TutorialsPoint"; Url = "www.tutorialspoint.com" }
Os exemplos a seguir irão explicar os conceitos -
Exemplo 1
Este programa define um tipo de registro denominado website. Em seguida, ele cria alguns registros do tipo site e imprime os registros.
(* defining a record type named website *)
type website =
{ Title : string;
Url : string }
(* creating some records *)
let homepage = { Title = "TutorialsPoint"; Url = "www.tutorialspoint.com" }
let cpage = { Title = "Learn C"; Url = "www.tutorialspoint.com/cprogramming/index.htm" }
let fsharppage = { Title = "Learn F#"; Url = "www.tutorialspoint.com/fsharp/index.htm" }
let csharppage = { Title = "Learn C#"; Url = "www.tutorialspoint.com/csharp/index.htm" }
(*printing records *)
(printfn "Home Page: Title: %A \n \t URL: %A") homepage.Title homepage.Url
(printfn "C Page: Title: %A \n \t URL: %A") cpage.Title cpage.Url
(printfn "F# Page: Title: %A \n \t URL: %A") fsharppage.Title fsharppage.Url
(printfn "C# Page: Title: %A \n \t URL: %A") csharppage.Title csharppage.Url
Quando você compila e executa o programa, ele produz a seguinte saída -
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"
Exemplo 2
type student =
{ Name : string;
ID : int;
RegistrationText : string;
IsRegistered : bool }
let getStudent name id =
{ Name = name; ID = id; RegistrationText = null; IsRegistered = false }
let registerStudent st =
{ st with
RegistrationText = "Registered";
IsRegistered = true }
let printStudent msg st =
printfn "%s: %A" msg st
let main() =
let preRegisteredStudent = getStudent "Zara" 10
let postRegisteredStudent = registerStudent preRegisteredStudent
printStudent "Before Registration: " preRegisteredStudent
printStudent "After Registration: " postRegisteredStudent
main()
Quando você compila e executa o programa, ele produz a seguinte saída -
Before Registration: : {Name = "Zara";
ID = 10;
RegistrationText = null;
IsRegistered = false;}
After Registration: : {Name = "Zara";
ID = 10;
RegistrationText = "Registered";
IsRegistered = true;}
Em F #, uma lista é uma série ordenada e imutável de elementos do mesmo tipo. Em certa medida, é equivalente a uma estrutura de dados de lista vinculada.
O módulo F #, Microsoft.FSharp.Collections.List,tem as operações comuns em listas. No entanto, o F # importa este módulo automaticamente e o torna acessível a todos os aplicativos F #.
Criação e inicialização de uma lista
A seguir estão as várias maneiras de criar listas -
Lista de uso literals.
Usando cons (: :) operador.
Usando o List.init método do módulo List.
Usando alguns syntactic constructs chamado List Comprehensions.
Listar literais
Nesse método, você apenas especifica uma sequência de valores delimitada por ponto-e-vírgula entre colchetes. Por exemplo -
let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
Os contras (: :) Operador
Com este método, você pode adicionar alguns valores prefixando ou cons-ingpara uma lista existente usando o operador ::. Por exemplo -
let list2 = 1::2::3::4::5::6::7::8::9::10::[];;
[] denota uma lista vazia.
Método de inicialização de lista
O método List.init do módulo List é freqüentemente usado para criar listas. Este método tem o tipo -
val init : int -> (int -> 'T) -> 'T list
O primeiro argumento é o comprimento desejado da nova lista e o segundo argumento é uma função inicializadora, que gera itens na lista.
Por exemplo,
let list5 = List.init 5 (fun index -> (index, index * index, index * index * index))
Aqui, a função de índice gera a lista.
Compreensões de lista
Compreensões de lista são construções sintáticas especiais usadas para gerar listas.
A sintaxe de compreensão de lista F # vem em duas formas - intervalos e geradores.
Os intervalos têm as construções - [início .. fim] e [início .. etapa .. fim]
Por exemplo,
let list3 = [1 .. 10]
Geradores têm a construção - [para x na coleção do ... rendimento expr]
Por exemplo,
let list6 = [ for a in 1 .. 10 do yield (a * a) ]
Enquanto o yield palavra-chave coloca um único valor em uma lista, a palavra-chave, yield!, coloca uma coleção de valores na lista.
A função a seguir demonstra os métodos acima -
Exemplo
(* using list literals *)
let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
printfn "The list: %A" list1
(*using cons operator *)
let list2 = 1 :: 2 :: 3 :: []
printfn "The list: %A" list2
(* using range constructs*)
let list3 = [1 .. 10]
printfn "The list: %A" list3
(* using range constructs *)
let list4 = ['a' .. 'm']
printfn "The list: %A" list4
(* using init method *)
let list5 = List.init 5 (fun index -> (index, index * index, index * index * index))
printfn "The list: %A" list5
(* using yield operator *)
let list6 = [ for a in 1 .. 10 do yield (a * a) ]
printfn "The list: %A" list6
(* using yield operator *)
let list7 = [ for a in 1 .. 100 do if a % 3 = 0 && a % 5 = 0 then yield a]
printfn "The list: %A" list7
(* using yield! operator *)
let list8 = [for a in 1 .. 3 do yield! [ a .. a + 3 ] ]
printfn "The list: %A" list8
Quando você compila e executa o programa, ele produz a seguinte saída -
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]
Propriedades do tipo de dados da lista
A tabela a seguir mostra várias propriedades do tipo de dados da lista -
Propriedade | Tipo | Descrição |
---|---|---|
Cabeça | 'T | O primeiro elemento. |
Vazio | 'T list | Uma propriedade estática que retorna uma lista vazia do tipo apropriado. |
Está vazia | bool | true se a lista não tiver elementos. |
Item | 'T | O elemento no índice especificado (baseado em zero). |
comprimento | int | O número de elementos. |
Rabo | 'T list | A lista sem o primeiro elemento. |
O exemplo a seguir mostra o uso dessas propriedades -
Exemplo
let list1 = [ 2; 4; 6; 8; 10; 12; 14; 16 ]
// Use of Properties
printfn "list1.IsEmpty is %b" (list1.IsEmpty)
printfn "list1.Length is %d" (list1.Length)
printfn "list1.Head is %d" (list1.Head)
printfn "list1.Tail.Head is %d" (list1.Tail.Head)
printfn "list1.Tail.Tail.Head is %d" (list1.Tail.Tail.Head)
printfn "list1.Item(1) is %d" (list1.Item(1))
Quando você compila e executa o programa, ele produz a seguinte saída -
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
Operadores básicos na lista
A tabela a seguir mostra as operações básicas no tipo de dados de lista -
Valor | Descrição |
---|---|
acrescentar: 'Lista T →' Lista T → 'Lista T | Retorna uma nova lista que contém os elementos da primeira lista seguidos pelos elementos da segunda. |
média: 'Lista T → ^ T | Retorna a média dos elementos da lista. |
AverageBy: ('T → ^ U) →' Lista T → ^ U | Retorna a média dos elementos gerados pela aplicação da função a cada elemento da lista. |
escolha: ('T →' opção U) → 'Lista T →' Lista U | Aplica a função fornecida a cada elemento da lista. Retorna a lista composta dos resultados de cada elemento onde a função retornaSome. |
coletar: ('T →' lista U) → 'lista T →' lista U | Para cada elemento da lista, aplica-se a função fornecida. Concatena todos os resultados e retorna a lista combinada. |
concat: seq <'lista T> →' lista T | Retorna uma nova lista que contém os elementos de cada uma das listas em ordem. |
vazio: 'T list | Retorna uma lista vazia do tipo fornecido. |
existe: ('T → bool) →' lista T → bool | Testa se algum elemento da lista satisfaz o predicado fornecido. |
existe2: ('T1 →' T2 → bool) → 'lista T1 →' lista T2 → bool | Testa se algum par de elementos correspondentes das listas satisfaz o predicado fornecido. |
filtro: ('T → bool) →' Lista T → 'Lista T | Retorna uma nova coleção contendo apenas os elementos da coleção para os quais o predicado dado retorna true. |
localizar: ('T → bool) →' Lista T → 'T | Retorna o primeiro elemento para o qual a função dada retorna true. |
findIndex: ('T → bool) →' lista T → int | Retorna o índice do primeiro elemento da lista que satisfaz o predicado fornecido. |
dobrar: ('Estado →' T → 'Estado) →' Estado → 'Lista T →' Estado | Aplica uma função a cada elemento da coleção, encadeando um argumento do acumulador por meio do cálculo. Esta função recebe o segundo argumento e aplica a função a ele e ao primeiro elemento da lista. Em seguida, ele passa esse resultado para a função junto com o segundo elemento e assim por diante. Finalmente, ele retorna o resultado final. Se a função de entrada for fe os elementos forem i0 ... iN, então esta função calcula f (... (fs i0) i1 ...) iN. |
fold2: ('Estado →' T1 → 'T2 →' Estado) → 'Estado →' lista T1 → 'lista T2 →' Estado | Aplica uma função aos elementos correspondentes de duas coleções, encadeando um argumento do acumulador por meio da computação. As coleções devem ter tamanhos idênticos. Se a função de entrada for fe os elementos forem i0 ... iN e j0 ... jN, então esta função calcula f (... (fs i0 j0) ...) iN jN. |
foldBack: ('T →' Estado → 'Estado) →' Lista T → 'Estado →' Estado | Aplica uma função a cada elemento da coleção, encadeando um argumento do acumulador por meio do cálculo. Se a função de entrada isf e os elementos forem i0 ... iN, então calcula f i0 (... (f iN s)). |
foldBack2: ('T1 →' T2 → 'Estado →' Estado) → 'lista T1 →' lista T2 → 'Estado →' Estado | Aplica uma função aos elementos correspondentes de duas coleções, encadeando um argumento do acumulador por meio da computação. As coleções devem ter tamanhos idênticos. Se a função de entrada for fe os elementos forem i0 ... iN e j0 ... jN, então esta função calcula f i0 j0 (... (f iN jN s)). |
forall: ('T → bool) →' lista T → bool | Testa se todos os elementos da coleção satisfazem o predicado fornecido. |
forall2: ('T1 →' T2 → bool) → 'lista T1 →' lista T2 → bool | Testa se todos os elementos correspondentes da coleção satisfazem o predicado fornecido em pares. |
head: 'T list →' T | Retorna o primeiro elemento da lista. |
init: int → (int → 'T) →' lista T | Cria uma lista chamando o gerador fornecido em cada índice. |
isEmpty: 'T list → bool | Devoluções true se a lista não contém elementos, false de outra forma. |
iter: ('T → unidade) →' Lista T → unidade | Aplica a função fornecida a cada elemento da coleção. |
iter2: ('T1 →' T2 → unidade) → 'lista T1 →' lista T2 → unidade | Aplica a função fornecida a duas coleções simultaneamente. As coleções devem ter tamanhos idênticos. |
iteri: (int → 'T → unidade) →' Lista T → unidade | Aplica a função fornecida a cada elemento da coleção. O inteiro passado para a função indica o índice do elemento. |
iteri2: (int → 'T1 →' T2 → unidade) → 'lista T1 →' lista T2 → unidade | Aplica a função fornecida a duas coleções simultaneamente. As coleções devem ter tamanhos idênticos. O inteiro passado para a função indica o índice do elemento. |
comprimento: 'T lista → int | Retorna o comprimento da lista. |
mapa: ('T →' U) → 'Lista T →' Lista U | Cria uma nova coleção cujos elementos são os resultados da aplicação da função dada a cada um dos elementos da coleção. |
map2: ('T1 →' T2 → 'U) →' lista T1 → 'lista T2 →' lista U | Cria uma nova coleção cujos elementos são os resultados da aplicação da função dada aos elementos correspondentes das duas coleções aos pares. |
map3: ('T1 →' T2 → 'T3 →' U) → 'lista T1 →' lista T2 → 'lista T3 →' lista U | Cria uma nova coleção cujos elementos são os resultados da aplicação da função dada aos elementos correspondentes das três coleções simultaneamente. |
mapi: (int → 'T →' U) → 'lista T →' lista U | Cria uma nova coleção cujos elementos são os resultados da aplicação da função dada a cada um dos elementos da coleção. O índice inteiro passado para a função indica o índice (de 0) do elemento sendo transformado. |
mapi2: (int → 'T1 →' T2 → 'U) →' lista T1 → 'lista T2 →' lista U | Como List.mapi, mas mapeando os elementos correspondentes de duas listas de comprimento igual. |
máx: 'Lista T →' T | Retorna o maior de todos os elementos da lista, comparado usando Operators.max. |
maxBy: ('T →' U) → 'Lista T →' T | Retorna o maior de todos os elementos da lista, comparado usando Operators.max no resultado da função. |
min: 'Lista T →' T | Retorna o mais baixo de todos os elementos da lista, comparado usando Operators.min. |
minBy: ('T →' U) → 'Lista T →' T | Retorna o mais baixo de todos os elementos da lista, comparado usando Operators.min no resultado da função |
enésimo: 'T lista → int →' T | Índices na lista. O primeiro elemento possui índice 0. |
ofArray: 'T [] →' Lista T | Cria uma lista a partir da matriz fornecida. |
ofSeq: seq <'T> →' lista T | Cria uma nova lista a partir do objeto enumerável fornecido. |
partição: ('T → bool) →' lista T * 'lista T | Divide a coleção em duas coleções, contendo os elementos para os quais o predicado dado retorna true e false respectivamente. |
permutar: (int → int) → 'Lista T →' Lista T | Retorna uma lista com todos os elementos permutados de acordo com a permutação especificada. |
escolha: ('T →' opção U) → 'Lista T →' U | Aplica a função fornecida a elementos sucessivos, retornando o primeiro resultado onde a função retorna Some por algum valor. |
reduzir: ('T →' T → 'T) →' Lista T → 'T | Aplica uma função a cada elemento da coleção, encadeando um argumento do acumulador por meio do cálculo. Esta função aplica a função especificada aos dois primeiros elementos da lista. Em seguida, ele passa esse resultado para a função junto com o terceiro elemento e assim por diante. Finalmente, ele retorna o resultado final. Se a função de entrada for fe os elementos forem i0 ... iN, então esta função calcula f (... (f i0 i1) i2 ...) iN. |
reduzirBack: ('T →' T → 'T) →' Lista T → 'T | Aplica uma função a cada elemento da coleção, encadeando um argumento do acumulador por meio do cálculo. Se a função de entrada isf e os elementos forem i0 ... iN, essa função calcula f i0 (... (f iN-1 iN)). |
replicar: (int → 'T →' lista T) | Cria uma lista chamando o gerador fornecido em cada índice. |
rev: 'Lista T →' Lista T | Retorna uma nova lista com os elementos em ordem reversa. |
varredura: ('Estado →' T → 'Estado) →' Estado → 'Lista T →' Lista de estados | Aplica uma função a cada elemento da coleção, encadeando um argumento do acumulador por meio do cálculo. Esta função recebe o segundo argumento e aplica a função especificada a ele e ao primeiro elemento da lista. Em seguida, ele passa esse resultado para a função junto com o segundo elemento e assim por diante. Finalmente, ele retorna a lista de resultados intermediários e o resultado final. |
scanBack: ('T →' Estado → 'Estado) →' Lista T → 'Estado →' Lista de estados | Semelhante a foldBack, mas retorna os resultados intermediários e finais |
classificar: 'Lista T →' Lista T | Classifica a lista fornecida usando Operators.compare. |
sortBy: ('T →' Tecla) → 'Lista T →' Lista T | Classifica a lista fornecida usando as chaves fornecidas pela projeção fornecida. As chaves são comparadas usando Operators.compare. |
sortWith: ('T →' T → int) → 'Lista T →' Lista T | Classifica a lista fornecida usando a função de comparação fornecida. |
soma: ^ T lista → ^ T | Retorna a soma dos elementos da lista. |
sumBy: ('T → ^ U) →' Lista T → ^ U | Retorna a soma dos resultados gerados pela aplicação da função a cada elemento da lista. |
cauda: 'lista T →' lista T | Retorna a lista de entrada sem o primeiro elemento. |
toArray: 'Lista T →' T [] | Cria uma matriz da lista fornecida. |
toSeq: 'Lista T → seq <' T> | Vê a lista fornecida como uma sequência. |
tryFind: ('T → bool) →' Lista T → 'opção T | Retorna o primeiro elemento para o qual a função dada retorna true. RetornaNone se tal elemento não existir. |
tryFindIndex: ('T → bool) →' Lista T → opção int | Retorna o índice do primeiro elemento da lista que satisfaz o predicado fornecido. RetornaNone se tal elemento não existir. |
tryPick: ('T →' opção U) → 'Lista T →' opção U | Aplica a função fornecida a elementos sucessivos, retornando o primeiro resultado onde a função retorna Somepor algum valor. Se tal elemento não existir, retorneNone. |
descompacte: ('T1 *' T2) lista → 'lista T1 *' lista T2 | Divide uma lista de pares em duas listas. |
unzip3: ('T1 *' T2 * 'T3) lista →' lista T1 * 'lista T2 *' lista T3 | Divide uma lista de triplos em três listas. |
CEP: 'Lista T1 →' Lista T2 → lista ('T1 *' T2) | Combina as duas listas em uma lista de pares. As duas listas devem ter comprimentos iguais. |
zip3: 'lista T1 →' lista T2 → 'lista T3 → lista (' T1 * 'T2 *' T3) | Combina as três listas em uma lista de triplos. As listas devem ter comprimentos iguais. |
Os exemplos a seguir demonstram os usos das funcionalidades acima -
Exemplo 1
Este programa mostra a reversão de uma lista recursivamente -
let list1 = [ 2; 4; 6; 8; 10; 12; 14; 16 ]
printfn "The original list: %A" list1
let reverse lt =
let rec loop acc = function
| [] -> acc
| hd :: tl -> loop (hd :: acc) tl
loop [] lt
printfn "The reversed list: %A" (reverse list1)
Quando você compila e executa o programa, ele produz a seguinte saída -
The original list: [2; 4; 6; 8; 10; 12; 14; 16]
The reversed list: [16; 14; 12; 10; 8; 6; 4; 2]
No entanto, você pode usar o rev função do módulo para o mesmo propósito -
let list1 = [ 2; 4; 6; 8; 10; 12; 14; 16 ]
printfn "The original list: %A" list1
printfn "The reversed list: %A" (List.rev list1)
Quando você compila e executa o programa, ele produz a seguinte saída -
The original list: [2; 4; 6; 8; 10; 12; 14; 16]
The reversed list: [16; 14; 12; 10; 8; 6; 4; 2]
Exemplo 2
Este programa mostra a filtragem de uma lista usando o List.filter método -
let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
printfn "The list: %A" list1
let list2 = list1 |> List.filter (fun x -> x % 2 = 0);;
printfn "The Filtered list: %A" list2
Quando você compila e executa o programa, ele produz a seguinte saída -
The list: [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
The Filtered list: [2; 4; 6; 8; 10]
Exemplo 3
o List.map método mapeia uma lista de um tipo para outro -
let list1 = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
printfn "The list: %A" list1
let list2 = list1 |> List.map (fun x -> (x * x).ToString());;
printfn "The Mapped list: %A" list2
Quando você compila e executa o programa, ele produz a seguinte saída -
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"]
Exemplo 4
o List.append método e o operador @ anexa uma lista a outra -
let list1 = [1; 2; 3; 4; 5 ]
let list2 = [6; 7; 8; 9; 10]
let list3 = List.append list1 list2
printfn "The first list: %A" list1
printfn "The second list: %A" list2
printfn "The appened list: %A" list3
let lt1 = ['a'; 'b';'c' ]
let lt2 = ['e'; 'f';'g' ]
let lt3 = lt1 @ lt2
printfn "The first list: %A" lt1
printfn "The second list: %A" lt2
printfn "The appened list: %A" lt3
Quando você compila e executa o programa, ele produz a seguinte saída -
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']
Exemplo 5
o List.sortmétodo classifica uma lista. oList.sum método fornece a soma dos elementos da lista e o List.average método fornece a média dos elementos na lista -
let list1 = [9.0; 0.0; 2.0; -4.5; 11.2; 8.0; -10.0]
printfn "The list: %A" list1
let list2 = List.sort list1
printfn "The sorted list: %A" list2
let s = List.sum list1
let avg = List.average list1
printfn "The sum: %f" s
printfn "The average: %f" avg
Quando você compila e executa o programa, ele produz a seguinte saída -
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
Uma operação "dobrar" aplica uma função a cada elemento em uma lista, agrega o resultado da função em uma variável de acumulador e retorna o acumulador como o resultado da operação dobrar.
Exemplo 6
o List.fold método aplica uma função a cada elemento da esquerda para a direita, enquanto List.foldBack aplica uma função a cada elemento da direita para a esquerda.
let sumList list = List.fold (fun acc elem -> acc + elem) 0 list
printfn "Sum of the elements of list %A is %d." [ 1 .. 10 ] (sumList [ 1 .. 10 ])
Quando você compila e executa o programa, ele produz a seguinte saída -
Sum of the elements of list [1; 2; 3; 4; 5; 6; 7; 8; 9; 10] is 55.
As sequências, assim como as listas, também representam uma coleção ordenada de valores. No entanto, os elementos em uma sequência ou expressão de sequência são calculados quando necessário. Eles não são calculados de uma só vez e, por essa razão, são usados para representar infinitas estruturas de dados.
Definindo Sequências
As sequências são definidas usando a seguinte sintaxe -
seq { expr }
Por exemplo,
let seq1 = seq { 1 .. 10 }
Criação de sequências e expressões de sequências
Semelhante às listas, você pode criar sequências usando intervalos e compreensões.
Expressões de sequência são as expressões que você pode escrever para criar sequências. Isso pode ser feito -
- Especificando o intervalo.
- Especificando o intervalo com incremento ou decremento.
- Usando o yield palavra-chave para produzir valores que se tornam parte da sequência.
- Usando o operador →.
Os exemplos a seguir demonstram o conceito -
Exemplo 1
(* Sequences *)
let seq1 = seq { 1 .. 10 }
(* ascending order and increment*)
printfn "The Sequence: %A" seq1
let seq2 = seq { 1 .. 5 .. 50 }
(* descending order and decrement*)
printfn "The Sequence: %A" seq2
let seq3 = seq {50 .. -5 .. 0}
printfn "The Sequence: %A" seq3
(* using yield *)
let seq4 = seq { for a in 1 .. 10 do yield a, a*a, a*a*a }
printfn "The Sequence: %A" seq4
Quando você compila e executa o programa, ele produz a seguinte saída -
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); ...]
Exemplo 2
O programa a seguir imprime os números primos de 1 a 50 -
(* Recursive isprime function. *)
let isprime n =
let rec check i =
i > n/2 || (n % i <> 0 && check (i + 1))
check 2
let primeIn50 = seq { for n in 1..50 do if isprime n then yield n }
for x in primeIn50 do
printfn "%d" x
Quando você compila e executa o programa, ele produz a seguinte saída -
1
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
Operações básicas na sequência
A tabela a seguir mostra as operações básicas no tipo de dados de sequência -
Valor | Descrição |
---|---|
anexar: seq <'T> → seq <' T> → seq <'T> | Envolve as duas enumerações fornecidas como uma única enumeração concatenada. |
média: seq <^ T> → ^ T | Retorna a média dos elementos na sequência. |
averageBy: ('T → ^ U) → seq <' T> → ^ U | Retorna a média dos resultados gerados pela aplicação da função a cada elemento da sequência. |
cache: seq <'T> → seq <' T> | Retorna uma sequência que corresponde a uma versão em cache da sequência de entrada. |
elenco: IEnumerable → seq <'T> | Envolve um sistema vagamente tipado. Sequência de coleções como uma sequência digitada. |
escolha: ('T →' opção U) → seq <'T> → seq <' U> | Aplica a função fornecida a cada elemento da lista. Retorna a lista composta dos resultados de cada elemento onde a função retornaSome. |
coletar: ('T →' Coleção) → seq <'T> → seq <' U> | Aplica a função fornecida a cada elemento da sequência e concatena todos os resultados. |
compareWith: ('T →' T → int) → seq <'T> → seq <' T> → int | Compara duas sequências usando a função de comparação fornecida, elemento por elemento. |
concat: seq <'Coleção> → seq <' T> | Combina a enumeração de enumerações fornecida como uma única enumeração concatenada. |
countBy: ('T →' Key) → seq <'T> → seq <' Key * int> | Aplica uma função de geração de chave a cada elemento de uma sequência e retorna uma sequência que produz chaves exclusivas e seu número de ocorrências na sequência original. |
atraso: (unidade → seq <'T>) → seq <' T> | Retorna uma sequência que é construída a partir da especificação atrasada fornecida de uma sequência. |
distinto: seq <'T> → seq <' T> | Retorna uma seqüência que não contém entradas duplicadas de acordo com hash genérico e comparações de igualdade nas entradas. Se um elemento ocorrer várias vezes na sequência, as ocorrências posteriores serão descartadas. |
DistintBy: ('T →' Chave) → seq <'T> → seq <' T> | Retorna uma seqüência que não contém entradas duplicadas de acordo com o hash genérico e comparações de igualdade nas chaves retornadas pela função de geração de chave fornecida. Se um elemento ocorrer várias vezes na sequência, as ocorrências posteriores serão descartadas. |
vazio: seq <'T> | Cria uma sequência vazia. |
exatamente Um: seq <'T> →' T | Retorna o único elemento da sequência. |
existe: ('T → bool) → seq <' T> → bool | Testa se algum elemento da sequência satisfaz o predicado fornecido. |
existe2: ('T1 →' T2 → bool) → seq <'T1> → seq <' T2> → bool | Testa se algum par de elementos correspondentes das sequências de entrada satisfaz o predicado fornecido. |
filtro: ('T → bool) → seq <' T> → seq <'T> | Retorna uma nova coleção contendo apenas os elementos da coleção para os quais o predicado dado retorna true. |
encontrar: ('T → bool) → seq <' T> → 'T | Retorna o primeiro elemento para o qual a função dada retorna true. |
findIndex: ('T → bool) → seq <' T> → int | Retorna o índice do primeiro elemento para o qual a função dada retorna true. |
dobrar: ('Estado →' T → 'Estado) →' Estado → seq <'T> →' Estado | Aplica uma função a cada elemento da coleção, encadeando um argumento do acumulador por meio do cálculo. Se a função de entrada for fe os elementos forem i0 ... iN, então esta função calcula f (... (fs i0) ...) iN. |
forall: ('T → bool) → seq <' T> → bool | Testa se todos os elementos da sequência satisfazem o predicado fornecido. |
forall2: ('T1 →' T2 → bool) → seq <'T1> → seq <' T2> → bool | Testa que todos os pares de elementos extraídos das duas sequências satisfazem o predicado fornecido. Se uma sequência for mais curta do que a outra, os elementos restantes da sequência mais longa serão ignorados. |
groupBy: ('T →' Tecla) → seq <'T> → seq <' Tecla * seq <'T >> | Aplica uma função de geração de chave a cada elemento de uma sequência e produz uma sequência de chaves exclusivas. Cada chave exclusiva também contém uma sequência de todos os elementos que correspondem a essa chave. |
cabeça: seq <'T> →' T | Retorna o primeiro elemento da sequência. |
init: int → (int → 'T) → seq <' T> | Gera uma nova sequência que, quando iterada, retorna elementos sucessivos chamando a função dada, até a contagem fornecida. Os resultados da chamada da função não são salvos, ou seja, a função é reaplicada conforme necessário para regenerar os elementos. A função recebe o índice do item que está sendo gerado. |
initInfinito: (int → 'T) → seq <' T> | Gera uma nova sequência que, quando iterada, retornará elementos sucessivos chamando a função dada. Os resultados da chamada da função não são salvos, ou seja, a função será reaplicada conforme necessário para regenerar os elementos. A função recebe o índice do item que está sendo gerado. |
isEmpty: seq <'T> → bool | Testa se uma sequência possui algum elemento. |
iter: ('T → unidade) → seq <' T> → unidade | Aplica a função fornecida a cada elemento da coleção. |
iter2: ('T1 →' T2 → unidade) → seq <'T1> → seq <' T2> → unidade | Aplica a função fornecida a duas coleções simultaneamente. Se uma sequência for mais curta do que a outra, os elementos restantes da sequência mais longa serão ignorados. |
iteri: (int → 'T → unidade) → seq <' T> → unidade | Aplica a função fornecida a cada elemento da coleção. O inteiro passado para a função indica o índice do elemento. |
último: seq <'T> →' T | Retorna o último elemento da sequência. |
comprimento: seq <'T> → int | Retorna o comprimento da sequência. |
mapa: ('T →' U) → seq <'T> → seq <' U> | Cria uma nova coleção cujos elementos são os resultados da aplicação da função dada a cada um dos elementos da coleção. A função fornecida será aplicada conforme os elementos são exigidos usando o método MoveNext em enumeradores recuperados do objeto. |
mapa2: ('T1 →' T2 → 'U) → seq <' T1> → seq <'T2> → seq <' U> | Cria uma nova coleção cujos elementos são os resultados da aplicação da função dada aos pares de elementos correspondentes das duas sequências. Se uma sequência de entrada for mais curta do que a outra, os elementos restantes da sequência mais longa serão ignorados. |
mapi: (int → 'T →' U) → seq <'T> → seq <' U> | Cria uma nova coleção cujos elementos são os resultados da aplicação da função dada a cada um dos elementos da coleção. O índice inteiro passado para a função indica o índice (de 0) do elemento sendo transformado. |
máx: seq <'T> →' T | Retorna o maior de todos os elementos da sequência, comparado usando Operators.max. |
maxBy: ('T →' U) → seq <'T> →' T | Retorna o maior de todos os elementos da sequência, comparado usando Operators.max no resultado da função. |
min: seq <'T> →' T | Retorna o mais baixo de todos os elementos da sequência, comparado usando Operators.min. |
minBy: ('T →' U) → seq <'T> →' T | Retorna o mais baixo de todos os elementos da sequência, comparado usando Operators.min no resultado da função. |
enésimo: int → seq <'T> →' T | Calcula o enésimo elemento da coleção. |
ofArray: 'T array → seq <' T> | Vê o array fornecido como uma sequência. |
ofList: 'T lista → seq <' T> | Vê a lista fornecida como uma sequência. |
em pares: seq <'T> → seq <' T * 'T> | Retorna uma sequência de cada elemento na sequência de entrada e seu predecessor, com exceção do primeiro elemento, que é retornado apenas como o predecessor do segundo elemento. |
escolha: ('T →' opção U) → seq <'T> →' U | Aplica a função fornecida a elementos sucessivos, retornando o primeiro valor onde a função retorna um Some valor. |
somente leitura: seq <'T> → seq <' T> | Cria um novo objeto de sequência que delega para o objeto de sequência fornecido. Isso garante que a sequência original não possa ser redescoberta e transformada por uma conversão de tipo. Por exemplo, se for fornecida uma matriz, a sequência retornada retornará os elementos da matriz, mas você não pode converter o objeto de sequência retornado em uma matriz. |
reduzir: ('T →' T → 'T) → seq <' T> → 'T | Aplica uma função a cada elemento da sequência, encadeando um argumento do acumulador por meio do cálculo. Comece aplicando a função aos dois primeiros elementos. Em seguida, insira esse resultado na função junto com o terceiro elemento e assim por diante. Retorne o resultado final. |
varredura: ('Estado →' T → 'Estado) →' Estado → seq <'T> → seq <' Estado> | Como Seq.fold, mas calcula sob demanda e retorna a sequência de resultados intermediários e finais. |
singleton: 'T → seq <' T> | Retorna uma sequência que produz apenas um item. |
pular: int → seq <'T> → seq <' T> | Retorna uma sequência que ignora um número especificado de elementos da sequência subjacente e, em seguida, produz os elementos restantes da sequência. |
skipWhile: ('T → bool) → seq <' T> → seq <'T> | Retorna uma sequência que, quando iterada, pula elementos da sequência subjacente enquanto o predicado fornecido retorna true, e então produz os elementos restantes da sequência. |
classificar: seq <'T> → seq <' T> | Rende uma sequência ordenada por chaves. |
sortBy: ('T →' Tecla) → seq <'T> → seq <' T> | Aplica uma função de geração de chave a cada elemento de uma sequência e produz uma sequência ordenada por chaves. As chaves são comparadas usando comparação genérica implementada por Operators.compare. |
soma: seq <^ T> → ^ T | Retorna a soma dos elementos na sequência. |
sumBy | Retorna a soma dos resultados gerados pela aplicação da função a cada elemento da sequência. |
pegar: int → seq <'T> → seq <' T> | Retorna os primeiros elementos da sequência até uma contagem especificada. |
takeWhile: ('T → bool) → seq <' T> → seq <'T> | Retorna uma sequência que, quando iterada, produz elementos da sequência subjacente enquanto o predicado fornecido retorna true, e não retorna nenhum elemento adicional. |
toArray: seq <'T> →' T [] | Cria uma matriz da coleção fornecida. |
toList: seq <'T> →' T list | Cria uma lista da coleção fornecida. |
truncar: int → seq <'T> → seq <' T> | Retorna uma sequência que, quando enumerada, não retorna mais do que um número especificado de elementos. |
tryFind: ('T → bool) → seq <' T> → 'opção T | Retorna o primeiro elemento para o qual a função dada retorna true, ou None se tal elemento não existir. |
tryFindIndex: ('T → bool) → seq <' T> → opção int | Retorna o índice do primeiro elemento na sequência que satisfaz o predicado fornecido, ou None se tal elemento não existir. |
tryPick: ('T →' opção U) → seq <'T> →' opção U | Aplica a função fornecida a elementos sucessivos, retornando o primeiro valor onde a função retorna um Some valor. |
desdobrar: (opção 'Estado →' T * 'Estado) →' Estado → seq <'T> | Retorna uma sequência que contém os elementos gerados pelo cálculo fornecido. |
onde: ('T → bool) → seq <' T> → seq <'T> | Retorna uma nova coleção contendo apenas os elementos da coleção para os quais o predicado dado retorna true. Um sinônimo para Seq.filter. |
em janela: int → seq <'T> → seq <' T []> | Retorna uma sequência que produz janelas deslizantes contendo elementos retirados da sequência de entrada. Cada janela é retornada como uma nova matriz. |
zip: seq <'T1> → seq <' T2> → seq <'T1 *' T2> | Combina as duas sequências em uma lista de pares. As duas sequências não precisam ter comprimentos iguais - quando uma sequência se esgota, todos os elementos restantes na outra sequência são ignorados. |
zip3: seq <'T1> → seq <' T2> → seq <'T3> → seq <' T1 * 'T2 *' T3> | Combina as três sequências em uma lista de triplas. As sequências não precisam ter comprimentos iguais - quando uma sequência se esgota, todos os elementos restantes nas outras sequências são ignorados. |
Os exemplos a seguir demonstram o uso de algumas das funcionalidades acima -
Exemplo 1
Este programa cria uma sequência vazia e a preenche mais tarde -
(* Creating sequences *)
let emptySeq = Seq.empty
let seq1 = Seq.singleton 20
printfn"The singleton sequence:"
printfn "%A " seq1
printfn"The init sequence:"
let seq2 = Seq.init 5 (fun n -> n * 3)
Seq.iter (fun i -> printf "%d " i) seq2
printfn""
(* converting an array to sequence by using cast *)
printfn"The array sequence 1:"
let seq3 = [| 1 .. 10 |] :> seq<int>
Seq.iter (fun i -> printf "%d " i) seq3
printfn""
(* converting an array to sequence by using Seq.ofArray *)
printfn"The array sequence 2:"
let seq4 = [| 2..2.. 20 |] |> Seq.ofArray
Seq.iter (fun i -> printf "%d " i) seq4
printfn""
Quando você compila e executa o programa, ele produz a seguinte saída -
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
Observe que -
O método Seq.empty cria uma sequência vazia.
O método Seq.singleton cria uma sequência de apenas um elemento especificado.
O método Seq.init cria uma sequência para a qual os elementos são criados usando uma determinada função.
Os métodos Seq.ofArray e Seq.ofList <'T> criam sequências de arrays e listas.
O método Seq.iter permite a iteração por meio de uma sequência.
Exemplo 2
O método Seq.unfold gera uma sequência de uma função de computação que pega um estado e o transforma para produzir cada elemento subsequente na sequência.
A função a seguir produz os primeiros 20 números naturais -
let seq1 = Seq.unfold (fun state -> if (state > 20) then None else Some(state, state + 1)) 0
printfn "The sequence seq1 contains numbers from 0 to 20."
for x in seq1 do printf "%d " x
printfn" "
Quando você compila e executa o programa, ele produz a seguinte saída -
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
Exemplo 3
O método Seq.truncate cria uma sequência de outra sequência, mas limita a sequência a um número especificado de elementos.
O método Seq.take cria uma nova sequência que contém um número especificado de elementos desde o início de uma sequência.
let mySeq = seq { for i in 1 .. 10 -> 3*i }
let truncatedSeq = Seq.truncate 5 mySeq
let takeSeq = Seq.take 5 mySeq
printfn"The original sequence"
Seq.iter (fun i -> printf "%d " i) mySeq
printfn""
printfn"The truncated sequence"
Seq.iter (fun i -> printf "%d " i) truncatedSeq
printfn""
printfn"The take sequence"
Seq.iter (fun i -> printf "%d " i) takeSeq
printfn""
Quando você compila e executa o programa, ele produz a seguinte saída -
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
Um conjunto em F # é uma estrutura de dados que atua como uma coleção de itens sem preservar a ordem em que os itens são inseridos. Os conjuntos não permitem que entradas duplicadas sejam inseridas na coleção.
Criação de conjuntos
Os conjuntos podem ser criados das seguintes maneiras -
- Criando um conjunto vazio usando Set.empty e adicionando itens usando a função add.
- Converter sequências e listas em conjuntos.
O programa a seguir demonstra as técnicas -
(* creating sets *)
let set1 = Set.empty.Add(3).Add(5).Add(7). Add(9)
printfn"The new set: %A" set1
let weekdays = Set.ofList ["mon"; "tues"; "wed"; "thurs"; "fri"]
printfn "The list set: %A" weekdays
let set2 = Set.ofSeq [ 1 .. 2.. 10 ]
printfn "The sequence set: %A" set2
Quando você compila e executa o programa, ele produz a seguinte saída -
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]
Operações básicas em conjuntos
A tabela a seguir mostra as operações básicas em conjuntos -
Valor | Descrição |
---|---|
adicionar: 'T → Definir <' T> → Definir <'T> | Retorna um novo conjunto com um elemento adicionado ao conjunto. Nenhuma exceção é levantada se o conjunto já contém o elemento fornecido. |
contém: 'T → Set <' T> → bool | Avalia para true se o elemento fornecido estiver no conjunto fornecido. |
contagem: Definir <'T> → int | Retorna o número de elementos no conjunto. |
diferença: Definir <'T> → Definir <' T> → Definir <'T> | Retorna um novo conjunto com os elementos do segundo conjunto removidos do primeiro. |
vazio: Definir <'T> | O conjunto vazio para o tipo especificado. |
existe: ('T → bool) → Set <' T> → bool | Testa se algum elemento da coleção satisfaz o predicado fornecido. Se a função de entrada for predicado e os elementos forem i0 ... iN, então essa função calcula o predicado i0 ou ... ou o predicado iN. |
filtro: ('T → bool) → Definir <' T> → Definir <'T> | Retorna uma nova coleção contendo apenas os elementos da coleção para os quais o predicado dado retorna true. |
dobrar: ('Estado →' T → 'Estado) →' Estado → Definir <'T> →' Estado | Aplica a função de acumulação fornecida a todos os elementos do conjunto. |
foldBack: ('T →' Estado → 'Estado) → Definir <' T> → 'Estado →' Estado | Aplica a função de acumulação fornecida a todos os elementos do conjunto. |
forall: ('T → bool) → Set <' T> → bool | Testa se todos os elementos da coleção satisfazem o predicado fornecido. Se a função de entrada for pe os elementos forem i0 ... iN, então esta função calcula p i0 && ... && p iN. |
cruzar: Definir <'T> → Definir <' T> → Definir <'T> | Calcula a interseção dos dois conjuntos. |
intersectMany: seq <Set <'T >> → Set <' T> | Calcula a interseção de uma sequência de conjuntos. A sequência não deve estar vazia. |
isEmpty: Set <'T> → bool | Devoluções true se o conjunto estiver vazio. |
isProperSubset: Set <'T> → Set <' T> → bool | Avalia para true se todos os elementos do primeiro conjunto estiverem no segundo e pelo menos um elemento do segundo não estiver no primeiro. |
isProperSuperset: Set <'T> → Set <' T> → bool | Avalia para true se todos os elementos do segundo conjunto estiverem no primeiro e pelo menos um elemento do primeiro não estiver no segundo. |
isSubset: Set <'T> → Set <' T> → bool | Avalia para true se todos os elementos do primeiro conjunto estiverem no segundo. |
isSuperset: Set <'T> → Set <' T> → bool | Avalia para true se todos os elementos do segundo conjunto estiverem no primeiro. |
iter: ('T → unidade) → Definir <' T> → unidade | Aplica a função dada a cada elemento do conjunto, na ordem de acordo com a função de comparação. |
mapa: ('T →' U) → Definir <'T> → Definir <' U> | Retorna uma nova coleção contendo os resultados da aplicação da função dada a cada elemento do conjunto de entrada. |
maxElement: Definir <'T> →' T | Retorna o elemento mais alto no conjunto de acordo com a ordem que está sendo usada para o conjunto. |
minElement: Set <'T> →' T | Retorna o elemento mais baixo no conjunto de acordo com a ordem em uso para o conjunto. |
ofArray: 'array T → Set <' T> | Cria um conjunto que contém os mesmos elementos da matriz fornecida. |
ofList: 'T list → Set <' T> | Cria um conjunto que contém os mesmos elementos da lista fornecida. |
ofSeq: seq <'T> → Definir <' T> | Cria uma nova coleção a partir do objeto enumerável fornecido. |
partição: ('T → bool) → Definir <' T> → Definir <'T> * Definir <' T> | Divide o conjunto em dois conjuntos contendo os elementos para os quais o predicado fornecido retorna verdadeiro e falso, respectivamente. |
remover: 'T → Definir <' T> → Definir <'T> | Retorna um novo conjunto com o elemento fornecido removido. Nenhuma exceção é levantada se o conjunto não contém o elemento fornecido. |
singleton: 'T → Definir <' T> | O conjunto que contém o elemento fornecido. |
toArray: Definir <'T> →' T array | Cria uma matriz que contém os elementos do conjunto em ordem. |
toList: Definir <'T> →' T lista | Cria uma lista que contém os elementos do conjunto em ordem. |
toSeq: Definir <'T> → seq <' T> | Retorna uma visão ordenada da coleção como um objeto enumerável. |
união: Definir <'T> → Definir <' T> → Definir <'T> | Calcula a união dos dois conjuntos. |
unionMany: seq <Set <'T >> → Set <' T> | Calcula a união de uma sequência de conjuntos. |
O exemplo a seguir demonstra os usos de algumas das funcionalidades acima -
Exemplo
let a = Set.ofSeq [ 1 ..2.. 20 ]
let b = Set.ofSeq [ 1 ..3 .. 20 ]
let c = Set.intersect a b
let d = Set.union a b
let e = Set.difference a b
printfn "Set a: "
Set.iter (fun x -> printf "%O " x) a
printfn""
printfn "Set b: "
Set.iter (fun x -> printf "%O " x) b
printfn""
printfn "Set c = set intersect of a and b : "
Set.iter (fun x -> printf "%O " x) c
printfn""
printfn "Set d = set union of a and b : "
Set.iter (fun x -> printf "%O " x) d
printfn""
printfn "Set e = set difference of a and b : "
Set.iter (fun x -> printf "%O " x) e
printfn""
Quando você compila e executa o programa, ele produz a seguinte saída -
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
Em F #, um mapa é um tipo especial de conjunto que associa os valores à chave. Um mapa é criado de maneira semelhante à criação de conjuntos.
Criação de mapas
Os mapas são criados criando um mapa vazio usando Map.empty e adicionando itens usando a função Adicionar. O exemplo a seguir demonstra isso -
Exemplo
(* Create an empty Map *)
let students =
Map.empty. (* Creating an empty Map *)
Add("Zara Ali", "1501").
Add("Rishita Gupta", "1502").
Add("Robin Sahoo", "1503").
Add("Gillian Megan", "1504");;
printfn "Map - students: %A" students
(* Convert a list to Map *)
let capitals =
[ "Argentina", "Buenos Aires";
"France ", "Paris";
"Chili", "Santiago";
"Malaysia", " Kuala Lumpur";
"Switzerland", "Bern" ]
|> Map.ofList;;
printfn "Map capitals : %A" capitals
Quando você compila e executa o programa, ele produz a seguinte saída -
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")]
Você pode acessar elementos individuais no mapa usando a tecla.
Exemplo
(* Create an empty Map *)
let students =
Map.empty. (* Creating an empty Map *)
Add("Zara Ali", "1501").
Add("Rishita Gupta", "1502").
Add("Robin Sahoo", "1503").
Add("Gillian Megan", "1504");;
printfn "Map - students: %A" students
(*Accessing an element using key *)
printfn "%A" students.["Zara Ali"]
Quando você compila e executa o programa, ele produz a seguinte saída -
Map - students: map
[("Gillian Megan", "1504"); ("Rishita Gupta", "1502"); ("Robin Sahoo", "1503
");
("Zara Ali", "1501")]
"1501"
Operações básicas em mapas
Adicionar nome de módulo
A tabela a seguir mostra as operações básicas em mapas -
Membro | Descrição |
---|---|
Adicionar | Retorna um novo mapa com o vínculo adicionado ao mapa fornecido. |
ContainsKey | Testa se um elemento está no domínio do mapa. |
Contagem | O número de ligações no mapa. |
Está vazia | Retorna verdadeiro se não houver vínculos no mapa. |
Item | Procure um elemento no mapa. Gera KeyNotFoundException se nenhuma ligação existir no mapa. |
Retirar | Remove um elemento do domínio do mapa. Nenhuma exceção é gerada se o elemento não estiver presente. |
TryFind | Procure um elemento no mapa, retornando um Some valor se o elemento estiver no domínio do mapa e None se não. |
O exemplo a seguir demonstra os usos de algumas das funcionalidades acima -
Exemplo
(* Create an empty Map *)
let students =
Map.empty. (* Creating an empty Map *)
Add("Zara Ali", "1501").
Add("Rishita Gupta", "1502").
Add("Robin Sahoo", "1503").
Add("Gillian Megan", "1504").
Add("Shraddha Dubey", "1505").
Add("Novonil Sarker", "1506").
Add("Joan Paul", "1507");;
printfn "Map - students: %A" students
printfn "Map - number of students: %d" students.Count
(* finding the registration number of a student*)
let found = students.TryFind "Rishita Gupta"
match found with
| Some x -> printfn "Found %s." x
| None -> printfn "Did not find the specified value."
Quando você compila e executa o programa, ele produz a seguinte saída -
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.
As uniões, ou uniões discriminadas, permitem que você crie estruturas de dados complexas que representam um conjunto bem definido de escolhas. Por exemplo, você precisa construir uma implementação de uma variável de escolha , que tem dois valores sim e não. Usando a ferramenta Sindicatos, você pode projetar isso.
Sintaxe
As uniões discriminadas são definidas usando a seguinte sintaxe -
type type-name =
| case-identifier1 [of [ fieldname1 : ] type1 [ * [ fieldname2 : ]
type2 ...]
| case-identifier2 [of [fieldname3 : ]type3 [ * [ fieldname4 : ]type4 ...]
...
Nossa implementação simples de, escolha, será semelhante ao seguinte -
type choice =
| Yes
| No
O exemplo a seguir usa a escolha de tipo -
type choice =
| Yes
| No
let x = Yes (* creates an instance of choice *)
let y = No (* creates another instance of choice *)
let main() =
printfn "x: %A" x
printfn "y: %A" y
main()
Quando você compila e executa o programa, ele produz a seguinte saída -
x: Yes
y: No
Exemplo 1
O exemplo a seguir mostra a implementação dos estados de tensão que define um bit em alto ou baixo -
type VoltageState =
| High
| Low
let toggleSwitch = function (* pattern matching input *)
| High -> Low
| Low -> High
let main() =
let on = High
let off = Low
let change = toggleSwitch off
printfn "Switch on state: %A" on
printfn "Switch off state: %A" off
printfn "Toggle off: %A" change
printfn "Toggle the Changed state: %A" (toggleSwitch change)
main()
Quando você compila e executa o programa, ele produz a seguinte saída -
Switch on state: High
Switch off state: Low
Toggle off: High
Toggle the Changed state: Low
Exemplo 2
type Shape =
// here we store the radius of a circle
| Circle of float
// here we store the side length.
| Square of float
// here we store the height and width.
| Rectangle of float * float
let pi = 3.141592654
let area myShape =
match myShape with
| Circle radius -> pi * radius * radius
| Square s -> s * s
| Rectangle (h, w) -> h * w
let radius = 12.0
let myCircle = Circle(radius)
printfn "Area of circle with radius %g: %g" radius (area myCircle)
let side = 15.0
let mySquare = Square(side)
printfn "Area of square that has side %g: %g" side (area mySquare)
let height, width = 5.0, 8.0
let myRectangle = Rectangle(height, width)
printfn "Area of rectangle with height %g and width %g is %g" height width (area myRectangle)
Quando você compila e executa o programa, ele produz a seguinte saída -
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
Variáveis em F # são immutable,o que significa que uma vez que uma variável está vinculada a um valor, ela não pode ser alterada. Na verdade, eles são compilados como propriedades estáticas somente leitura.
O exemplo a seguir demonstra isso.
Exemplo
let x = 10
let y = 20
let z = x + y
printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z
let x = 15
let y = 20
let z = x + y
printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z
Quando você compila e executa o programa, ele mostra a seguinte mensagem de erro -
Duplicate definition of value 'x'
Duplicate definition of value 'Y'
Duplicate definition of value 'Z'
Variáveis Mutáveis
Às vezes, você precisa alterar os valores armazenados em uma variável. Para especificar que pode haver uma mudança no valor de uma variável declarada e atribuída em uma parte posterior de um programa, F # fornece omutablepalavra-chave. Você pode declarar e atribuir variáveis mutáveis usando esta palavra-chave, cujos valores você irá alterar.
o mutable palavra-chave permite declarar e atribuir valores em uma variável mutável.
Você pode atribuir algum valor inicial a uma variável mutável usando o letpalavra-chave. No entanto, para atribuir um novo valor subsequente a ele, você precisa usar o<- operador.
Por exemplo,
let mutable x = 10
x <- 15
O exemplo a seguir irá limpar o conceito -
Exemplo
let mutable x = 10
let y = 20
let mutable z = x + y
printfn "Original Values:"
printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z
printfn "Let us change the value of x"
printfn "Value of z will change too."
x <- 15
z <- x + y
printfn "New Values:"
printfn "x: %i" x
printfn "y: %i" y
printfn "z: %i" z
Quando você compila e executa o programa, ele produz a seguinte saída -
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
Usos de dados mutáveis
Os dados mutáveis costumam ser necessários e usados no processamento de dados, principalmente com a estrutura de dados de registro. O exemplo a seguir demonstra isso -
open System
type studentData =
{ ID : int;
mutable IsRegistered : bool;
mutable RegisteredText : string; }
let getStudent id =
{ ID = id;
IsRegistered = false;
RegisteredText = null; }
let registerStudents (students : studentData list) =
students |> List.iter(fun st ->
st.IsRegistered <- true
st.RegisteredText <- sprintf "Registered %s" (DateTime.Now.ToString("hh:mm:ss"))
Threading.Thread.Sleep(1000) (* Putting thread to sleep for 1 second to simulate processing overhead. *))
let printData (students : studentData list) =
students |> List.iter (fun x -> printfn "%A" x)
let main() =
let students = List.init 3 getStudent
printfn "Before Process:"
printData students
printfn "After process:"
registerStudents students
printData students
Console.ReadKey(true) |> ignore
main()
Quando você compila e executa o programa, ele produz a seguinte saída -
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";}
Os arrays são coleções mutáveis, baseadas em zero e de tamanho fixo de elementos de dados consecutivos que são todos do mesmo tipo.
Criação de matrizes
Você pode criar matrizes usando várias sintaxes e formas ou usando as funções do módulo Array. Nesta seção, discutiremos a criação de arrays sem usar as funções do módulo.
Existem três maneiras sintáticas de criar matrizes sem funções -
- Listando valores consecutivos entre [| e |] e separados por ponto e vírgula.
- Colocando cada elemento em uma linha separada, caso em que o separador de ponto-e-vírgula é opcional.
- Usando expressões de sequência.
Você pode acessar os elementos da matriz usando um operador ponto (.) E colchetes ([e]).
O exemplo a seguir demonstra a criação de matrizes -
//using semicolon separator
let array1 = [| 1; 2; 3; 4; 5; 6 |]
for i in 0 .. array1.Length - 1 do
printf "%d " array1.[i]
printfn" "
// without semicolon separator
let array2 =
[|
1
2
3
4
5
|]
for i in 0 .. array2.Length - 1 do
printf "%d " array2.[i]
printfn" "
//using sequence
let array3 = [| for i in 1 .. 10 -> i * i |]
for i in 0 .. array3.Length - 1 do
printf "%d " array3.[i]
printfn" "
Quando você compila e executa o programa, ele produz a seguinte saída -
1 2 3 4 5 6
1 2 3 4 5
1 4 9 16 25 36 49 64 81 100
Operações básicas em matrizes
O módulo de biblioteca Microsoft.FSharp.Collections.Array oferece suporte a operações em matrizes unidimensionais.
A tabela a seguir mostra as operações básicas em Arrays -
Valor | Descrição |
---|---|
acrescente: 'T [] →' T [] → 'T [] | Cria uma matriz que contém os elementos de uma matriz seguidos pelos elementos de outra matriz. |
média: ^ T [] → ^ T | Retorna a média dos elementos em uma matriz. |
averageBy: ('T → ^ U) →' T [] → ^ U | Retorna a média dos elementos gerados pela aplicação de uma função a cada elemento de uma matriz. |
blit: 'T [] → int →' T [] → int → int → unidade | Lê uma variedade de elementos de um array e os grava em outro. |
escolha: (opção 'T → U) →' T [] → 'U [] | Aplica uma função fornecida a cada elemento de uma matriz. Retorna uma matriz que contém os resultados x para cada elemento para o qual a função retorna Some (x). |
coletar: ('T →' U []) → T [] → 'U [] | Aplica a função fornecida a cada elemento de uma matriz, concatena os resultados e retorna a matriz combinada. |
concat: seq <'T []> →' T [] | Cria uma matriz que contém os elementos de cada uma das sequências de matrizes fornecidas. |
cópia: 'T →' T [] | Cria uma matriz que contém os elementos da matriz fornecida. |
criar: int → 'T →' T [] | Cria uma matriz cujos elementos são todos inicialmente o valor fornecido. |
vazio: 'T [] | Retorna uma matriz vazia do tipo fornecido. |
existe: ('T → bool) →' T [] → bool | Testa se algum elemento de uma matriz satisfaz o predicado fornecido. |
existe2: ('T1 →' T2 → bool) → 'T1 [] →' T2 [] → bool | Testa se algum par de elementos correspondentes de duas matrizes satisfaz a condição fornecida. |
preencher: 'T [] → int → int →' T → unidade | Preenche um intervalo de elementos de uma matriz com o valor fornecido. |
filtro: ('T → bool) →' T [] → 'T [] | Retorna uma coleção que contém apenas os elementos da matriz fornecida para a qual a condição fornecida retorna true. |
encontrar: ('T → bool) →' T [] → 'T | Retorna o primeiro elemento para o qual a função fornecida retorna true. Gera KeyNotFoundException se tal elemento não existir. |
findIndex: ('T → bool) →' T [] → int | Retorna o índice do primeiro elemento em uma matriz que satisfaça a condição fornecida. Gera KeyNotFoundException se nenhum dos elementos satisfizer a condição. |
dobrar: ('Estado →' T → 'Estado) →' Estado → 'T [] →' Estado | Aplica uma função a cada elemento de uma matriz, encadeando um argumento do acumulador por meio da computação. Se a função de entrada for fe os elementos da matriz forem i0 ... iN, esta função calcula f (... (fs i0) ...) iN. |
fold2: ('Estado →' T1 → 'T2 →' Estado) → 'Estado →' T1 [] → 'T2 [] →' Estado | Aplica uma função a pares de elementos de duas matrizes fornecidas, da esquerda para a direita, encadeando um argumento do acumulador por meio da computação. As duas matrizes de entrada devem ter os mesmos comprimentos; caso contrário, ArgumentException é gerado. |
foldBack: ('T →' Estado → 'Estado) →' T [] → 'Estado →' Estado | Aplica uma função a cada elemento de uma matriz, encadeando um argumento do acumulador por meio da computação. Se a função de entrada for fe os elementos da matriz forem i0 ... iN, esta função calcula f i0 (... (f iN s)). |
foldBack2: ('T1 →' T2 → 'Estado →' Estado) → 'T1 [] →' T2 [] → 'Estado →' Estado | Aplica uma função a pares de elementos de dois arrays fornecidos, da direita para a esquerda, encadeando um argumento do acumulador por meio da computação. As duas matrizes de entrada devem ter os mesmos comprimentos; caso contrário, ArgumentException é gerado. |
forall: ('T → bool) →' T [] → bool | Testa se todos os elementos de uma matriz satisfazem a condição fornecida. |
forall2: ('T1 →' T2 → bool) → 'T1 [] →' T2 [] → bool | Testa se todos os elementos correspondentes de duas matrizes fornecidas satisfazem uma condição fornecida. |
obter: 'T [] → int →' T | Obtém um elemento de uma matriz. |
init: int → (int → 'T) →' T [] | Usa uma função fornecida para criar uma matriz da dimensão fornecida. |
isEmpty: 'T [] → bool | Testa se uma matriz possui algum elemento. |
iter: ('T → unidade) →' T [] → unidade | Aplica a função fornecida a cada elemento de uma matriz. |
iter2: ('T1 →' T2 → unidade) → 'T1 [] →' T2 [] → unidade) | Aplica a função fornecida a um par de elementos de índices correspondentes em duas matrizes. As duas matrizes devem ter os mesmos comprimentos; caso contrário, ArgumentException é gerado. |
iteri: (int → 'T → unidade) →' T [] → unidade | Aplica a função fornecida a cada elemento de uma matriz. O inteiro passado para a função indica o índice do elemento. |
iteri2: (int → 'T1 →' T2 → unidade) → 'T1 [] →' T2 [] → unidade | Aplica a função fornecida a um par de elementos a partir de índices correspondentes em duas matrizes, passando também o índice dos elementos. As duas matrizes devem ter os mesmos comprimentos; caso contrário, um ArgumentException é gerado. |
comprimento: 'T [] → int | Retorna o comprimento de uma matriz. A propriedade Length faz a mesma coisa. |
mapa: ('T →' U) → 'T [] →' U [] | Cria uma matriz cujos elementos são os resultados da aplicação da função fornecida a cada um dos elementos de uma matriz fornecida. |
mapa2: ('T1 →' T2 → 'U) →' T1 [] → 'T2 [] →' U [] | Cria uma matriz cujos elementos são os resultados da aplicação da função fornecida aos elementos correspondentes de duas matrizes fornecidas. As duas matrizes de entrada devem ter os mesmos comprimentos; caso contrário, ArgumentException é gerado. |
mapi: (int → 'T →' U) → 'T [] →' U [] | Cria uma matriz cujos elementos são os resultados da aplicação da função fornecida a cada um dos elementos de uma matriz fornecida. Um índice inteiro passado para a função indica o índice do elemento sendo transformado. |
mapi2: (int → 'T1 →' T2 → 'U) →' T1 [] → 'T2 [] →' U [] | Cria uma matriz cujos elementos são os resultados da aplicação da função fornecida aos elementos correspondentes das duas coleções aos pares, passando também o índice dos elementos. As duas matrizes de entrada devem ter os mesmos comprimentos; caso contrário, ArgumentException é gerado. |
máx: 'T [] →' T | Retorna o maior de todos os elementos de uma matriz. Operators.max é usado para comparar os elementos. |
maxBy: ('T →' U) → 'T [] →' T | Retorna o maior de todos os elementos de uma matriz, comparado por Operators.max no resultado da função. |
min: ('T [] →' T | Retorna o menor de todos os elementos de uma matriz. Operators.min é usado para comparar os elementos. |
minBy: ('T →' U) → 'T [] →' T | Retorna o menor de todos os elementos de uma matriz. Operators.min é usado para comparar os elementos. |
ofList: 'Lista T →' T [] | Cria uma matriz da lista fornecida. |
ofSeq: seq <'T> →' T [] | Cria uma matriz do objeto enumerável fornecido. |
partição: ('T → bool) →' T [] → 'T [] *' T [] | Divide uma matriz em duas matrizes, uma contendo os elementos para os quais a condição fornecida retorna true, e o outro contendo aqueles para os quais ele retorna false. |
permutar: (int → int) → 'T [] →' T [] | Permuta os elementos de uma matriz de acordo com a permutação especificada. |
escolha: ('T →' opção U) → 'T [] →' U | Aplica a função fornecida a elementos sucessivos de uma matriz fornecida, retornando o primeiro resultado onde a função retorna Some (x) para algum x. Se a função nunca retorna Some (x), KeyNotFoundException é gerado. |
reduzir: ('T →' T → 'T) →' T [] → 'T | Aplica uma função a cada elemento de uma matriz, encadeando um argumento do acumulador por meio da computação. Se a função de entrada for fe os elementos da matriz forem i0 ... iN, esta função calcula f (... (f i0 i1) ...) iN. Se a matriz tiver tamanho zero, ArgumentException será gerado. |
reduzVoltar: ('T →' T → 'T) →' T [] → 'T | Aplica uma função a cada elemento de uma matriz, encadeando um argumento do acumulador por meio da computação. Se a função de entrada for fe os elementos forem i0 ... iN, esta função calcula f i0 (... (f iN-1 iN)). Se a matriz tiver tamanho zero, ArgumentException será gerado. |
rev: 'T [] →' T [] | Inverte a ordem dos elementos em uma matriz fornecida. |
varredura: ('Estado →' T → 'Estado) →' Estado → 'T [] →' Estado []) | Comporta-se como dobra, mas retorna os resultados intermediários junto com os resultados finais. |
scanBack: ('T →' Estado → 'Estado) →' T [] → 'Estado →' Estado [] | Se comporta como foldBack, mas retorna os resultados intermediários junto com os resultados finais. |
definir: 'T [] → int →' T → unidade | Define um elemento de uma matriz. |
classificar: 'T [] →' T [] | Classifica os elementos de uma matriz e retorna uma nova matriz. Operators.compare é usado para comparar os elementos. |
sortBy: ('T →' Tecla) → 'T [] →' T [] | Classifica os elementos de uma matriz usando a função fornecida para transformar os elementos no tipo no qual a operação de classificação se baseia e retorna uma nova matriz. Operators.compare é usado para comparar os elementos. |
sortInPlace: 'T [] → unidade | Classifica os elementos de uma matriz alterando a matriz no local, usando a função de comparação fornecida. Operators.compare é usado para comparar os elementos. |
sortInPlaceBy: (tecla 'T →') → 'T [] → unidade | Classifica os elementos de uma matriz alterando a matriz no local, usando a projeção fornecida para as chaves. Operators.compare é usado para comparar os elementos. |
sortInPlaceWith: ('T →' T → int) → 'T [] → unidade | Classifica os elementos de uma matriz usando a função de comparação fornecida para alterar a matriz no local. |
sortWith: ('T →' T → int) → 'T [] →' T [] | Classifica os elementos de uma matriz usando a função de comparação fornecida e retorna uma nova matriz. |
sub: 'T [] → int → int →' T [] | Cria uma matriz que contém o subintervalo fornecido, que é especificado pelo índice inicial e comprimento. |
soma: 'T [] → ^ T | Retorna a soma dos elementos da matriz. |
sumBy: ('T → ^ U) →' T [] → ^ U | Retorna a soma dos resultados gerados pela aplicação de uma função a cada elemento de uma matriz. |
toList: 'T [] →' T list | Converte a matriz fornecida em uma lista. |
toSeq: 'T [] → seq <' T> | Vê a matriz fornecida como uma sequência. |
tryFind: ('T → bool) →' T [] → 'opção T | Retorna o primeiro elemento na matriz fornecida para o qual a função fornecida retorna true. DevoluçõesNone se tal elemento não existir. |
tryFindIndex: ('T → bool) →' T [] → opção int | Retorna o índice do primeiro elemento em uma matriz que satisfaça a condição fornecida. |
tryPick: ('T →' opção U) → 'T [] →' opção U | Aplica a função fornecida a elementos sucessivos da matriz fornecida e retorna o primeiro resultado onde a função retorna Some (x) para algum x. Se a função nunca retorna Some (x),None é devolvido. |
descompactar: ('T1 *' T2) [] → 'T1 [] *' T2 [] | Divide um array de pares de tupla em uma tupla de dois arrays. |
unzip3: ('T1 *' T2 * 'T3) [] →' T1 [] * 'T2 [] *' T3 [] | Divide um array de tuplas de três elementos em uma tupla de três arrays. |
zeroCreate: int → 'T [] | Cria uma matriz cujos elementos são inicialmente definidos com o valor padrão Unchecked.defaultof <'T>. |
CEP: 'T1 [] →' T2 [] → ('T1 *' T2) [] | Combina duas matrizes em uma matriz de tuplas que possui dois elementos. As duas matrizes devem ter comprimentos iguais; caso contrário, ArgumentException é gerado. |
zip3: 'T1 [] →' T2 [] → 'T3 [] → (' T1 * 'T2 * 113' T3) [] | Combina três matrizes em uma matriz de tuplas com três elementos. As três matrizes devem ter comprimentos iguais; caso contrário, ArgumentException é gerado. |
Na seção seguinte, veremos os usos de algumas dessas funcionalidades.
Criação de matrizes usando funções
O módulo Array oferece várias funções que criam um array desde o início.
o Array.empty função cria um novo array vazio.
o Array.create função cria uma matriz de um tamanho especificado e define todos os elementos para determinados valores.
o Array.init function cria um array, dada uma dimensão e uma função para gerar os elementos.
o Array.zeroCreate função cria uma matriz na qual todos os elementos são inicializados com o valor zero.
o Array.copy função cria uma nova matriz que contém elementos que são copiados de uma matriz existente.
o Array.sub função gera um novo array a partir de um subintervalo de um array.
o Array.append função cria um novo array combinando dois arrays existentes.
o Array.choose função seleciona elementos de uma matriz para incluir em uma nova matriz.
o Array.collect function executa uma função especificada em cada elemento da matriz de uma matriz existente e, a seguir, coleta os elementos gerados pela função e os combina em uma nova matriz.
o Array.concat função pega uma sequência de matrizes e as combina em uma única matriz.
o Array.filter function recebe uma função de condição booleana e gera uma nova matriz que contém apenas os elementos da matriz de entrada para os quais a condição é verdadeira.
o Array.rev função gera um novo array invertendo a ordem de um array existente.
Os exemplos a seguir demonstram essas funções -
Exemplo 1
(* using create and set *)
let array1 = Array.create 10 ""
for i in 0 .. array1.Length - 1 do
Array.set array1 i (i.ToString())
for i in 0 .. array1.Length - 1 do
printf "%s " (Array.get array1 i)
printfn " "
(* empty array *)
let array2 = Array.empty
printfn "Length of empty array: %d" array2.Length
let array3 = Array.create 10 7.0
printfn "Float Array: %A" array3
(* using the init and zeroCreate *)
let array4 = Array.init 10 (fun index -> index * index)
printfn "Array of squares: %A" array4
let array5 : float array = Array.zeroCreate 10
let (myZeroArray : float array) = Array.zeroCreate 10
printfn "Float Array: %A" array5
Quando você compila e executa o programa, ele produz a seguinte saída -
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|]
Exemplo 2
(* creating subarray from element 5 *)
(* containing 15 elements thereon *)
let array1 = [| 0 .. 50 |]
let array2 = Array.sub array1 5 15
printfn "Sub Array:"
printfn "%A" array2
(* appending two arrays *)
let array3 = [| 1; 2; 3; 4|]
let array4 = [| 5 .. 9 |]
printfn "Appended Array:"
let array5 = Array.append array3 array4
printfn "%A" array5
(* using the Choose function *)
let array6 = [| 1 .. 20 |]
let array7 = Array.choose (fun elem -> if elem % 3 = 0 then
Some(float (elem))
else
None) array6
printfn "Array with Chosen elements:"
printfn "%A" array7
(*using the Collect function *)
let array8 = [| 2 .. 5 |]
let array9 = Array.collect (fun elem -> [| 0 .. elem - 1 |]) array8
printfn "Array with collected elements:"
printfn "%A" array9
Quando você compila e executa o programa, ele produz a seguinte saída -
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|]
Pesquisando matrizes
o Array.find function recebe uma função booleana e retorna o primeiro elemento para o qual a função retorna true; caso contrário, gera uma KeyNotFoundException.
o Array.findIndex A função funciona de forma semelhante, exceto que retorna o índice do elemento em vez do próprio elemento.
O exemplo a seguir demonstra isso.
A Microsoft fornece este exemplo de programa interessante, que encontra o primeiro elemento no intervalo de um determinado número que é tanto um quadrado perfeito quanto um cubo perfeito -
let array1 = [| 2 .. 100 |]
let delta = 1.0e-10
let isPerfectSquare (x:int) =
let y = sqrt (float x)
abs(y - round y) < delta
let isPerfectCube (x:int) =
let y = System.Math.Pow(float x, 1.0/3.0)
abs(y - round y) < delta
let element = Array.find (fun elem -> isPerfectSquare elem && isPerfectCube elem) array1
let index = Array.findIndex (fun elem -> isPerfectSquare elem && isPerfectCube elem) array1
printfn "The first element that is both a square and a cube is %d and its index is %d." element index
When you compile and execute the program, it yields the following output −
The first element that is both a square and a cube is 64 and its index is 62.
The List<'T> class represents a strongly typed list of objects that can be accessed by index.
It is a mutable counterpart of the List class. It is similar to arrays, as it can be accessed by an index, however, unlike arrays, lists can be resized. Therefore you need not specify a size during declaration.
Creating a Mutable List
Lists are created using the new keyword and calling the list's constructor. The following example demonstrates this −
(* Creating a List *)
open System.Collections.Generic
let booksList = new List<string>()
booksList.Add("Gone with the Wind")
booksList.Add("Atlas Shrugged")
booksList.Add("Fountainhead")
booksList.Add("Thornbirds")
booksList.Add("Rebecca")
booksList.Add("Narnia")
booksList |> Seq.iteri (fun index item -> printfn "%i: %s" index booksList.[index])
When you compile and execute the program, it yields the following output −
0: Gone with the Wind
1: Atlas Shrugged
2: Fountainhead
3: Thornbirds
4: Rebecca
5: Narnia
The List(T) Class
The List(T) class represents a strongly typed list of objects that can be accessed by index. It provide methods to search, sort, and manipulate lists.
The following tables provide the properties, constructors and the methods of the List(T) class −
Properties
Property | Description |
---|---|
Capacity | Gets or sets the total number of elements the internal data structure can hold without resizing. |
Count | Gets the number of elements contained in the List(T). |
Item | Gets or sets the element at the specified index. |
Constructors
Constructor | Description |
---|---|
List(T)() | Initializes a new instance of the List(T) class that is empty and has the default initial capacity. |
List(T)(IEnumerable(T)) | Initializes a new instance of the List(T) class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied. |
List(T)(Int32) | Initializes a new instance of the List(T) class that is empty and has the specified initial capacity. |
Method
Methods | Description |
---|---|
Add | Adds an object to the end of the List(T). |
AddRange | Adds the elements of the specified collection to the end of the List(T). |
AsReadOnly | Returns a read-only IList(T) wrapper for the current collection. |
BinarySearch(T) | Searches the entire sorted List(T) for an element using the default comparer and returns the zero-based index of the element. |
BinarySearch(T, IComparer(T)) | Searches the entire sorted List(T) for an element using the specified comparer and returns the zero-based index of the element. |
BinarySearch(Int32, Int32, T, IComparer(T)) | Searches a range of elements in the sorted List(T) for an element using the specified comparer and returns the zero-based index of the element. |
Clear | Removes all elements from the List(T). |
Contains | Determines whether an element is in the List(T). |
ConvertAll(TOutput) | Converts the elements in the current List(T) to another type, and returns a list containing the converted elements. |
CopyTo(T[]) | Copies the entire List(T) to a compatible one-dimensional array, starting at the beginning of the target array. |
CopyTo(T[], Int32) | Copies the entire List(T) to a compatible one-dimensional array, starting at the specified index of the target array. |
CopyTo(Int32, T[], Int32, Int32) | Copies a range of elements from the List(T) to a compatible one-dimensional array, starting at the specified index of the target array. |
Equals(Object) | Determines whether the specified object is equal to the current object. (Inherited from Object.) |
Exists | Determines whether the List(T) contains elements that match the conditions defined by the specified predicate. |
Finalize | Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection (Inherited from Object). |
Find | Searches for an element that matches the conditions defined by the specified predicate, and returns the first occurrence within the entire List(T). |
FindAll | Retrieves all the elements that match the conditions defined by the specified predicate. |
FindIndex(Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the entire List(T). |
FindIndex(Int32, Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the range of elements in the List(T) that extends from the specified index to the last element. |
FindIndex(Int32, Int32, Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the first occurrence within the range of elements in the List(T) that starts at the specified index and contains the specified number of elements. |
FindLast | Searches for an element that matches the conditions defined by the specified predicate, and returns the last occurrence within the entire List(T). |
FindLastIndex(Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the last occurrence within the entire List(T). |
FindLastIndex(Int32, Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the last occurrence within the range of elements in the List(T) that extends from the first element to the specified index. |
FindLastIndex(Int32, Int32, Predicate(T)) | Searches for an element that matches the conditions defined by the specified predicate, and returns the zero-based index of the last occurrence within the range of elements in the List(T) that contains the specified number of elements and ends at the specified index. |
ForEach | Performs the specified action on each element of the List(T). |
GetEnumerator | Returns an enumerator that iterates through the List(T). |
GetHashCode | Serves as the default hash function. (Inherited from Object.) |
GetRange | Creates a shallow copy of a range of elements in the source List(T). |
GetType | Gets the Type of the current instance. (Inherited from Object.) |
IndexOf(T) | Searches for the specified object and returns the zero-based index of the first occurrence within the entire List(T). |
IndexOf(T, Int32) | Searches for the specified object and returns the zero-based index of the first occurrence within the range of elements in the List(T) that extends from the specified index to the last element. |
IndexOf(T, Int32, Int32) | Searches for the specified object and returns the zero-based index of the first occurrence within the range of elements in the List(T) that starts at the specified index and contains the specified number of elements. |
Insert | Inserts an element into the List(T) at the specified index. |
InsertRange | Inserts the elements of a collection into the List(T) at the specified index. |
LastIndexOf(T) | Searches for the specified object and returns the zero-based index of the last occurrence within the entire List(T). |
LastIndexOf(T, Int32) | Searches for the specified object and returns the zero-based index of the last occurrence within the range of elements in the List(T) that extends from the first element to the specified index. |
LastIndexOf(T, Int32, Int32) | Searches for the specified object and returns the zero-based index of the last occurrence within the range of elements in the List(T) that contains the specified number of elements and ends at the specified index. |
MemberwiseClone | Creates a shallow copy of the current Object. (Inherited from Object.) |
Remove | Removes the first occurrence of a specific object from the List(T). |
RemoveAll | Removes all the elements that match the conditions defined by the specified predicate. |
RemoveAt | Removes the element at the specified index of the List(T). |
RemoveRange | Removes a range of elements from the List(T). |
Reverse() | Reverses the order of the elements in the entire List(T). |
Reverse(Int32, Int32) | Reverses the order of the elements in the specified range. |
Sort() | Sorts the elements in the entire List(T) using the default comparer. |
Sort(Comparison(T)) | Sorts the elements in the entire List(T) using the specified System. Comparison(T). |
Sort(IComparer(T)) | Sorts the elements in the entire List(T) using the specified comparer. |
Sort(Int32, Int32, IComparer(T)) | Sorts the elements in a range of elements in List(T) using the specified comparer. |
ToArray | Copies the elements of the List(T) to a new array. |
ToString | Returns a string that represents the current object. (Inherited from Object.) |
TrimExcess | Sets the capacity to the actual number of elements in the List(T), if that number is less than a threshold value. |
TrueForAll | Determines whether every element in the List(T) matches the conditions defined by the specified predicate. |
Exemplo
(* Creating a List *)
open System.Collections.Generic
let booksList = new List<string>()
booksList.Add("Gone with the Wind")
booksList.Add("Atlas Shrugged")
booksList.Add("Fountainhead")
booksList.Add("Thornbirds")
booksList.Add("Rebecca")
booksList.Add("Narnia")
printfn"Total %d books" booksList.Count
booksList |> Seq.iteri (fun index item -> printfn "%i: %s" index booksList.[index])
booksList.Insert(2, "Roots")
printfn("after inserting at index 2")
printfn"Total %d books" booksList.Count
booksList |> Seq.iteri (fun index item -> printfn "%i: %s" index booksList.[index])
booksList.RemoveAt(3)
printfn("after removing from index 3")
printfn"Total %d books" booksList.Count
booksList |> Seq.iteri (fun index item -> printfn "%i: %s" index booksList.[index])
Quando você compila e executa o programa, ele produz a seguinte saída -
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
o Dictionary<'TKey, 'TValue> classe é o análogo mutável da estrutura de dados do mapa F # e contém muitas das mesmas funções.
Recapitulando do capítulo Mapa em F #, um mapa é um tipo especial de conjunto que associa os valores à chave.
Criação de um dicionário mutável
Dicionários mutáveis são criados usando o newpalavra-chave e chamando o construtor da lista. O exemplo a seguir demonstra isso -
open System.Collections.Generic
let dict = new Dictionary<string, string>()
dict.Add("1501", "Zara Ali")
dict.Add("1502","Rishita Gupta")
dict.Add("1503","Robin Sahoo")
dict.Add("1504","Gillian Megan")
printfn "Dictionary - students: %A" dict
Quando você compila e executa o programa, ele produz a seguinte saída -
Dictionary - students: seq
[[1501, Zara Ali]; [1502, Rishita Gupta]; [1503, Robin Sahoo];
[1504, Gillian Megan]]
A classe de dicionário (TKey, TValue)
A classe Dictionary (TKey, TValue) representa uma coleção de chaves e valores.
As tabelas a seguir fornecem as propriedades, construtores e os métodos da classe List (T) -
Propriedades
Propriedade | Descrição |
---|---|
Comparer | Obtém o IEqualityComparer (T) que é usado para determinar a igualdade das chaves do dicionário. |
Contagem | Obtém o número de pares de chave / valor contidos no Dicionário (TKey, TValue). |
Item | Obtém ou define o valor associado à chave especificada. |
Chaves | Obtém uma coleção contendo as chaves do Dicionário (TKey, TValue). |
Valores | Obtém uma coleção contendo os valores do Dicionário (TKey, TValue). |
Construtores
Construtores | Descrição |
---|---|
Dicionário (TKey, TValue) () | Inicializa uma nova instância do Dictionary(TKey, TValue) classe que está vazia, tem a capacidade inicial padrão e usa o comparador de igualdade padrão para o tipo de chave. |
Dicionário (TKey, TValue) (IDictionary (TKey, TValue)) | Inicializa uma nova instância do Dictionary(TKey, TValue) classe que contém elementos copiados do especificado IDictionary(TKey, TValue) e usa o comparador de igualdade padrão para o tipo de chave. |
Dicionário (TKey, TValue) (IEqualityComparer (TKey)) | Inicializa uma nova instância do Dictionary(TKey, TValue) classe que está vazia, tem a capacidade inicial padrão e usa o especificado IEqualityComparer(T). |
Dicionário (TKey, TValue) (Int32) | Inicializa uma nova instância do Dictionary(TKey, TValue) classe que está vazia, tem a capacidade inicial especificada e usa o comparador de igualdade padrão para o tipo de chave. |
Dicionário (TKey, TValue) (IDictionary (TKey, TValue), IEqualityComparer (TKey)) | Inicializa uma nova instância do Dictionary(TKey, TValue) classe que contém elementos copiados do especificado IDictionary(TKey, TValue) e usa o especificado IEqualityComparer(T). |
Dicionário (TKey, TValue) (Int32, IEqualityComparer (TKey)) | Inicializa uma nova instância do Dictionary(TKey, TValue) classe que está vazia, tem a capacidade inicial especificada e usa o especificado IEqualityComparer(T). |
Dicionário (TKey, TValue) (SerializationInfo, StreamingContext) | Inicializa uma nova instância do ictionary(TKey, TValue) classe com dados serializados. |
Métodos
Método | Descrição |
---|---|
Adicionar | Adiciona a chave e o valor especificados ao dicionário. |
Claro | Remove todas as chaves e valores do Dicionário (TKey, TValue). |
ContainsKey | Determina se o Dicionário (TKey, TValue) contém a chave especificada. |
ContainsValue | Determina se o Dicionário (TKey, TValue) contém um valor específico. |
Igual a (objeto) | Determina se o objeto especificado é igual ao objeto atual. (Herdado do objeto.) |
Finalizar | Permite que um objeto tente liberar recursos e realizar outras operações de limpeza antes de ser recuperado pela coleta de lixo. (Herdado do objeto.) |
GetEnumerator | Retorna um enumerador que itera por meio do Dicionário (TKey, TValue). |
GetHashCode | Serve como a função hash padrão. (Herdado do objeto.) |
GetObjectData | Implementa a interface System.Runtime.Serialization.ISerializable e retorna os dados necessários para serializar a instância do Dicionário (TKey, TValue). |
GetType | Obtém o tipo da instância atual. (Herdado do objeto.) |
MemberwiseClone | Cria uma cópia superficial do objeto atual. (Herdado do objeto.) |
OnDeserialization | Implementa a interface System.Runtime.Serialization.ISerializable e gera o evento de desserialização quando a desserialização é concluída. |
Retirar | Remove o valor com a chave especificada do Dicionário (TKey, TValue). |
Para sequenciar | Retorna uma string que representa o objeto atual. (Herdado do objeto.) |
TryGetValue | Obtém o valor associado à chave especificada. |
Exemplo
open System.Collections.Generic
let dict = new Dictionary<string, string>()
dict.Add("1501", "Zara Ali")
dict.Add("1502","Rishita Gupta")
dict.Add("1503","Robin Sahoo")
dict.Add("1504","Gillian Megan")
printfn "Dictionary - students: %A" dict
printfn "Total Number of Students: %d" dict.Count
printfn "The keys: %A" dict.Keys
printf"The Values: %A" dict.Values
Quando você compila e executa o programa, ele produz a seguinte saída -
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"]
A entrada de saída básica inclui -
- Ler e escrever no console.
- Ler e escrever no arquivo.
Módulo Core.Printf
Usamos as funções printf e printfn para escrever no console. Nesta seção, veremos os detalhes doPrintf módulo do F #.
Além das funções acima, o módulo Core.Printf do F # possui vários outros métodos de impressão e formatação usando marcadores% como espaços reservados. A tabela a seguir mostra os métodos com uma breve descrição -
Valor | Descrição |
---|---|
bprintf: StringBuilder → BuilderFormat <'T> →' T | Imprime em um StringBuilder. |
eprintf: TextWriterFormat <'T> →' T | Imprime saída formatada em stderr. |
eprintfn: TextWriterFormat <'T> →' T | Imprime saída formatada em stderr, adicionando uma nova linha. |
failwithf: StringFormat <'T,' Result> → 'T | Imprime em um buffer de string e levanta uma exceção com o resultado fornecido. |
fprintf: TextWriter → TextWriterFormat <'T> →' T | Imprime para um redator de texto. |
fprintfn: TextWriter → TextWriterFormat <'T> →' T | Imprime em um redator de texto, adicionando uma nova linha. |
kbprintf: (unidade → 'Resultado) → StringBuilder → BuilderFormat <' T, 'Resultado> →' T | Como bprintf, mas chama a função especificada para gerar o resultado. |
kfprintf: (unidade → 'Resultado) → TextWriter → TextWriterFormat <' T, 'Resultado> →' T | Como fprintf, mas chama a função especificada para gerar o resultado. |
kprintf: (string → 'Resultado) → StringFormat <' T, 'Resultado> →' T | Como printf, mas chama a função especificada para gerar o resultado. Por exemplo, eles permitem que a impressão force uma descarga após toda a saída ter sido inserida no canal, mas não antes. |
ksprintf: (string → 'Resultado) → StringFormat <' T, 'Resultado> →' T | Como sprintf, mas chama a função especificada para gerar o resultado. |
printf: TextWriterFormat <'T> →' T | Imprime saída formatada em stdout. |
printfn: TextWriterFormat <'T> →' T | Imprime saída formatada em stdout, adicionando uma nova linha. |
sprintf: StringFormat <'T> →' T | Imprime em uma string usando um buffer de string interno e retorna o resultado como uma string. |
Especificações de formato
As especificações de formato são usadas para formatar a entrada ou saída, de acordo com a necessidade do programador.
Estas são strings com marcadores% indicando espaços reservados de formato.
A sintaxe de um espaço reservado para formato é -
%[flags][width][.precision][type]
o type é interpretado como -
Tipo | Descrição |
---|---|
% b | Formatos a bool, formatado como true ou false. |
% c | Formata um personagem. |
% s | Formatos a string, formatado como seu conteúdo, sem interpretar nenhum caractere de escape. |
% d,% i | Formata qualquer tipo de inteiro básico formatado como um inteiro decimal, com sinal se o tipo de inteiro básico for assinado. |
%você | Formata qualquer tipo de inteiro básico formatado como um inteiro decimal sem sinal. |
% x | Formata qualquer tipo de inteiro básico formatado como um inteiro hexadecimal sem sinal, usando letras minúsculas de a a f. |
% X | Formata qualquer tipo de inteiro básico formatado como um inteiro hexadecimal sem sinal, usando letras maiúsculas de A a F. |
% o | Formata qualquer tipo de inteiro básico formatado como um inteiro octal sem sinal. |
% e,% E,% f,% F,% g,% G | Formata qualquer tipo básico de ponto flutuante (float, float32) formatado usando especificações de formato de ponto flutuante de estilo C. |
% e,% E | Formata um valor com sinal no formato [-] d.dddde [sinal] ddd onde d é um único dígito decimal, dddd é um ou mais dígitos decimais, ddd é exatamente três dígitos decimais e o sinal é + ou -. |
% f | Formata um valor com sinal no formato [-] dddd.dddd, onde dddd é um ou mais dígitos decimais. O número de dígitos antes do ponto decimal depende da magnitude do número, e o número de dígitos depois do ponto decimal depende da precisão solicitada. |
% g,% G | Formata um valor com sinal impresso no formato f ou e, o que for mais compacto para o valor e a precisão fornecidos. |
% M | Formata um valor decimal. |
% O | Formata qualquer valor, impresso encaixotando o objeto e usando seu ToString método. |
% A,% + A | Formata qualquer valor, impresso com as configurações de layout padrão. Use% + A para imprimir a estrutura de sindicatos discriminados com representações internas e privadas. |
%uma | Um especificador de formato geral requer dois argumentos. O primeiro argumento é uma função que aceita dois argumentos: primeiro, um parâmetro de contexto do tipo apropriado para a função de formatação fornecida (por exemplo, um TextWriter) e, segundo, um valor a ser impresso e que produz ou retorna o texto apropriado. O segundo argumento é o valor específico a ser impresso. |
% t | Um especificador de formato geral requer um argumento: uma função que aceita um parâmetro de contexto do tipo apropriado para a função de formatação fornecida (aTextWriter) e que produz ou retorna o texto apropriado. Tipos inteiros básicos sãobyte, sbyte, int16, uint16, int32, uint32, int64, uint64, nativeint, e unativeint. Tipos básicos de ponto flutuante são float e float32. |
o widthé um parâmetro opcional. É um número inteiro que indica a largura mínima do resultado. Por exemplo,% 5d imprime um número inteiro com pelo menos espaços de 5 caracteres.
Válido flags são descritos na tabela a seguir -
Valor | Descrição |
---|---|
0 | Especifica a adição de zeros em vez de espaços para completar a largura necessária. |
- | Especifica que o resultado deve ser justificado à esquerda dentro da largura especificada. |
+ | Especifica a adição de um caractere + se o número for positivo (para corresponder a um sinal - para números negativos). |
'' (espaço) | Especifica adicionar um espaço extra se o número for positivo (para corresponder a um sinal - para números negativos). |
# | Inválido. |
Exemplo
printf "Hello "
printf "World"
printfn ""
printfn "Hello "
printfn "World"
printf "Hi, I'm %s and I'm a %s" "Rohit" "Medical Student"
printfn "d: %f" 212.098f
printfn "e: %f" 504.768f
printfn "x: %g" 212.098f
printfn "y: %g" 504.768f
printfn "x: %e" 212.098f
printfn "y: %e" 504.768f
printfn "True: %b" true
Quando você compila e executa o programa, ele produz a seguinte saída -
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
A classe do console
Esta classe faz parte da estrutura .NET. Ele representa a entrada, saída e fluxos de erro padrão para aplicativos de console.
Ele fornece vários métodos de leitura e gravação no console. A tabela a seguir mostra os métodos -
Método | Descrição |
---|---|
Bip() | Reproduz o som de um bipe pelo alto-falante do console. |
Beep (Int32, Int32) | Reproduz o som de um bipe de frequência e duração especificadas pelo alto-falante do console. |
Claro | Limpa o buffer do console e a janela do console correspondente das informações de exibição. |
MoveBufferArea (Int32, Int32, Int32, Int32, Int32, Int32) | Copia uma área de origem especificada do buffer de tela para uma área de destino especificada. |
MoveBufferArea (Int32, Int32, Int32, Int32, Int32, Int32, Char, ConsoleColor, ConsoleColor) | Copia uma área de origem especificada do buffer de tela para uma área de destino especificada. |
OpenStandardError () | Adquire o fluxo de erro padrão. |
OpenStandardError (Int32) | Adquire o fluxo de erro padrão, que é definido para um tamanho de buffer especificado. |
OpenStandardInput () | Adquire o fluxo de entrada padrão. |
OpenStandardInput (Int32) | Adquire o fluxo de entrada padrão, que é definido para um tamanho de buffer especificado. |
OpenStandardOutput () | Adquire o fluxo de saída padrão. |
OpenStandardOutput (Int32) | Adquire o fluxo de saída padrão, que é definido para um tamanho de buffer especificado. |
Ler | Lê o próximo caractere do fluxo de entrada padrão. |
Chave de leitura() | Obtém o próximo caractere ou tecla de função pressionada pelo usuário. A tecla pressionada é exibida na janela do console. |
ReadKey (booleano) | Obtém o próximo caractere ou tecla de função pressionada pelo usuário. A tecla pressionada é opcionalmente exibida na janela do console. |
Leia a linha | Lê a próxima linha de caracteres do fluxo de entrada padrão. |
ResetColor | Define as cores do console do primeiro plano e do plano de fundo para seus padrões. |
SetBufferSize | Define a altura e largura da área de buffer da tela para os valores especificados. |
SetCursorPosition | Define a posição do cursor. |
SetError | Define a propriedade Error para o objeto TextWriter especificado . |
SetIn | Define a propriedade In para o objeto TextReader especificado . |
Estabelecer | Define a propriedade Out para o objeto TextWriter especificado . |
SetWindowPosition | Define a posição da janela do console em relação ao buffer da tela. |
SetWindowSize | Define a altura e largura da janela do console para os valores especificados. |
Write (booleano) | Grava a representação de texto do valor booleano especificado no fluxo de saída padrão. |
Write (Char) | Grava o valor do caractere Unicode especificado no fluxo de saída padrão. |
Write (Char []) | Grava a matriz especificada de caracteres Unicode no fluxo de saída padrão. |
Escrever (decimal) | Grava a representação de texto do valor decimal especificado no fluxo de saída padrão. |
Escrever (duplo) | Grava a representação de texto do valor de ponto flutuante de precisão dupla especificado no fluxo de saída padrão. |
Write (Int32) | Grava a representação de texto do valor inteiro assinado de 32 bits especificado no fluxo de saída padrão. |
Write (Int64) | Grava a representação de texto do valor inteiro assinado de 64 bits especificado no fluxo de saída padrão. |
Write (Object) | Grava a representação de texto do objeto especificado no fluxo de saída padrão. |
Write (Single) | Grava a representação de texto do valor de ponto flutuante de precisão única especificado no fluxo de saída padrão. |
Write (String) | Grava o valor da string especificada no fluxo de saída padrão. |
Write (UInt32) | Grava a representação de texto do valor inteiro não assinado de 32 bits especificado no fluxo de saída padrão. |
Write (UInt64) | Grava a representação de texto do valor inteiro não assinado de 64 bits especificado no fluxo de saída padrão. |
Write (String, Object) | Grava a representação de texto do objeto especificado no fluxo de saída padrão usando as informações de formato especificado. |
Write (String, Object []) | Grava a representação de texto da matriz especificada de objetos no fluxo de saída padrão usando as informações de formato especificado. |
Write (Char [], Int32, Int32) | Grava o subarray especificado de caracteres Unicode no fluxo de saída padrão. |
Write (String, Object, Object) | Grava a representação de texto dos objetos especificados no fluxo de saída padrão usando as informações de formato especificado. |
Write (String, Object, Object, Object) | Grava a representação de texto dos objetos especificados no fluxo de saída padrão usando as informações de formato especificado. |
Write (String, Object, Object, Object, Object) | Grava a representação de texto dos objetos especificados e a lista de parâmetros de comprimento variável no fluxo de saída padrão usando as informações de formato especificado. |
WriteLine () | Grava o terminador de linha atual no fluxo de saída padrão. |
WriteLine (booleano) | Grava a representação de texto do valor booleano especificado, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (Char) | Grava o caractere Unicode especificado, seguido pelo terminador de linha atual, valor para o fluxo de saída padrão. |
WriteLine (Char []) | Grava a matriz especificada de caracteres Unicode, seguida pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (decimal) | Grava a representação de texto do valor decimal especificado, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (duplo) | Grava a representação de texto do valor de ponto flutuante de precisão dupla especificado, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (Int32) | Grava a representação de texto do valor inteiro assinado de 32 bits especificado, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (Int64) | Grava a representação de texto do valor inteiro assinado de 64 bits especificado, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (objeto) | Grava a representação de texto do objeto especificado, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (individual) | Grava a representação de texto do valor de ponto flutuante de precisão única especificado, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (String) | Grava o valor da string especificada, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (UInt32) | Grava a representação de texto do valor inteiro não assinado de 32 bits especificado, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (UInt64) | Grava a representação de texto do valor inteiro não assinado de 64 bits especificado, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (String, Object) | Grava a representação de texto do objeto especificado, seguido pelo terminador de linha atual, no fluxo de saída padrão usando as informações de formato especificado. |
WriteLine (String, Object []) | Grava a representação de texto da matriz especificada de objetos, seguida pelo terminador de linha atual, no fluxo de saída padrão usando as informações de formato especificado. |
WriteLine (Char [], Int32, Int32) | Grava o subarray especificado de caracteres Unicode, seguido pelo terminador de linha atual, no fluxo de saída padrão. |
WriteLine (String, Object, Object) | Grava a representação de texto dos objetos especificados, seguido pelo terminador de linha atual, no fluxo de saída padrão usando as informações de formato especificado. |
WriteLine (String, Object, Object, Object) | Grava a representação de texto dos objetos especificados, seguido pelo terminador de linha atual, no fluxo de saída padrão usando as informações de formato especificado. |
WriteLine (String, Object, Object, Object, Object) | Grava a representação de texto dos objetos especificados e da lista de parâmetros de comprimento variável, seguida pelo terminador de linha atual, no fluxo de saída padrão usando as informações de formato especificado. |
O exemplo a seguir demonstra a leitura do console e a escrita nele -
Exemplo
open System
let main() =
Console.Write("What's your name? ")
let name = Console.ReadLine()
Console.Write("Hello, {0}\n", name)
Console.WriteLine(System.String.Format("Big Greetings from {0} and {1}", "TutorialsPoint", "Absoulte Classes"))
Console.WriteLine(System.String.Format("|{0:yyyy-MMM-dd}|", System.DateTime.Now))
main()
Quando você compila e executa o programa, ele produz a seguinte saída -
What's your name? Kabir
Hello, Kabir
Big Greetings from TutorialsPoint and Absoulte Classes
|2015-Jan-05|
O namespace System.IO
O namespace System.IO contém uma variedade de classes úteis para realizar E / S básicas.
Ele contém tipos ou classes que permitem a leitura e gravação em arquivos e fluxos de dados e tipos que fornecem suporte básico a arquivos e diretórios.
Aulas úteis para trabalhar com o sistema de arquivos -
- A classe System.IO.File é usada para criar, anexar e excluir arquivos.
- A classe System.IO.Directory é usada para criar, mover e excluir diretórios.
- A classe System.IO.Path executa operações em strings, que representam caminhos de arquivo.
- A classe System.IO.FileSystemWatcher permite que os usuários ouçam alterações em um diretório.
Classes úteis para trabalhar com os streams (sequência de bytes) -
- A classe System.IO.StreamReader é usada para ler caracteres de um fluxo.
- A classe System.IO.StreamWriter é usada para gravar caracteres em um fluxo.
- A classe System.IO.MemoryStream cria um fluxo de bytes na memória.
A tabela a seguir mostra todas as classes fornecidas no namespace junto com uma breve descrição -
Classe | Descrição |
---|---|
BinaryReader | Lê tipos de dados primitivos como valores binários em uma codificação específica. |
BinaryWriter | Grava tipos primitivos em binário em um fluxo e oferece suporte à gravação de strings em uma codificação específica. |
BufferedStream | Adiciona uma camada de buffer para ler e gravar operações em outro fluxo. |
Diretório | Expõe métodos estáticos para criar, mover e enumerar por meio de diretórios e subdiretórios. |
DirectoryInfo | Expõe métodos de instância para criar, mover e enumerar por meio de diretórios e subdiretórios. |
DirectoryNotFoundException | A exceção que é lançada quando parte de um arquivo ou diretório não pode ser encontrada. |
DriveInfo | Fornece acesso às informações sobre uma unidade. |
DriveNotFoundException | A exceção que é lançada ao tentar acessar uma unidade ou compartilhamento que não está disponível. |
EndOfStreamException | A exceção que é lançada quando a leitura é tentada após o final de um fluxo. |
ErrorEventArgs | Fornece dados para o evento FileSystemWatcher.Error. |
Arquivo | Fornece métodos estáticos para a criação, cópia, exclusão, movimentação e abertura de um único arquivo e ajuda na criação de objetos FileStream. |
FileFormatException | A exceção que é lançada quando um arquivo de entrada ou um fluxo de dados que deveria estar em conformidade com uma determinada especificação de formato de arquivo está malformado. |
Informações do arquivo | Fornece propriedades e métodos de instância para a criação, cópia, exclusão, movimentação e abertura de arquivos e ajuda na criação de objetos FileStream. |
FileLoadException | A exceção que é lançada quando um assembly gerenciado é encontrado, mas não pode ser carregado. |
FileNotFoundException | A exceção que é lançada quando uma tentativa de acessar um arquivo que não existe no disco falha. |
FileStream | Expõe um fluxo em torno de um arquivo, suportando operações de leitura e gravação síncronas e assíncronas. |
FileSystemEventArgs | Provides data for the directory events − Changed, Created, Deleted. |
FileSystemInfo | Provides the base class for both FileInfo and DirectoryInfo objects. |
FileSystemWatcher | Listens to the file system change notifications and raises events when a directory, or file in a directory, changes. |
InternalBufferOverflowException | The exception thrown when the internal buffer overflows. |
InvalidDataException | The exception that is thrown when a data stream is in an invalid format. |
IODescriptionAttribute | Sets the description visual designers can display when referencing an event, extender, or property. |
IOException | The exception that is thrown when an I/O error occurs. |
MemoryStream | Creates a stream whose backing store is memory. |
Path | Performs operations on String instances that contain file or directory path information. These operations are performed in a cross-platform manner. |
PathTooLongException | The exception that is thrown when a path or file name is longer than the system-defined maximum length. |
PipeException | Thrown when an error occurs within a named pipe. |
RenamedEventArgs | Provides data for the Renamed event. |
Stream | Provides a generic view of a sequence of bytes. This is an abstract class. |
StreamReader | Implements a TextReader that reads characters from a byte stream in a particular encoding. |
StreamWriter | Implements a TextWriter for writing characters to a stream in a particular encoding. To browse the .NET Framework source code for this type, see the Reference Source. |
StringReader | Implements a TextReader that reads from a string. |
StringWriter | Implements a TextWriter for writing information to a string. The information is stored in an underlying StringBuilder. |
TextReader | Represents a reader that can read a sequential series of characters. |
TextWriter | Represents a writer that can write a sequential series of characters. This class is abstract. |
UnmanagedMemoryAccessor | Provides random access to unmanaged blocks of memory from managed code. |
UnmanagedMemoryStream | Provides access to unmanaged blocks of memory from managed code. |
WindowsRuntimeStorageExtensions | Contains extension methods for the IStorageFile and IStorageFolder interfaces in the Windows Runtime when developing Windows Store apps. |
WindowsRuntimeStreamExtensions | Contains extension methods for converting between streams in the Windows Runtime and managed streams in the .NET for Windows Store apps. |
Example
The following example creates a file called test.txt, writes a message there, reads the text from the file and prints it on the console.
Note − The amount of code needed to do this is surprisingly less!
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
When you compile and execute the program, it yields the following output −
Hello There
Welcome to:
Tutorials Point
Generics allow you to delay the specification of the data type of programming elements in a class or a method, until it is actually used in the program. In other words, generics allow you to write a class or method that can work with any data type.
You write the specifications for the class or the method, with substitute parameters for data types. When the compiler encounters a constructor for the class or a function call for the method, it generates code to handle the specific data type.
In F#, function values, methods, properties, and aggregate types such as classes, records, and discriminated unions can be generic.
Generic constructs contain at least one type parameter. Generic functions and types enable you to write code that works with a variety of types without repeating the code for each type.
Syntax
Syntax for writing a generic construct is as follows −
// 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
Examples
(* Generic Function *)
let printFunc<'T> x y =
printfn "%A, %A" x y
printFunc<float> 10.0 20.0
When you compile and execute the program, it yields the following output −
10.0, 20.0
You can also make a function generic by using the single quotation mark syntax −
(* Generic Function *)
let printFunction (x: 'a) (y: 'a) =
printfn "%A %A" x y
printFunction 10.0 20.0
When you compile and execute the program, it yields the following output −
10.0 20.0
Please note that when you use generic functions or methods, you might not have to specify the type arguments. However, in case of an ambiguity, you can provide type arguments in angle brackets as we did in the first example.
If you have more than one type, then you separate multiple type arguments with commas.
Generic Class
Like generic functions, you can also write generic classes. The following example demonstrates this −
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) } )
When you compile and execute the program, it yields the following output −
"zara"
seq [(1, 1); (2, 4); (3, 9); (4, 16); ...]
A delegate is a reference type variable that holds the reference to a method. The reference can be changed at runtime. F# delegates are similar to pointers to functions, in C or C++.
Declaring Delegates
Delegate declaration determines the methods that can be referenced by the delegate. A delegate can refer to a method, which have the same signature as that of the delegate.
Syntax for delegate declaration is −
type delegate-typename = delegate of type1 -> type2
For example, consider the delegates −
// Delegate1 works with tuple arguments.
type Delegate1 = delegate of (int * int) -> int
// Delegate2 works with curried arguments.
type Delegate2 = delegate of int * int -> int
Both the delegates can be used to reference any method that has two int parameters and returns an int type variable.
In the syntax −
type1 represents the argument type(s).
type2 represents the return type.
Please note −
The argument types are automatically curried.
Delegates can be attached to function values, and static or instance methods.
F# function values can be passed directly as arguments to delegate constructors.
For a static method the delegate is called by using the name of the class and the method. For an instance method, the name of the object instance and method is used.
The Invoke method on the delegate type calls the encapsulated function.
Also, delegates can be passed as function values by referencing the Invoke method name without the parentheses.
The following example demonstrates the concept −
Example
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)
When you compile and execute the program, it yields the following output −
400 + 200 = 600
400 - 200 = 200
400 + 200 = 600
400 - 200 = 200
100 + 45 = 145
100 - 45 = 55
100 + 45 = 145
100 - 45 = 55
An enumeration is a set of named integer constants.
In F#, enumerations, also known as enums, are integral types where labels are assigned to a subset of the values. You can use them in place of literals to make code more readable and maintainable.
Declaring Enumerations
The general syntax for declaring an enumeration is −
type enum-name =
| value1 = integer-literal1
| value2 = integer-literal2
...
The following example demonstrates the use of enumerations −
Example
// 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
When you compile and execute the program, it yields the following output −
Monday: Mon
Saturday: Sat
Sunday: Sun
Pattern matching allows you to “compare data with a logical structure or structures, decompose data into constituent parts, or extract information from data in various ways”.
In other terms, it provides a more flexible and powerful way of testing data against a series of conditions and performing some computations based on the condition met.
Conceptually, it is like a series of if… then statements.
Syntax
In high level terms, pattern matching follows this syntax in F# −
match expr with
| pat1 - result1
| pat2 -> result2
| pat3 when expr2 -> result3
| _ -> defaultResult
Where,
- Each | symbol defines a condition.
- The -> symbol means "if the condition is true, return this value...".
- The _ symbol provides the default pattern, meaning that it matches all other things like a wildcard.
Example 1
The following example, calculates the Fibonacci numbers using pattern matching syntax −
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)
When you compile and execute the program, it yields the following output −
Fibonacci 1: 1
Fibonacci 2: 1
Fibonacci 3: 2
Fibonacci 4: 3
Fibonacci 5: 5
Fibonacci 6: 8
Fibonacci 7: 13
Fibonacci 8: 21
Fibonacci 9: 34
Fibonacci 10: 55
You can also chain together multiple conditions, which return the same value. For example −
Example 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"
When you compile and execute the program, it yields the following output −
Winter
Spring
Autumn
Rainy
Pattern Matching Functions
F# allows you to write pattern matching functions using the function keyword −
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")
When you compile and execute the program, it yields the following output −
10
20.5
21
8.75
15
Adding Filters or Guards to Patterns
You can add filters, or guards, to patterns using the when keyword.
Example 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)
When you compile and execute the program, it yields the following output −
-1
1
0
Example 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)
When you compile and execute the program, it yields the following output −
11 is less than 25
72 is greater than 10
0 equals 0
Pattern Matching with Tuples
The following example demonstrates the pattern matching with tuples −
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"))
When you compile and execute the program, it yields the following output −
Hello, Zara
Hello, Raman from the department of Computer Sc.
You are not registered into the system
Pattern Matching with Records
The following example demonstrates pattern matching with records −
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 }
When you compile and execute the program, it yields the following output −
Point is at the origin.
Point is on the x-axis. Value is 10.000000.
Point is on the y-axis. Value is 10.000000.
Point is at (10.000000, 10.000000).
An exception is a problem that arises during the execution of a program. An F# exception is a response to an exceptional circumstance that arises while a program is running, such as an attempt to divide by zero.
Exceptions provide a way to transfer control from one part of a program to another. F# exception handling provides the following constructs −
Construct | Description |
---|---|
raise expr | Raises the given exception. |
failwith expr | Raises the System.Exception exception. |
try expr with rules | Catches expressions matching the pattern rules. |
try expr finally expr | Execution the finally expression both when the computation is successful and when an exception is raised. |
| :? ArgumentException | A rule matching the given .NET exception type. |
| :? ArgumentException as e | A rule matching the given .NET exception type, binding the name e to the exception object value. |
| Failure(msg) → expr | A rule matching the given data-carrying F# exception. |
| exn → expr | A rule matching any exception, binding the name exn to the exception object value. |
| exn when expr → expr | A rule matching the exception under the given condition, binding the name exn to the exception object value. |
Let us start with the basic syntax of Exception Handling.
Syntax
Basic syntax for F# exception handling block is −
exception exception-type of argument-type
Where,
exception-type is the name of a new F# exception type.
argument-type represents the type of an argument that can be supplied when you raise an exception of this type.
Multiple arguments can be specified by using a tuple type for argument-type.
o try...with expressão é usada para tratamento de exceções na linguagem F #.
A sintaxe para tentar ... com expressão é -
try
expression1
with
| pattern1 -> expression2
| pattern2 -> expression3
...
o try...finally expression permite que você execute código de limpeza mesmo se um bloco de código lançar uma exceção.
Sintaxe para a tentativa ... finalmente a expressão é -
try
expression1
finally
expression2
o raiseA função é usada para indicar que ocorreu um erro ou condição excepcional. Ele também captura as informações sobre o erro em um objeto de exceção.
A sintaxe para a função de aumento é -
raise (expression)
o failwith função gera uma exceção F #.
A sintaxe para a função failwith é -
failwith error-message-string
o invalidArg função gera uma exceção de argumento.
invalidArg parameter-name error-message-string
Exemplo de tratamento de exceções
Exemplo 1
O programa a seguir mostra o tratamento básico de exceções com uma simples tentativa ... com bloco -
let divisionprog x y =
try
Some (x / y)
with
| :? System.DivideByZeroException -> printfn "Division by zero!"; None
let result1 = divisionprog 100 0
Quando você compila e executa o programa, ele produz a seguinte saída -
Division by zero!
Exemplo 2
F # fornece um exceptiontipo para declarar exceções. Você pode usar um tipo de exceção diretamente nos filtros em umtry...with expressão.
O exemplo a seguir demonstra isso -
exception Error1 of string
// Using a tuple type as the argument type.
exception Error2 of string * int
let myfunction x y =
try
if x = y then raise (Error1("Equal Number Error"))
else raise (Error2("Error Not detected", 100))
with
| Error1(str) -> printfn "Error1 %s" str
| Error2(str, i) -> printfn "Error2 %s %d" str i
myfunction 20 10
myfunction 5 5
Quando você compila e executa o programa, ele produz a seguinte saída -
Error2 Error Not detected 100
Error1 Equal Number Error
Exemplo 3
O exemplo a seguir demonstra o tratamento de exceções aninhadas -
exception InnerError of string
exception OuterError of string
let func1 x y =
try
try
if x = y then raise (InnerError("inner error"))
else raise (OuterError("outer error"))
with
| InnerError(str) -> printfn "Error:%s" str
finally
printfn "From the finally block."
let func2 x y =
try
func1 x y
with
| OuterError(str) -> printfn "Error: %s" str
func2 100 150
func2 100 100
func2 100 120
Quando você compila e executa o programa, ele produz a seguinte saída -
From the finally block.
Error: outer error
Error:inner error
From the finally block.
From the finally block.
Error: outer error
Exemplo 4
A função a seguir demonstra o failwith função -
let divisionFunc x y =
if (y = 0) then failwith "Divisor cannot be zero."
else
x / y
let trydivisionFunc x y =
try
divisionFunc x y
with
| Failure(msg) -> printfn "%s" msg; 0
let result1 = trydivisionFunc 100 0
let result2 = trydivisionFunc 100 4
printfn "%A" result1
printfn "%A" result2
Quando você compila e executa o programa, ele produz a seguinte saída -
Divisor cannot be zero.
0
25
Exemplo 5
o invalidArgfunção gera uma exceção de argumento. O programa a seguir demonstra isso -
let days = [| "Sunday"; "Monday"; "Tuesday"; "Wednesday"; "Thursday"; "Friday"; "Saturday" |]
let findDay day =
if (day > 7 || day < 1)
then invalidArg "day" (sprintf "You have entered %d." day)
days.[day - 1]
printfn "%s" (findDay 1)
printfn "%s" (findDay 5)
printfn "%s" (findDay 9)
Quando você compila e executa o programa, ele produz a seguinte saída -
Sunday
Thursday
Unhandled Exception:
System.ArgumentException: You have entered 9.
…
Algumas outras informações sobre o arquivo e a variável que causam o erro no sistema também serão exibidas, dependendo do sistema.
Classes são tipos que representam objetos que podem ter propriedades, métodos e eventos. 'Eles são usados para modelar ações, processos e quaisquer entidades conceituais em aplicativos'.
Sintaxe
A sintaxe para definir um tipo de classe é a seguinte -
// 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 ...
...
Onde,
o type-nameé qualquer identificador válido. O modificador de acesso padrão para isso épublic.
o type-params descreve parâmetros opcionais de tipo genérico.
o parameter-listdescreve os parâmetros do construtor. O modificador de acesso padrão para o construtor primário épublic.
o identifier usado com o opcional as palavra-chave dá um nome para a variável de instância, ou self-identifier, que pode ser usado na definição de tipo para se referir à instância do tipo.
o inherit palavra-chave permite que você especifique a classe base para uma classe.
o let as ligações permitem declarar campos ou valores de função locais para a classe.
o do-bindings seção inclui o código a ser executado na construção do objeto.
o member-list consiste em construtores adicionais, declarações de instância e métodos estáticos, declarações de interface, ligações abstratas e declarações de propriedade e evento.
As palavras-chave class e end que marcam o início e o fim da definição são opcionais.
Construtor de uma classe
O construtor é o código que cria uma instância do tipo de classe.
Em F #, os construtores funcionam um pouco diferente de outras linguagens .Net. Na definição da classe, os argumentos do construtor primário são descritos como lista de parâmetros.
O corpo do construtor consiste no let e do ligações.
Você pode adicionar construtores adicionais usando a nova palavra-chave para adicionar um membro -
new (argument-list) = constructor-body
O exemplo a seguir ilustra o conceito -
Exemplo
O programa a seguir cria uma classe de linha junto com um construtor que calcula o comprimento da linha enquanto um objeto da classe é criado -
type Line = class
val X1 : float
val Y1 : float
val X2 : float
val Y2 : float
new (x1, y1, x2, y2) as this =
{ X1 = x1; Y1 = y1; X2 = x2; Y2 = y2;}
then
printfn " Creating Line: {(%g, %g), (%g, %g)}\nLength: %g"
this.X1 this.Y1 this.X2 this.Y2 this.Length
member x.Length =
let sqr x = x * x
sqrt(sqr(x.X1 - x.X2) + sqr(x.Y1 - x.Y2) )
end
let aLine = new Line(1.0, 1.0, 4.0, 5.0)
Quando você compila e executa o programa, ele produz a seguinte saída -
Creating Line: {(1, 1), (4, 5)}
Length: 5
Let Bindings
As ligações let em uma definição de classe permitem definir campos privados e funções privadas para classes F #.
type Greetings(name) as gr =
let data = name
do
gr.PrintMessage()
member this.PrintMessage() =
printf "Hello %s\n" data
let gtr = new Greetings("Zara")
Quando você compila e executa o programa, ele produz a seguinte saída -
Hello Zara
Observe o uso do auto-identificador gr para a classe Saudações .
Uma estrutura em F # é um tipo de dados de tipo de valor. Isso ajuda você a fazer uma única variável, manter dados relacionados de vários tipos de dados. ostruct palavra-chave é usada para criar uma estrutura.
Sintaxe
A sintaxe para definir uma estrutura é a seguinte -
[ attributes ]
type [accessibility-modifier] type-name =
struct
type-definition-elements
end
// or
[ attributes ]
[<StructAttribute>]
type [accessibility-modifier] type-name =
type-definition-elements
Existem duas sintaxes. A primeira sintaxe é mais usada, porque, se você usar ostruct e end palavras-chave, você pode omitir o StructAttribute atributo.
Os elementos de definição de estrutura fornecem -
- Declarações e definições dos membros.
- Construtores e campos mutáveis e imutáveis.
- Membros e implementações de interface.
Ao contrário das classes, as estruturas não podem ser herdadas e não podem conter let ou do bindings. Desde então, as estruturas não têm ligações let; você deve declarar campos em estruturas usando oval palavra-chave.
Quando você define um campo e seu tipo usando valpalavra-chave, você não pode inicializar o valor do campo, em vez disso, eles são inicializados para zero ou nulo. Portanto, para uma estrutura com um construtor implícito, oval declarações sejam anotadas com o DefaultValue atributo.
Exemplo
O programa a seguir cria uma estrutura de linha junto com um construtor. O programa calcula o comprimento de uma linha usando a estrutura -
type Line = struct
val X1 : float
val Y1 : float
val X2 : float
val Y2 : float
new (x1, y1, x2, y2) =
{X1 = x1; Y1 = y1; X2 = x2; Y2 = y2;}
end
let calcLength(a : Line)=
let sqr a = a * a
sqrt(sqr(a.X1 - a.X2) + sqr(a.Y1 - a.Y2) )
let aLine = new Line(1.0, 1.0, 4.0, 5.0)
let length = calcLength aLine
printfn "Length of the Line: %g " length
Quando você compila e executa o programa, ele produz a seguinte saída -
Length of the Line: 5
Você pode redefinir ou sobrecarregar a maioria dos operadores integrados disponíveis no F #. Assim, um programador também pode usar operadores com tipos definidos pelo usuário.
Operadores são funções com nomes especiais entre colchetes. Eles devem ser definidos como membros de classe estáticos. Como qualquer outra função, um operador sobrecarregado tem um tipo de retorno e uma lista de parâmetros.
O exemplo a seguir mostra um operador + em números complexos -
//overloading + operator
static member (+) (a : Complex, b: Complex) =
Complex(a.x + b.x, a.y + b.y)
A função acima implementa o operador de adição (+) para uma classe Complex definida pelo usuário. Ele adiciona os atributos de dois objetos e retorna o objeto Complex resultante.
Implementação de Sobrecarga do Operador
O programa a seguir mostra a implementação completa -
//implementing a complex class with +, and - operators
//overloaded
type Complex(x: float, y : float) =
member this.x = x
member this.y = y
//overloading + operator
static member (+) (a : Complex, b: Complex) =
Complex(a.x + b.x, a.y + b.y)
//overloading - operator
static member (-) (a : Complex, b: Complex) =
Complex(a.x - b.x, a.y - b.y)
// overriding the ToString method
override this.ToString() =
this.x.ToString() + " " + this.y.ToString()
//Creating two complex numbers
let c1 = Complex(7.0, 5.0)
let c2 = Complex(4.2, 3.1)
// addition and subtraction using the
//overloaded operators
let c3 = c1 + c2
let c4 = c1 - c2
//printing the complex numbers
printfn "%s" (c1.ToString())
printfn "%s" (c2.ToString())
printfn "%s" (c3.ToString())
printfn "%s" (c4.ToString())
Quando você compila e executa o programa, ele produz a seguinte saída -
7 5
4.2 3.1
11.2 8.1
2.8 1.9
Um dos conceitos mais importantes na programação orientada a objetos é o de herança. A herança nos permite definir uma classe em termos de outra classe, o que torna mais fácil criar e manter um aplicativo. Isso também fornece uma oportunidade de reutilizar a funcionalidade do código e tempo de implementação rápido.
Ao criar uma classe, em vez de escrever membros de dados e funções de membro completamente novos, o programador pode designar que a nova classe deve herdar os membros de uma classe existente. Essa classe existente é chamada de classe base e a nova classe é chamada de classe derivada.
A ideia de herança implementa o relacionamento IS-A. Por exemplo, o mamífero É um animal, o cão é um mamífero, portanto, o cão também é um animal e assim por diante.
Classe Base e Subclasse
Uma subclasse é derivada de uma classe base, que já está definida. Uma subclasse herda os membros da classe base, bem como tem seus próprios membros.
Uma subclasse é definida usando o inherit palavra-chave conforme mostrado abaixo -
type MyDerived(...) =
inherit MyBase(...)
Em F #, uma classe pode ter no máximo uma classe base direta. Se você não especificar uma classe base usando oinherit palavra-chave, a classe herda implicitamente de Object.
Observe -
Os métodos e membros da classe base estão disponíveis para usuários da classe derivada como os membros diretos da classe derivada.
Deixe que as ligações e os parâmetros do construtor sejam privados para uma classe e, portanto, não podem ser acessados de classes derivadas.
A palavra-chave baserefere-se à instância da classe base. Ele é usado como o auto-identificador.
Exemplo
type Person(name) =
member x.Name = name
member x.Greet() = printfn "Hi, I'm %s" x.Name
type Student(name, studentID : int) =
inherit Person(name)
let mutable _GPA = 0.0
member x.StudentID = studentID
member x.GPA
with get() = _GPA
and set value = _GPA <- value
type Teacher(name, expertise : string) =
inherit Person(name)
let mutable _salary = 0.0
member x.Salary
with get() = _salary
and set value = _salary <- value
member x.Expertise = expertise
//using the subclasses
let p = new Person("Mohan")
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")
p.Greet()
st.Greet()
tr.Greet()
Quando você compila e executa o programa, ele produz a seguinte saída -
Hi, I'm Mohan
Hi, I'm Zara
Hi, I'm Mariam
Métodos de substituição
Você pode substituir um comportamento padrão de um método da classe base e implementá-lo de maneira diferente na subclasse ou na classe derivada.
Os métodos em F # não podem ser substituídos por padrão.
Para substituir métodos em uma classe derivada, você deve declarar seu método como substituível usando o abstract e default palavras-chave da seguinte forma -
type Person(name) =
member x.Name = name
abstract Greet : unit -> unit
default x.Greet() = printfn "Hi, I'm %s" x.Name
Agora, o método Greet da classe Person pode ser substituído nas classes derivadas. O exemplo a seguir demonstra isso -
Exemplo
type Person(name) =
member x.Name = name
abstract Greet : unit -> unit
default x.Greet() = printfn "Hi, I'm %s" x.Name
type Student(name, studentID : int) =
inherit Person(name)
let mutable _GPA = 0.0
member x.StudentID = studentID
member x.GPA
with get() = _GPA
and set value = _GPA <- value
override x.Greet() = printfn "Student %s" x.Name
type Teacher(name, expertise : string) =
inherit Person(name)
let mutable _salary = 0.0
member x.Salary
with get() = _salary
and set value = _salary <- value
member x.Expertise = expertise
override x.Greet() = printfn "Teacher %s." x.Name
//using the subclasses
let p = new Person("Mohan")
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")
//default Greet
p.Greet()
//Overriden Greet
st.Greet()
tr.Greet()
Quando você compila e executa o programa, ele produz a seguinte saída -
Hi, I'm Mohan
Student Zara
Teacher Mariam.
Classe Abstrata
Às vezes, você precisa fornecer uma implementação incompleta de um objeto, que não deveria ser implementada na realidade. Posteriormente, algum outro programador deve criar subclasses da classe abstrata para uma implementação completa.
Por exemplo, a classe Person não será necessária em um Sistema de Gestão Escolar. No entanto, a classe Aluno ou Professor será necessária. Nesses casos, você pode declarar a classe Person como uma classe abstrata.
o AbstractClass atributo diz ao compilador que a classe possui alguns membros abstratos.
Você não pode criar uma instância de uma classe abstrata porque a classe não está totalmente implementada.
O exemplo a seguir demonstra isso -
Exemplo
[<AbstractClass>]
type Person(name) =
member x.Name = name
abstract Greet : unit -> unit
type Student(name, studentID : int) =
inherit Person(name)
let mutable _GPA = 0.0
member x.StudentID = studentID
member x.GPA
with get() = _GPA
and set value = _GPA <- value
override x.Greet() = printfn "Student %s" x.Name
type Teacher(name, expertise : string) =
inherit Person(name)
let mutable _salary = 0.0
member x.Salary
with get() = _salary
and set value = _salary <- value
member x.Expertise = expertise
override x.Greet() = printfn "Teacher %s." x.Name
let st = new Student("Zara", 1234)
let tr = new Teacher("Mariam", "Java")
//Overriden Greet
st.Greet()
tr.Greet()
Quando você compila e executa o programa, ele produz a seguinte saída -
Student Zara
Teacher Mariam.
As interfaces fornecem uma maneira abstrata de escrever os detalhes de implementação de uma classe. É um modelo que declara os métodos que a classe deve implementar e expor publicamente.
Sintaxe
Uma interface especifica os conjuntos de membros relacionados que outras classes implementam. Possui a seguinte sintaxe -
// 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
Observe -
Em uma declaração de interface, os membros não são implementados.
Os membros são abstratos, declarados pelo abstractpalavra-chave. No entanto, você pode fornecer uma implementação padrão usando odefault palavra-chave.
Você pode implementar interfaces usando expressões de objeto ou tipos de classe.
Na implementação de classe ou objeto, você precisa fornecer corpos de método para métodos abstratos da interface.
As palavras-chave interface e end, que marcam o início e o fim da definição, são opcionais.
Por exemplo,
type IPerson =
abstract Name : string
abstract Enter : unit -> unit
abstract Leave : unit -> unit
Métodos de interface de chamada
Os métodos de interface são chamados por meio da interface, não por meio da instância da classe ou interface de implementação de tipo. Para chamar um método de interface, você elimina o tipo de interface usando o:> operador (operador upcast).
Por exemplo,
(s :> IPerson).Enter()
(s :> IPerson).Leave()
O exemplo a seguir ilustra o conceito -
Exemplo
type IPerson =
abstract Name : string
abstract Enter : unit -> unit
abstract Leave : unit -> unit
type Student(name : string, id : int) =
member this.ID = id
interface IPerson with
member this.Name = name
member this.Enter() = printfn "Student entering premises!"
member this.Leave() = printfn "Student leaving premises!"
type StuffMember(name : string, id : int, salary : float) =
let mutable _salary = salary
member this.Salary
with get() = _salary
and set(value) = _salary <- value
interface IPerson with
member this.Name = name
member this.Enter() = printfn "Stuff member entering premises!"
member this.Leave() = printfn "Stuff member leaving premises!"
let s = new Student("Zara", 1234)
let st = new StuffMember("Rohit", 34, 50000.0)
(s :> IPerson).Enter()
(s :> IPerson).Leave()
(st :> IPerson).Enter()
(st :> IPerson).Leave()
Quando você compila e executa o programa, ele produz a seguinte saída -
Student entering premises!
Student leaving premises!
Stuff member entering premises!
Stuff member leaving premises!
Herança de interface
As interfaces podem herdar de uma ou mais interfaces básicas.
O exemplo a seguir mostra o conceito -
type Interface1 =
abstract member doubleIt: int -> int
type Interface2 =
abstract member tripleIt: int -> int
type Interface3 =
inherit Interface1
inherit Interface2
abstract member printIt: int -> string
type multiplierClass() =
interface Interface3 with
member this.doubleIt(a) = 2 * a
member this.tripleIt(a) = 3 * a
member this.printIt(a) = a.ToString()
let ml = multiplierClass()
printfn "%d" ((ml:>Interface3).doubleIt(5))
printfn "%d" ((ml:>Interface3).tripleIt(5))
printfn "%s" ((ml:>Interface3).printIt(5))
Quando você compila e executa o programa, ele produz a seguinte saída -
10
15
5
Os eventos permitem que as turmas enviem e recebam mensagens entre si.
Na GUI, os eventos são ações do usuário como pressionamento de tecla, cliques, movimentos do mouse, etc., ou alguma ocorrência como notificações geradas pelo sistema. Os aplicativos precisam responder aos eventos quando eles ocorrem. Por exemplo, interrupções. Os eventos são usados para comunicação entre processos.
Os objetos comunicam-se uns com os outros por meio da passagem síncrona de mensagens.
Os eventos são anexados a outras funções; registro de objetoscallback funções para um evento, e esses retornos de chamada são executados quando (e se) o evento é disparado por algum objeto.
A classe de evento e o módulo de evento
A classe Control.Event <'T> ajuda na criação de um objeto ou evento observável.
Tem os seguintes membros de instância para trabalhar com os eventos -
Membro | Descrição |
---|---|
Publicar | Publica uma observação como um valor de primeira classe. |
Desencadear | Dispara uma observação usando os parâmetros fornecidos. |
O Módulo Control.Event fornece funções para gerenciar fluxos de eventos -
Valor | Descrição |
---|---|
adicione: ('T → unidade) → Evento <' Del, 'T> → unidade | Executa a função fornecida sempre que um determinado evento é disparado. |
escolha: ('T →' opção U) → IEvent <'Del,' T> → IEvent <'U> | Retorna um novo evento que dispara em uma seleção de mensagens do evento original. A função de seleção leva uma mensagem original a uma nova mensagem opcional. |
filtro: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> | Retorna um novo evento que escuta o evento original e dispara o evento resultante apenas quando o argumento para o evento passa pela função fornecida. |
mapa: ('T →' U) → IEvent <'Del,' T> → IEvent <'U> | Retorna um novo evento que passa valores transformados pela função fornecida. |
mesclar: IEvent <'Del1,' T> → IEvent <'Del2,' T> → IEvent <'T> | Dispara o evento de saída quando um dos eventos de entrada é disparado. |
em pares: IEvent <'Del,' T> → IEvent <'T *' T> | Retorna um novo evento que dispara no segundo disparo e nos subsequentes do evento de entrada. oNth o acionamento do evento de entrada passa os argumentos do N-1th e Nthdesencadeando como um par. O argumento passou para oN-1th o acionamento é mantido em estado interno oculto até que o Nth o acionamento ocorre. |
partição: ('T → bool) → IEvent <' Del, 'T> → IEvent <' T> * IEvent <'T> | Retorna um novo evento que escuta o evento original e dispara o primeiro evento resultante se a aplicação do predicado aos argumentos do evento retornou verdadeiro, e o segundo evento se retornou falso. |
varredura: ('U →' T → 'U) →' U → IEvent <'Del,' T> → IEvent <'U> | Retorna um novo evento que consiste nos resultados da aplicação da função de acumulação fornecida a valores sucessivos acionados no evento de entrada. Um item de estado interno registra o valor atual do parâmetro de estado. O estado interno não é bloqueado durante a execução da função de acumulação, portanto, deve-se tomar cuidado para que a entrada IEvent não seja acionada por vários threads simultaneamente. |
dividir: ('T → Escolha <' U1, 'U2>) → IEvent <' Del, 'T> → IEvent <' U1> * IEvent <'U2> | Retorna um novo evento que escuta o evento original e dispara o primeiro evento resultante se a aplicação da função aos argumentos do evento retornou um Choice1Of2, e o segundo evento se ele retornou um Choice2Of2. |
Criação de eventos
Os eventos são criados e usados por meio do Eventclasse. O construtor Event é usado para criar um evento.
Exemplo
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
Depois disso, você precisa expor o campo nameChanged como um membro público, para que os ouvintes possam se conectar ao evento para o qual você usa o Publish propriedade do evento -
type Worker(name : string, shift : string) =
let mutable _name = name;
let mutable _shift = shift;
let nameChanged = new Event<unit>() (* creates event *)
let shiftChanged = new Event<unit>() (* creates event *)
member this.NameChanged = nameChanged.Publish (* exposed event handler *)
member this.ShiftChanged = shiftChanged.Publish (* exposed event handler *)
member this.Name
with get() = _name
and set(value) = _name <- value
nameChanged.Trigger() (* invokes event handler *)
member this.Shift
with get() = _shift
and set(value) = _shift <- value
shiftChanged.Trigger() (* invokes event handler *)
Em seguida, você adiciona retornos de chamada aos manipuladores de eventos. Cada manipulador de eventos tem o tipo IEvent <'T>, que fornece vários métodos -
Método | Descrição |
---|---|
val Adicionar: evento :( 'T → unidade) → unidade | Conecta uma função de ouvinte ao evento. O ouvinte será invocado quando o evento for disparado. |
val AddHandler: 'del → unidade | Conecta um objeto delegado do manipulador ao evento. Um manipulador pode ser removido posteriormente usando RemoveHandler. O ouvinte será invocado quando o evento for disparado. |
val RemoveHandler: 'del → unidade | Remove um delegado de ouvinte de um armazenamento de ouvinte de evento. |
A seção a seguir fornece um exemplo completo.
Exemplo
O exemplo a seguir demonstra o conceito e as técnicas discutidas acima -
type Worker(name : string, shift : string) =
let mutable _name = name;
let mutable _shift = shift;
let nameChanged = new Event<unit>() (* creates event *)
let shiftChanged = new Event<unit>() (* creates event *)
member this.NameChanged = nameChanged.Publish (* exposed event handler *)
member this.ShiftChanged = shiftChanged.Publish (* exposed event handler *)
member this.Name
with get() = _name
and set(value) =
_name <- value
nameChanged.Trigger() (* invokes event handler *)
member this.Shift
with get() = _shift
and set(value) =
_shift <- value
shiftChanged.Trigger() (* invokes event handler *)
let wk = new Worker("Wilson", "Evening")
wk.NameChanged.Add(fun () -> printfn "Worker changed name! New name: %s" wk.Name)
wk.Name <- "William"
wk.NameChanged.Add(fun () -> printfn "-- Another handler attached to NameChanged!")
wk.Name <- "Bill"
wk.ShiftChanged.Add(fun () -> printfn "Worker changed shift! New shift: %s" wk.Shift)
wk.Shift <- "Morning"
wk.ShiftChanged.Add(fun () -> printfn "-- Another handler attached to ShiftChanged!")
wk.Shift <- "Night"
Quando você compila e executa o programa, ele produz a seguinte saída -
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!
De acordo com a biblioteca MSDN, um módulo F # é um agrupamento de construções de código F #, como tipos, valores, valores de função e código em ligações do. Ele é implementado como uma classe de tempo de execução de linguagem comum (CLR) que possui apenas membros estáticos.
Dependendo da situação, se o arquivo inteiro está incluído no módulo, existem dois tipos de declarações de módulo -
- Declaração de módulo de nível superior
- Declaração de módulo local
Em uma declaração de módulo de nível superior, o arquivo inteiro é incluído no módulo. Nesse caso, a primeira declaração no arquivo é a declaração do módulo. Você não precisa recuar declarações em um módulo de nível superior.
Em uma declaração de módulo local, apenas as declarações que são recuadas nessa declaração de módulo fazem parte do módulo.
Sintaxe
A sintaxe para a declaração do módulo é a seguinte -
// Top-level module declaration.
module [accessibility-modifier] [qualified-namespace.]module-name
declarations
// Local module declaration.
module [accessibility-modifier] module-name =
declarations
Observe que o modificador de acessibilidade pode ser um dos seguintes - público, privado, interno. O padrão épublic.
Os exemplos a seguir demonstrarão os conceitos -
Exemplo 1
O arquivo do módulo 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
O arquivo de programa main.fs -
// Fully qualify the function name.
open Arithmetic
let addRes = Arithmetic.add 25 9
let subRes = Arithmetic.sub 25 9
let multRes = Arithmetic.mult 25 9
let divRes = Arithmetic.div 25 9
printfn "%d" addRes
printfn "%d" subRes
printfn "%d" multRes
printfn "%d" divRes
Quando você compila e executa o programa, ele produz a seguinte saída -
34
16
225
2
110
90
1000
10
Exemplo 2
// Module1
module module1 =
// Indent all program elements within modules that are declared with an equal sign.
let value1 = 100
let module1Function x =
x + value1
// Module2
module module2 =
let value2 = 200
// Use a qualified name to access the function.
// from module1.
let module2Function x =
x + (module1.module1Function value2)
let result = module1.module1Function 25
printfn "%d" result
let result2 = module2.module2Function 25
printfn "%d" result2
Quando você compila e executa o programa, ele produz a seguinte saída -
125
325
UMA namespaceé projetado para fornecer uma maneira de manter um conjunto de nomes separado de outro. Os nomes de classe declarados em um namespace não entrarão em conflito com os mesmos nomes de classe declarados em outro.
De acordo com a biblioteca MSDN, um namespace permite organizar o código em áreas de funcionalidade relacionada, permitindo que você anexe um nome a um agrupamento de elementos do programa.
Declaração de um namespace
Para organizar seu código em um namespace, você deve declarar o namespace como a primeira declaração no arquivo. O conteúdo de todo o arquivo passa a fazer parte do namespace.
namespace [parent-namespaces.]identifier
O exemplo a seguir ilustra o conceito -
Exemplo
namespace testing
module testmodule1 =
let testFunction x y =
printfn "Values from Module1: %A %A" x y
module testmodule2 =
let testFunction x y =
printfn "Values from Module2: %A %A" x y
module usermodule =
do
testmodule1.testFunction ( "one", "two", "three" ) 150
testmodule2.testFunction (seq { for i in 1 .. 10 do yield i * i }) 200
Quando você compila e executa o programa, ele produz a seguinte saída -
Values from Module1: ("one", "two", "three") 150
Values from Module2: seq [1; 4; 9; 16; ...] 200