F#
Het type "eenheid"
Zoeken…
Wat heb je aan een 0-tuple?
Een 2-tuple of een 3-tuple vertegenwoordigen een groep gerelateerde items. (Punten in 2D-ruimte, RGB-waarden van een kleur, enz.) Een 1-tuple is niet erg handig omdat het gemakkelijk kan worden vervangen door een enkele int
.
Een 0-tupel lijkt nog nutteloos omdat het absoluut niets bevat. Toch heeft het eigenschappen die het zeer nuttig maken in functionele talen zoals F #. Het type 0-tuple heeft bijvoorbeeld precies één waarde, meestal weergegeven als ()
. Alle 0-tupels hebben deze waarde, dus het is in wezen een singleton-type. In de meeste functionele programmeertalen, inclusief F #, wordt dit het type unit
.
Functies die void
in C # retourneren het unit
in F #:
let printResult = printfn "Hello"
Voer dat uit in de interactieve F # -interpreter en u ziet:
val printResult : unit = ()
Dit betekent dat de waarde printResult
van het type unit
is en de waarde ()
(de lege tuple, de enige waarde van het unit
).
Functies kunnen het type unit
als parameter nemen. In F # kunnen functies eruit zien alsof ze geen parameters aannemen. Maar in feite nemen ze een enkele parameter van het type unit
. Deze functie:
let doMath() = 2 + 4
is eigenlijk gelijk aan:
let doMath () = 2 + 4
Dat wil zeggen, een functie die één parameter van type- unit
en de int
waarde 6 retourneert. Als u kijkt naar de typeaanduiding die de F # interactieve interpreter afdrukt wanneer u deze functie definieert, ziet u:
val doMath : unit -> int
Het feit dat alle functies ten minste één parameter nodig hebben en een waarde retourneren, zelfs als die waarde soms een "nutteloze" waarde is zoals ()
, betekent dat functiesamenstelling een stuk eenvoudiger is in F # dan in talen die niet de type unit
. Maar dat is een geavanceerder onderwerp waar we later op zullen ingaan. Onthoud voor nu dat wanneer u unit
in een functiehandtekening, of ()
in de parameters van een functie, dat dit het 0-tuple type is dat dient als de manier om te zeggen: "Deze functie heeft geen betekenisvolle waarden".
Uitvoering van code uitstellen
We kunnen het unit
gebruiken als een functieargument om functies te definiëren die we pas later willen uitvoeren. Dit is vaak handig bij asynchrone achtergrondtaken, wanneer de hoofdthread mogelijk een vooraf gedefinieerde functionaliteit van de achtergrondthread wil activeren, zoals misschien verplaatsen naar een nieuw bestand, of als een let-binding niet onmiddellijk moet worden uitgevoerd:
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)
In de volgende code definiëren we code om een "werker" te starten die eenvoudig de waarde waaraan het werkt elke 2 seconden afdrukt. De werker geeft vervolgens twee functies terug die kunnen worden gebruikt om het te besturen - één die het naar de volgende waarde verplaatst om aan te werken, en één die het stopt met werken. Dit moeten functies zijn, omdat we niet willen dat hun lichamen worden uitgevoerd totdat we ervoor kiezen, anders zou de werknemer onmiddellijk naar de tweede waarde gaan en afsluiten zonder iets te hebben gedaan.
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
We kunnen dan een werknemer starten door het te doen
let nextValue, stopOnNextTick = startWorker 12
en het werk zal beginnen - als we in F # interactive zijn, zullen we de berichten elke twee seconden in de console afdrukken. We kunnen dan vluchten
nextValue ()
en we zullen de berichten zien die aangeven dat de waarde waaraan wordt gewerkt, naar de volgende is verplaatst.
Wanneer het tijd is om te werken, kunnen we de
stopOnNextTick ()
functie, die het sluitingsbericht zal afdrukken en vervolgens afsluiten.
Het unit
is hier belangrijk om "geen invoer" aan te geven - de functies hebben al alle informatie die ze nodig hebben om in te werken ingebouwd, en de beller mag dat niet veranderen.