F # - Функции
В F # функции работают как типы данных. Вы можете объявить и использовать функцию так же, как любую другую переменную.
Поскольку функции можно использовать как любые другие переменные, вы можете:
- Создайте функцию с именем и свяжите это имя с типом.
- Присвойте ему значение.
- Выполните некоторые вычисления для этого значения.
- Передайте его как параметр другой функции или подпрограмме.
- Вернуть функцию как результат другой функции.
Определение функции
Функции определяются с помощью letключевое слово. Определение функции имеет следующий синтаксис -
let [inline] function-name parameter-list [ : return-type ]
= function-body
Где,
function-name - идентификатор, представляющий функцию.
parameter-listдает список параметров, разделенных пробелами. Вы также можете указать явный тип для каждого параметра, и если он не указан, компилятор будет выводить его из тела функции (например, переменных).
function-bodyсостоит из выражения или составного выражения, состоящего из ряда выражений. Последнее выражение в теле функции - это возвращаемое значение.
return-typeявляется двоеточием, за которым следует тип, и не является обязательным. Если тип возвращаемого значения не указан, то компилятор определяет его из последнего выражения в теле функции.
Параметры функции
Вы указываете имена параметров сразу после имени функции. Вы можете указать тип параметра. Тип параметра должен следовать за именем параметра, разделенным двоеточием.
Если тип параметра не указан, он определяется компилятором.
Например -
let doubleIt (x : int) = 2 * x
Вызов функции
Функция вызывается путем указания имени функции, за которым следует пробел, а затем любые аргументы, разделенные пробелами.
Например -
let vol = cylinderVolume 3.0 5.0
Следующие программы иллюстрируют эти концепции.
Пример 1
Следующая программа вычисляет объем цилиндра, когда радиус и длина заданы как параметры.
// 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
Когда вы компилируете и выполняете программу, она дает следующий результат:
Volume: 141.372
Пример 2
Следующая программа возвращает большее значение из двух заданных параметров -
// 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
Когда вы компилируете и выполняете программу, она дает следующий результат:
Max Value: 52
Пример 3
let doubleIt (x : int) = 2 * x
printfn "Double 19: %d" ( doubleIt(19))
Когда вы компилируете и выполняете программу, она дает следующий результат:
Double 19: 38
Рекурсивные функции
Рекурсивные функции - это функции, которые вызывают сами себя.
Вы определяете рекурсию, используя let rec комбинация ключевых слов.
Синтаксис для определения рекурсивной функции -
//Recursive function definition
let rec function-name parameter-list = recursive-function-body
Например -
let rec fib n = if n < 2 then 1 else fib (n - 1) + fib (n - 2)
Пример 1
Следующая программа возвращает значения Фибоначчи от 1 до 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)
Когда вы компилируете и выполняете программу, она дает следующий результат:
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
Пример 2
Следующая программа возвращает факториал 8 -
open System
let rec fact x =
if x < 1 then 1
else x * fact (x - 1)
Console.WriteLine(fact 8)
Когда вы компилируете и выполняете программу, она дает следующий результат:
40320
Обозначения стрелок в F #
F # сообщает о типах данных в функциях и значениях, используя нотацию со стрелками. Давайте рассмотрим пример функции, которая принимает один ввод int и возвращает строку. В обозначениях стрелок это записывается как -
int -> string
Типы данных читаются слева направо.
Давайте возьмем еще одну гипотетическую функцию, которая принимает два ввода данных типа int и возвращает строку.
let mydivfunction x y = (x / y).ToString();;
F # сообщает о типе данных, используя обозначения со стрелками как -
val mydivfunction : x:int -> y:int -> string
Тип возвращаемого значения представлен крайним правым типом данных в виде связанных стрелок.
Еще несколько примеров -
Обозначение | Имея в виду |
---|---|
поплавок → поплавок → поплавок | Функция принимает два входа с плавающей запятой , возвращает еще одно значение с плавающей запятой . |
int → строка → float | Функция принимает int и строковый ввод, возвращает float . |
Лямбда-выражения
А lambda expression безымянная функция.
Давайте возьмем пример двух функций -
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
Когда вы компилируете и выполняете программу, она дает следующий результат:
35
Теперь, в приведенном выше примере, если бы вместо определения функции mul мы могли бы использовать лямбда-выражения как -
let applyFunction ( f: int -> int -> int) x y = f x y
let res = applyFunction (fun x y -> x * y ) 5 7
printfn "%d" res
Когда вы компилируете и выполняете программу, она дает следующий результат:
35
Композиция функций и конвейерная обработка
В F # одна функция может быть составлена из других функций.
В следующем примере показана композиция функции с именем f из двух функций function1 и function2:
let function1 x = x + 1
let function2 x = x * 5
let f = function1 >> function2
let res = f 10
printfn "%d" res
Когда вы компилируете и выполняете программу, она дает следующий результат:
55
F # также предоставляет функцию под названием pipelining of functions. Конвейерная обработка позволяет объединять вызовы функций как последовательные операции.
Следующий пример показывает, что -
let function1 x = x + 1
let function2 x = x * 5
let res = 10 |> function1 |> function2
printfn "%d" res
Когда вы компилируете и выполняете программу, она дает следующий результат:
55