Поиск…
Что хорошего в 0-кортеже?
Набор из 2-х кортежей или 3-кортежей представляет собой группу связанных предметов. (Точки в 2D-пространстве, RGB-значения цвета и т. Д.). 1-кортеж не очень полезен, поскольку его можно легко заменить одним int
.
0-кортеж кажется еще более бесполезным, поскольку в нем нет абсолютно ничего . Тем не менее он обладает свойствами, которые делают его очень полезным в функциональных языках, таких как F #. Например, тип 0-кортежа имеет ровно одно значение, обычно представленное как ()
. Все 0-кортежи имеют это значение, поэтому он по существу является одноэлементным. В большинстве функциональных языков программирования, включая F #, это называется типом unit
.
Функции, возвращающие void
в C #, возвращают тип unit
в F #:
let printResult = printfn "Hello"
Запустите это в интерактивном интерпретаторе F #, и вы увидите:
val printResult : unit = ()
Это означает, что значение printResult
имеет тип unit
и имеет значение ()
(пустой кортеж, одно и единственное значение типа unit
).
Функции также могут принимать тип unit
в качестве параметра. В F # функции могут выглядеть так, как будто они не принимают никаких параметров. Но на самом деле они берут единственный параметр unit
типа. Эта функция:
let doMath() = 2 + 4
на самом деле эквивалентно:
let doMath () = 2 + 4
То есть, функция, которая принимает один параметр unit
типа и возвращает значение int
6. Если вы посмотрите на подпись типа, которую интерпретирует интерактивный интерпретатор F # при определении этой функции, вы увидите:
val doMath : unit -> int
Тот факт, что все функции будут принимать по крайней мере один параметр и возвращать значение, даже если это значение иногда является «бесполезным» значением like ()
, означает, что композиция функций намного проще в F #, чем на языках, на которых нет тип unit
. Но это более продвинутый предмет, о котором мы поговорим позже. Пока просто помните, что когда вы видите unit
в сигнатуре функции или ()
в параметрах функции, это тип 0-кортежа, который служит в качестве способа сказать: «Эта функция принимает или возвращает значения, значимые».
Отложить выполнение кода
Мы можем использовать тип unit
в качестве аргумента функции для определения функций, которые мы не хотим выполнять до конца. Это часто полезно в асинхронных фоновых задачах, когда основной поток может запускать некоторые предопределенные функции фонового потока, например, может быть, переместить его в новый файл или если aa let-binding не следует запускать сразу:
module Time =
let now = System.DateTime.Now // value is set and fixed for duration of program
let now() = System.DateTime.Now // value is calculated when function is called (each time)
В следующем коде мы определяем код для запуска «рабочего», который просто выводит значение, которое он работает каждые 2 секунды. Затем рабочий возвращает две функции, которые могут использоваться для управления им - одна, которая перемещает ее до следующего значения для работы, и которое перестает работать. Они должны быть функциями, потому что мы не хотим, чтобы их тела исполнялись до тех пор, пока мы не примем решение, иначе рабочий немедленно переместится ко второму значению и выключится, не сделав ничего.
let startWorker value =
let current = ref value
let stop = ref false
let nextValue () = current := !current + 1
let stopOnNextTick () = stop := true
let rec loop () = async {
if !stop then
printfn "Stopping work."
return ()
else
printfn "Working on %d." !current
do! Async.Sleep 2000
return! loop () }
Async.Start (loop ())
nextValue, stopOnNextTick
Затем мы можем начать работника,
let nextValue, stopOnNextTick = startWorker 12
и работа начнется - если мы находимся в интерактивном режиме F #, мы увидим, что сообщения печатаются на консоли каждые две секунды. Затем мы можем запустить
nextValue ()
и мы увидим сообщения, указывающие, что обрабатываемая ценность переместилась на следующую.
Когда пришло время закончить работу, мы можем запустить
stopOnNextTick ()
функция, которая распечатает закрывающее сообщение, затем выйдет.
unit
типа важно здесь не означает «нет» вход - функции уже есть вся информация , они должны работать встроенные в них, и вызывающий абонент не может изменить.