Ricerca…


A che serve una tupla 0?

Una tupla di 2 o una tupla di 3 rappresentano un gruppo di elementi correlati. (Punti nello spazio 2D, valori RGB di un colore, ecc.) Una tupla 1 non è molto utile in quanto potrebbe essere facilmente sostituita con un singolo int .

Una tupla 0 sembra ancora più inutile poiché non contiene assolutamente nulla . Tuttavia ha proprietà che lo rendono molto utile in linguaggi funzionali come F #. Ad esempio, il tipo di tupla 0 ha esattamente un valore, solitamente rappresentato come () . Tutte le tuple 0 hanno questo valore quindi è essenzialmente un tipo singleton. Nella maggior parte dei linguaggi di programmazione funzionale, incluso F #, questo è chiamato il tipo di unit .

Le funzioni che restituiscono void in C # restituiranno il tipo di unit in F #:

let printResult = printfn "Hello"

Eseguilo nell'interprete interattivo F # e vedrai:

val printResult : unit = ()

Ciò significa che il valore printResult è di tipo unit e ha il valore () (la tupla vuota, l'unico valore del tipo di unit ).

Le funzioni possono anche prendere il tipo di unit come parametro. In F #, le funzioni potrebbero sembrare che non stanno prendendo alcun parametro. Ma in effetti stanno prendendo un singolo parametro unit di tipo. Questa funzione:

let doMath() = 2 + 4

è in realtà equivalente a:

let doMath () = 2 + 4

Cioè, una funzione che accetta un parametro di tipo unit e restituisce il valore int 6. Se si osserva la firma del tipo che l'interprete interattivo F # stampa quando si definisce questa funzione, vedrete:

val doMath : unit -> int

Il fatto che tutte le funzioni richiedono almeno un parametro e restituiscono un valore, anche se tale valore è talvolta un valore "inutile" come () , significa che la composizione della funzione è molto più semplice in F # rispetto alle lingue che non hanno il tipo di unit . Ma questo è un argomento più avanzato che vedremo più avanti. Per ora, ricorda che quando vedi l' unit in una firma di funzione, o () nei parametri di una funzione, questo è il tipo di tupla 0 che funge da modo per dire "Questa funzione accetta o restituisce valori privi di significato".

Differire nell'esecuzione del codice

Possiamo usare il tipo di unit come argomento di funzione per definire funzioni che non vogliamo vengano eseguite fino a più tardi. Questo è spesso utile in attività di background asincrone, quando il thread principale potrebbe voler attivare alcune funzionalità predefinite del thread in background, come magari spostarlo in un nuovo file, o se aa let-binding non dovrebbe essere eseguito immediatamente:

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)

Nel codice seguente, definiamo il codice per avviare un "worker" che stampa semplicemente il valore su cui sta lavorando ogni 2 secondi. L'operatore restituisce quindi due funzioni che possono essere utilizzate per controllarlo, una che la sposta al valore successivo su cui lavorare e una che ne impedisce il funzionamento. Queste devono essere funzioni, perché non vogliamo che i loro corpi siano eseguiti fino a quando non lo decidiamo, altrimenti il ​​lavoratore si sposterebbe immediatamente al secondo valore e si spegnerebbe senza aver fatto nulla.

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

Possiamo quindi iniziare un lavoratore facendo

let nextValue, stopOnNextTick = startWorker 12

e il lavoro inizierà - se siamo in F # interattiva, vedremo i messaggi stampati nella console ogni due secondi. Possiamo quindi correre

nextValue ()

e vedremo i messaggi che indicano che il valore su cui si sta lavorando è passato a quello successivo.

Quando è il momento di terminare il lavoro, possiamo eseguire il

stopOnNextTick ()

funzione, che stamperà il messaggio di chiusura, quindi uscirà.

Il tipo di unit è importante qui per indicare "nessun input": le funzioni dispongono già di tutte le informazioni necessarie per lavorare su di esse e il chiamante non può modificarlo.



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow