open System // Gets access to functionality in System namespace.
// Defines a list of names
let names = [ "Peter"; "Julia"; "Xi" ]
// Defines a function that takes a name and produces a greeting.
let getGreeting name = $"Hello, {name}"
// Prints a greeting for each name!
names
|> List.map getGreeting
|> List.iter (fun greeting -> printfn $"{greeting}! Enjoy your F#")
Title | Description |
---|---|
Literals | Learn about the syntax for literal values in F# and how to specify type information for F# literals. |
Strings | Learn about strings in F#. The string type represents immutable text, as a sequence of Unicode characters. string is an alias for System.String in .NET. |
Interpolated strings | Learn about interpolated strings, a special form of string that allows you to embed F# expressions directly inside them. |
Types | Data Types |
---|---|
Primitive data types | char, byte, bool, int, float |
Derived data types | class, array, list, records, sequence |
Enumeration | enum |
Unit type | It is used if other data types are not specified. |
let ExExample a b =
let mutable c = 0
c <- (a/b)
printfn "Rest of the code"
ExExample 10 0
Title | Description |
---|---|
Exception Handling | Contains information about exception handling support in F#. |
The try...with Expression |
Learn about how to use the try...with expression for exception handling. |
The try...finally Expression |
Learn about how the F# try...finally expression enables you to execute clean-up code even if a block of code throws an exception. |
The use Keyword |
Learn about the keywords use and using , which can control the initialization and release of resources. |
Assertions | Learn about the assert expression, which is a debugging feature that you can use to test an expression. Upon failure in Debug mode, an assertion generates a system error dialog box. |
let ExExample a b =
let mutable c = 0
try
c <- (a/b)
with
| :? System.DivideByZeroException as e -> printfn "%s" e.Message
printfn "Rest of the code"
ExExample 10 0
let TestAgeValidation age =
try
if (age<18) then failwith "Sorry, Age must be greater than 18"
with
| Failure(e) -> printfn "%s" e;
printf "Rest of the code"
TestAgeValidation 10
Example of InvalidArg keyword
let TestInvalidArgument age =
if(age<18) then
invalidArg "TestInvalidArgument" ("Sorry, Age must be greater than 18")
TestInvalidArgument 10
let divide (x:int, y:int):int =
assert (x>0)
let z = (x/y)
z
let result = divide(10,2)
printf "%d" result
open Arithmetic
printf "%d" (sub 20 10)
string
type represents immutable text as a sequence of Unicode characters. string
is an alias for System.String
in .NET. (")
character. The backslash character ( \ )
is used to encode certain special characters. The backslash and the next character together are known as an escape sequence. Escape sequences supported in F# string literals are shown in the following table.Character | Escape sequence |
---|---|
Alert | \a |
Backspace | \b |
Form feed | \f |
Newline | \n |
Carriage return | \r |
Tab | \t |
Vertical tab | \v |
Backslash | \\ |
Quotation mark | \" |
Apostrophe | \' |
Unicode character | \DDD (where D indicates a decimal digit; range of 000 - 255; for example, \231 = "ç") |
Unicode character | \xHH (where H indicates a hexadecimal digit; range of 00 - FF; for example, \xE7 = "ç") |
Unicode character | \uHHHH (UTF-16) (where H indicates a hexadecimal digit; range of 0000 - FFFF; for example, \u00E7 = "ç") |
Unicode character | \U00HHHHHH (UTF-32) (where H indicates a hexadecimal digit; range of 000000 - 10FFFF; for example, \U0001F47D = "👽") |
@ symbol
, the literal is a verbatim string. Declaring a verbatim string means that any escape sequences are ignored, except that two quotation mark characters are interpreted as one quotation mark character.// Using a verbatim string
let xmlFragment1 = @"<book author=""Milton, John"" title=""Paradise Lost"">"
// Using a triple-quoted string
let xmlFragment2 = """<book author="Milton, John" title="Paradise Lost">"""
str1
that has value "abc\ndef
" and a string str2
that has value "abcdef
".let str1 = "abc
def"
let str2 = "abc\
def"
printfn "%c" str1[1]
The output is : b.
printfn "%s" str1[0..2]
printfn "%s" str2[3..5]
abc
def
byte[]
. You add the suffix B
to a string literal to indicate that it's an ASCII string.
ASCII string literals used with byte arrays support the same escape sequences as Unicode strings, except for the Unicode escape sequences.// "abc" interpreted as a Unicode string.
let str1 : string = "abc"
// "abc" interpreted as an ASCII byte array.
let bytearray : byte[] = "abc"B
let function1 x y = x + y
function1 10 20 // this line results a compiler warning
// changing the code to the following and eliminates the warning
let result = function1 10 20
// Use this if you are calling the function and don't want the return value
function1 10 20 |> ignore
type BaseClass() =
class
member this.ShowClassName()=
printfn "BaseClass"
end
type DerivedClass() =
class
inherit BaseClass()
member this.ShowClassName()=
printfn "DerivedClass"
end
let baseClass = new BaseClass()
let derivedClass : DerivedClass = new DerivedClass()
baseClass.ShowClassName()
derivedClass.ShowClassName()
let castIntoBaseClass = derivedClass :> BaseClass // upcasting
castIntoBaseClass.ShowClassName()
let castIntoDerivedClass = baseClass :?> DerivedClass // downcasting
castIntoDerivedClass.ShowClassName()
F#
, the bitwise operator works on individual bits and return a result after evaluation.// Binding a value:
let identifier-or-pattern [: type] =expressionbody-expression
// Binding a function value:
let identifier parameter-list [: return-type ] =expressionbody-expression
F#
function has a name, can have parameters and take arguments, and has a body. F#
also supports functional programming constructs such as treating functions as values, using unnamed functions in expressions, composition of functions to form new functions, curried functions, and the implicit definition of functions by way of the partial application of function arguments.// Non-recursive function definition.
let [inline] function-name parameter-list [ : return-type ] = function-body
// Recursive function definition.
let rec function-name parameter-list = recursive-function-body
F#
, functions can be composed from other functions. It is a process of composing in which a function represents the application of two composed functions. F#
function pipelining allows us to call functions in the chain. Pipelining operator takes a function and an argument as operands and returns a value.let function1 name=
name + " FSharp"
let function2 name =
name + " Programming"
let programmingName = function1 >> function2
let result = programmingName "Hello"
printf "%s" result
let function1 name=
name + " FSharp"
let function2 name =
name + " Programming"
let result = "Hello" |> function1 |> function2
printf "%s" result
let result = (fun a -> a+1) 100
printf "%d" result
type InlineClass() =
class
member inline this.inlineFunction(a) = a*a
end
let obj = new InlineClass()
let result = obj.inlineFunction 2
printf "%d" result
// Recursive function:
let rec function-nameparameter-list =
function-body
// Mutually recursive functions:
let rec function1-nameparameter-list =
function1-body
and function2-nameparameter-list =
function2-body
...
let rec fib n =
match n with
| 0 | 1 -> n
| n -> fib (n-1) + fib (n-2)
Methods are implicitly recursive within the type they are defined in, meaning there is no need to add the rec keyword. For example :
type MyClass() =
member this.Fib(n) =
match n with
| 0 | 1 -> n
| n -> this.Fib(n-1) + this.Fib(n-2)
Let bindings within classes are not implicitly recursive, though. All let-bound functions require the rec keyword.
match
expression. They are used when you are processing arguments for functions in let
bindings, lambda expressions, and in the exception handlers associated with the try...with
expression. For more information, see Match Expressions, let Bindings, Lambda Expressions: The fun Keyword, and Exceptions: The try...with Expression.match expression with
| pattern [ when condition ] -> result-expression
...
Name | Description | Example |
---|---|---|
Constant pattern | Any numeric, character, or string literal, an enumeration constant, or a defined literal identifier | 1.0 , "test" , 30 , Color.Red |
Identifier pattern | A case value of a discriminated union, an exception label, or an active pattern case | Some(x) Failure(msg) |
Variable pattern | identifier | a |
as pattern |
pattern as identifier | (a, b) as tuple1 |
OR pattern | pattern1 | pattern2 | ([h] | [h; _]) |
AND pattern | pattern1 & pattern2 | (a, b) & (_, "test") |
Cons pattern | identifier :: list-identifier | h :: t |
List pattern | [ pattern_1; ... ; pattern_n ] | [ a; b; c ] |
Array pattern | [| pattern_1; ..; pattern_n |] | [| a; b; c |] |
Parenthesized pattern | ( pattern ) | ( a ) |
Tuple pattern | ( pattern_1, ... , pattern_n ) | ( a, b ) |
Record pattern | { identifier1 = pattern_1; ... ; identifier_n = pattern_n } | { Name = name; } |
Wildcard pattern | _ | _ |
Pattern together with type annotation | pattern : type | a : int |
Type test pattern | :? type [ as identifier ] | :? System.DateTime as dt |
Null pattern | null | null |
Nameof pattern | nameof expr | nameof str |
F#
.type DoBindingClass() =
class
do printf "Hello FSharp"
end
new DoBindingClass()
: (colon)
to apply annotation in F#
.let a:int = 10
printf "%d" a
F#
is a statically typed language, which means that the compiler deduces an exact type for each construct during compilation. If there is not enough information for the compiler to deduce the types of each construct, you must supply additional type information, typically by adding explicit type annotations somewhere in the code.a
and b
and the return type are all inferred to be int
because the literal 100
is of type int
.let f a b = a + b + 100
100
a uint32
by appending the suffix u
, the types of a, b
, and the return value are inferred to be uint32
.// Type annotations on a parameter.
let addu1 (x : uint32) y =
x + y
// Type annotations on an expression.
let addu2 x y =
(x : uint32) + y
let addu1 x y : uint32 =
x + y
let replace(str: string) =
str.Replace("A", "a")
let makeTuple a b = (a, b)
'a -> 'b -> 'a * 'b
let x : int = 5
let b : byte = byte x
Operator | Description |
---|---|
byte |
Convert to byte, an 8-bit unsigned type. |
sbyte |
Convert to signed byte. |
int16 |
Convert to a 16-bit signed integer. |
uint16 |
Convert to a 16-bit unsigned integer. |
int32, int |
Convert to a 32-bit signed integer. |
uint32 |
Convert to a 32-bit unsigned integer. |
int64 |
Convert to a 64-bit signed integer. |
uint64 |
Convert to a 64-bit unsigned integer. |
nativeint |
Convert to a native integer. |
unativeint |
Convert to an unsigned native integer. |
float, double |
Convert to a 64-bit double-precision IEEE floating point number. |
float32, single |
Convert to a 32-bit single-precision IEEE floating point number. |
decimal |
Convert to System.Decimal . |
char |
Convert to System.Char , a Unicode character. |
enum |
Convert to an enumerated type. |
enum
operator is a generic operator that takes one type parameter that represents the type of the enum
to convert to. When it converts to an enumerated type, type inference attempts to determine the type of the enum
that you want to convert to. In the following example, the variable col1
is not explicitly annotated, but its type is inferred from the later equality test. Therefore, the compiler can deduce that you are converting to a Color
enumeration. Alternatively, you can supply a type annotation, as with col2
in the following example.type Color =
| Red = 1
| Green = 2
| Blue = 3
// The target type of the conversion cannot be determined by type inference, so the type parameter must be explicit.
let col1 = enum<Color> 1
// The target type is supplied by a type annotation.
let col2 : Color = enum 2
let col3 = enum<Color> 3
int32
and uint32
.// Error: types are incompatible
let col4 : Color = enum 2u
#type
#SomeType
'T when 'T :> SomeType
iterate2
enables the higher order function to work with functions that generate sequences, arrays, lists, and any other enumerable type.let iterate1 (f : unit -> seq<int>) =
for e in f() do printfn "%d" e
let iterate2 (f : unit -> #seq<int>) =
for e in f() do printfn "%d" e
// Passing a function that takes a list requires a cast.
iterate1 (fun () -> [1] :> seq<int>)
// Passing a function that takes a list to the version that specifies a
// flexible type as the return value is OK as is.
iterate2 (fun () -> [1])
val concat: sequences:seq<#seq<'T>> -> seq<'T>
let list1 = [1;2;3]
let list2 = [4;5;6]
let list3 = [7;8;9]
let concat1 = Seq.concat [ list1; list2; list3]
printfn "%A" concat1
let array1 = [|1;2;3|]
let array2 = [|4;5;6|]
let array3 = [|7;8;9|]
let concat2 = Seq.concat [ array1; array2; array3 ]
printfn "%A" concat2
let concat3 = Seq.concat [| list1; list2; list3 |]
printfn "%A" concat3
let concat4 = Seq.concat [| array1; array2; array3 |]
printfn "%A" concat4
let seq1 = { 1 .. 3 }
let seq2 = { 4 .. 6 }
let seq3 = { 7 .. 9 }
let concat5 = Seq.concat [| seq1; seq2; seq3 |]
printfn "%A" concat5
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
seq [1; 2; 3; 4; ...]
(element, ... , element)
struct(element, ... ,element )
solved
" by using structs. You must consider the additional cost of copying when using them instead of reference types. However, large F# programs commonly instantiate many optional types that flow through hot paths, and in such cases, structs can often yield better overall performance over the lifetime of a program.[<StructuralEquality; StructuralComparison>]
[<Struct>]
type ValueOption<'T> =
| ValueNone
| ValueSome of 'T
let tryParseDateTime (s: string) =
match System.DateTime.TryParse(s) with
| (true, dt) -> ValueSome dt
| (false, _) -> ValueNone
let possibleDateString1 = "1990-12-25"
let possibleDateString2 = "This is not a date"
let result1 = tryParseDateTime possibleDateString1
let result2 = tryParseDateTime possibleDateString2
match (result1, result2) with
| ValueSome d1, ValueSome d2 -> printfn "Both are dates!"
| ValueSome d1, ValueNone -> printfn "Only the first is a date!"
| ValueNone, ValueSome d2 -> printfn "Only the second is a date!"
| ValueNone, ValueNone -> printfn "None of them are dates!"
As with Options, the naming convention for a function that returns ValueOption is to prefix it with try.
Value.
An InvalidOperationException is raised if no value is present when this property is invoked.ValueOption
module in FSharp.Core
contains equivalent functionality to the Option module. There are a few differences in name, such as defaultValueArg
:val defaultValueArg : arg:'T voption -> defaultValue:'T -> 'T
F# List Example
let list = [1;2;3;4;5;6;7;8;9]
for i in list do
printfn "%d" i
let arr = [| 1; 2; 3; 4; 5; |] // Creating and initializing array
for i = 0 to arr.Length-1 do // Traversing of array
printfn "%d" arr.[i]
You can create sequence expression like following. Here, we have used Seq.iter () function to iterate sequence. We can also use for loop or array format specifier to iterate sequence elements.
let seq1 =
seq { 0 .. 10 }
Seq.iter(fun a->printf " %d" a)seq1
let refVariable = ref 50
printf "%d" refVariable.Value
System.Collections.Generic
namespace, in that the F# collection types are designed from a functional programming perspective rather than an object-oriented perspective. More specifically, only the array collection has mutable elements. Therefore, when you modify a collection, you create an instance of the modified collection instead of altering the original collection.Type | Description | Related Links |
---|---|---|
List | An ordered, immutable series of elements of the same type. Implemented as a linked list. | List Module |
Array | A fixed-size, zero-based, mutable collection of consecutive data elements that are all of the same type. | Array Module Array2D Module Array3D Module |
seq | A logical series of elements that are all of one type. Sequences are particularly useful when you have a large, ordered collection of data but don't necessarily expect to use all the elements. Individual sequence elements are computed only as required, so a sequence can perform better than a list if not all the elements are used. Sequences are represented by the seq<'T> type, which is an alias for IEnumerable . Therefore, any .NET Framework type that implements System.Collections.Generic.IEnumerable<'T> can be used as a sequence. |
Seq Module |
Map | An immutable dictionary of elements. Elements are accessed by key. | Map Module |
Set | An immutable set that's based on binary trees, where comparison is the F# structural comparison function, which potentially uses implementations of the System.IComparable interface on key values. |
Set Module |
let objectName = new ClassName()
type Student (id,name)=
class
member x.show =
printf "%d \n%s" id name
end
let a = new Student (12,"FSharp")
a.show
type Employee(name) =
class
do printf "%s" name
end
let e = new Employee("FSharp")
C#
and Java
. You can name the self-identifier
however you want. You are not restricted to names such as this or self as in .Net languages.type Employee(id,name) as this =
let id = id
let name = name
do this.Display() // This is how we can use self(this) object
member this.Display() =
printf "%d %s" id name
let e =new Employee(100, "Ramana")
type Account(accno,name) = class
static let rateOfInterest = 8.8
member this.display()=
printfn "%d %s %0.2f" accno name rateOfInterest
end
let a1 = new Account(101,"Rajkumar")
let a2 = new Account(102, "john")
a1.display()
a2.display()
is-a
" relationship, or subtyping, in object-oriented programming.type MyDerived(...) =
inherit MyBase(...)
abstract member [method-name] : [type]
default [self-identifier].[method-name] [argument-list] = [method-body]
override [self-identifier].[method-name] [argument-list] = [method-body]
type MyClassBase1() =
let mutable z = 0
abstract member function1 : int -> int
default u.function1(a : int) = z <- z + a; z
type MyClassDerived1() =
inherit MyClassBase1()
override u.function1(a: int) = a + 1
type MyClassBase2(x: int) =
let mutable z = x * x
do for i in 1..z do printf "%d " i
type MyClassDerived2(y: int) =
inherit MyClassBase2(y * 2)
do for i in 1..y do printf "%d " i
type BaseClass =
val string1 : string
new (str) = { string1 = str }
new () = { string1 = "" }
type DerivedClass =
inherit BaseClass
val string2 : string
new (str1, str2) = { inherit BaseClass(str1); string2 = str2 }
new (str2) = { inherit BaseClass(); string2 = str2 }
let obj1 = DerivedClass("A", "B")
let obj2 = DerivedClass("A")
open System
let object1 = { new Object() with
override this.ToString() = "This overrides object.ToString()"
}
printfn "%s" (object1.ToString())
// Abstract class syntax.
[<AbstractClass>]
type [ accessibility-modifier ] abstract-class-name =
[ inherit base-class-or-interface-name ]
[ abstract-member-declarations-and-member-definitions ]
// Abstract member syntax.
abstract member member-name : type-signature
type Employee() =
class
abstract ShowName : unit -> unit
default this.ShowName() = printfn"This is base class method"
end
type Manager() =
class
inherit Employee()
override this.ShowName() = printf "This is derived class method"
end
let employee = new Employee()
let manager = new Manager()
employee.ShowName()
manager.ShowName()
// Overloading an operator as a class or record member.
static member (operator-symbols) (parameter-list) =
method-body
// Overloading an operator at the global level
let [inline] (operator-symbols) parameter-list = function-body
+, -, *, /, =
, and so on. The parameter-list specifies the operands in the order they appear in the usual syntax for that operator. The method-body constructs the resulting value.+
and -
, must use a tilde (~
) in the operator-symbol to indicate that the operator is a unary operator and not a binary operator, as shown in the following declaration.static member (~-) (v : Vector)
Operator | Generated name |
---|---|
[] |
op_Nil |
:: |
op_Cons |
+ |
op_Addition |
- |
op_Subtraction |
* |
op_Multiply |
/ |
op_Division |
@ |
op_Append |
^ |
op_Concatenate |
% |
op_Modulus |
&&& |
op_BitwiseAnd |
||| |
op_BitwiseOr |
^^^ |
op_ExclusiveOr |
<<< |
op_LeftShift |
~~~ |
op_LogicalNot |
>>> |
op_RightShift |
~+ |
op_UnaryPlus |
~- |
op_UnaryNegation |
= |
op_Equality |
<= |
op_LessThanOrEqual |
>= |
op_GreaterThanOrEqual |
< |
op_LessThan |
> |
op_GreaterThan |
? |
op_Dynamic |
?<- |
op_DynamicAssignment |
|> |
op_PipeRight |
<| |
op_PipeLeft |
! |
op_Dereference |
>> |
op_ComposeRight |
<< |
op_ComposeLeft |
<@ @> |
op_Quotation |
<@@ @@> |
op_QuotationUntyped |
+= |
op_AdditionAssignment |
-= |
op_SubtractionAssignment |
*= |
op_MultiplyAssignment |
/= |
op_DivisionAssignment |
.. |
op_Range |
.. .. |
op_RangeStep |
type IEmployee =
abstract member ShowName : unit -> unit
type Manager(id:int, name:string) =
interface IEmployee with
member this.ShowName() = printfn "Id = %d \nName = %s" id name
let manager = new Manager(100,"RajKumar")
//manager.ShowName() // error: you can't directly access interface abstract method by using class object.
// so, we need to upcast class type object to interface type by using :> operator.
(manager :> IEmployee).ShowName()
type Deligate() =
static member mul(a : int, b : int) = a * b
member x.Mul(a : int, b : int) = a * b
type Multiply = delegate of (int * int) -> int
let getIt (d : Multiply) (a : int) (b: int) =
d.Invoke(a, b)
let d : Multiply = new Multiply( Deligate.mul )
for (a, b) in [(5, 8) ] do
printfn "%d * %d = %d" a b (getIt d a b)
Signature file named as signature.fsi
namespace FSharpPrograms
module Arithmetic =
val add : int * int -> int
val sub : int * int -> int
open System
Console.WriteLine("Hello, this is F# here.")
Lazy expressions
are expressions that are not evaluated immediately, but are instead evaluated when the result is needed. This can help to improve the performance of your code.let identifier = lazy ( expression )
<'T>
, where the actual type that is used for 'T
is determined from the result of the expression.force
the expressions to be performed, you call the method Force
. Force
causes the execution to be performed only one time. Subsequent calls to Force return the same result, but do not execute any code.lazy
expressions and the use of Force. In this code, the type of result is Lazy<int>
, and the Force method returns an int.let x = 10
let result = lazy (x + 10)
printfn "%d" (result.Force())
Lazy evaluation, but not the Lazy type
, is also used for sequences.
///
) code comments. XML comments can precede declarations in code files (.fs
) or signature (.fsi
) files.let add x y = x+y
let result = lazy (add 10 10)
printfn "%d" (result.Force())
System.Runtime.CompilerServices
namespace:Attribute | Description | Type |
---|---|---|
CallerFilePath | Full path of the source file that contains the caller. This is the file path at compile time. | String |
CallerLineNumber | Line number in the source file at which the method is called. | Integer |
CallerMemberName | Method or property name of the caller. See the Member Names section later in this topic. | String |
open System.Diagnostics
open System.Runtime.CompilerServices
open System.Runtime.InteropServices
type Tracer() =
member _.DoTrace(message: string,
[<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string,
[<CallerFilePath; Optional; DefaultParameterValue("")>] path: string,
[<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) =
Trace.WriteLine(sprintf $"Message: {message}")
Trace.WriteLine(sprintf $"Member name: {memberName}")
Trace.WriteLine(sprintf $"Source file path: {path}")
Trace.WriteLine(sprintf $"Source line number: {line}")
fsi.exe
. F# Interactive accepts many of the same command-line
options as the F# compiler, but also accepts some additional options.dotnet fsi
, can be launched interactively, or it can be launched from the command line to run a script. dotnet fsi [options] [ script-file [arguments] ]
The file extension for F# script files is .fsx.