EDIT:
To seems że obecnie oficjalny pakiet do obsługi rekordowe manipulacje jest purescript-record
- można znaleźć Builder.purs tam, co zapewnia merge
i build
funkcje:
> import Data.Record.Builder (build, merge)
> name = {name: "Jim"}
> age = {age: 37}
> :t (build (merge age) name)
{ name :: String
, age :: Int
}
API UWAGA:
Ten interfejs API wygląda na pierwszy rzut oka zbyt skomplikowany - zwłaszcza gdy porównasz go do prostego połączenia unionMerge name age
(unionMerge
zostaje wprowadzony na końcu tej odpowiedzi). Powodem istnienia Builder
istnienia (a więc tego API) jest wydajność. Zapewniam Cię, że:
> build (merge name >>> merge age) {email: "[email protected]"}
tworzy tylko jeden nowy rekord. Ale to:
> unionMerge name (unionMerge age {email: "[email protected]"})
tworzy dwie zapisy podczas wykonywania.
Co jest jeszcze bardziej interesujące jest to, jak Builder
, build
i merge
są realizowane - Builder
jest newtype otoki wokół funkcji (i jego skład jest tylko złożenie funkcji) i build
jest tylko funkcja aplikacji na skopiowanej wersji rekordu:
newtype Builder a b = Builder (a -> b)
build (Builder b) r1 = b (copyRecord r1)
W merge
jest unsafeMerge
wykonywane:
merge r2 = Builder \r1 -> unsafeMerge r1 r2
Więc w hy zyskujemy cokolwiek ?? Ponieważ możemy być pewni, że wyniki pośrednie nie mogą wymknąć się zakresowi funkcji, więc cała transformacja może zostać przeprowadzona na miejscu. Innymi słowy intermediate
wartość:
> intermediate = unionMerge name {email: "[email protected]"}
> unionMerge age intermediate
nie może być "ekstrakcji" stąd:
> build (merge name >>> merge age) {email: "[email protected]"}
system typów Komentarz:
Wydaje się, że układ typu Purescript może obsłużyć tego teraz dzięki klasa typu Union
z 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.
który ma tę "magiczną type" (źródło: slide 23):
Union r1 r2 r3 | r1 r2 -> r3, r1 r3 -> r2
stara metoda (nadal ważna, ale nie zalecane):
Jest purescript-records pakiet, który naraża unionMerge
który robi dokładnie to, co chce (w nowych psci nie musimy używać let
):
> import Data.Record (unionMerge)
> name = {name: "Jim"}
> age = {age: 37}
> :t (unionMerge age name)
{ name :: String
, age :: Int
}
Fajnie, dziękuję za wyjaśnienie. Ale żeby trochę wyjaśnić sprawy: Jak to działa z wierszem Eff. O ile rozumiem, wiersz typu Eff jest jak "skomponowany" z różnych typów efektów. Jak tam działa? –
Opiera się na zunifikowanych typach, więc w powyższym przykładzie, jeśli nazwiemy 'coś' z' {name :: String, age :: Int, address :: String} ', otrzymamy' r ~ (age: : Int, adres :: String) 'in' {nazwa :: String | r} '. Komponenty 'Eff' działają w podobny sposób, nigdy nie mamy w rzeczywistości czegoś, w czym dwie różne wartości' eff' są łączone z różnych argumentów w celu utworzenia nowego. –
OK, myślę, że nie. Wielkie dzięki. –