EDIT:
E seems che attualmente il pacchetto ufficiale per la gestione di manipolazioni record è purescript-record
- si possono trovare Builder.purs lì che fornisce merge
e build
funzioni:
> import Data.Record.Builder (build, merge)
> name = {name: "Jim"}
> age = {age: 37}
> :t (build (merge age) name)
{ name :: String
, age :: Int
}
API NOTA:
Questa API sembra complicata a prima vista, specialmente quando la si confronta con la semplice chiamata unionMerge name age
(unionMerge
è intodotto alla fine di questa risposta). Il motivo alla base dell'esistenza di Builder
(e quindi di questa API) è la prestazione. Posso assicurarti che questo:
> build (merge name >>> merge age) {email: "[email protected]"}
crea solo un nuovo record. Ma questo:
> unionMerge name (unionMerge age {email: "[email protected]"})
crea due record durante l'esecuzione.
Ciò che è ancora più interessante è come sono implementati Builder
, build
e merge
- Builder
è Newtype wrapper per la funzione (e la sua composizione è solo la composizione di funzione) e build
è solo funzione di applicazione sulla versione copiata di un record:
newtype Builder a b = Builder (a -> b)
build (Builder b) r1 = b (copyRecord r1)
In merge
c'è unsafeMerge
eseguita:
merge r2 = Builder \r1 -> unsafeMerge r1 r2
Quindi w sto guadagnando qualcosa ?? Perché possiamo essere sicuri che i risultati intermedi non possono sfuggire dall'ambito della funzione, quindi tutte le trasformazioni possono essere eseguite sul posto. In altre parole questo valore intermediate
:
> intermediate = unionMerge name {email: "[email protected]"}
> unionMerge age intermediate
non può essere "estratta" da qui:
> build (merge name >>> merge age) {email: "[email protected]"}
sistema dei tipi COMMENTO:
Sembra che tipo di sistema Purescript può gestire questa ora grazie la classe Union
tipo da Prim
:
The Union type class is used to compute the union of two rows
of types (left-biased, including duplicates).
The third type argument represents the union of the first two.
Che ha questo "tipo di magia" (fonte: slide 23):
Union r1 r2 r3 | r1 r2 -> r3, r1 r3 -> r2
vecchio metodo (ancora valido ma non preferita):
C'è purescript-records pacchetto che espone unionMerge
che fa esattamente quello che voglio (nel nuovo psci non dobbiamo usare let
):
> import Data.Record (unionMerge)
> name = {name: "Jim"}
> age = {age: 37}
> :t (unionMerge age name)
{ name :: String
, age :: Int
}
Cool, grazie per la spiegazione. Ma solo per chiarire un po 'le cose: come funziona con il rowtype Eff. Per quanto ho capito, il tipo di riga Eff è un po 'come "composto" da diversi tipi di effetti. Come funziona lì? –
Si basa sui tipi che sono unificati, quindi nell'esempio sopra, se chiamiamo 'something' con' {name :: String, age :: Int, address :: String} 'finiamo con' r ~ (age: : Int, address :: String) 'in' {name :: String | r} '. La roba 'Eff' funziona in modo simile, non abbiamo mai realmente qualcosa in cui due diversi valori di' eff' vengono combinati da argomenti diversi per produrne uno nuovo. –
ok, penso di aver capito. Molte grazie. –