EDIT:
Это seems, что в настоящее время официальный пакет для обработки записей манипуляций purescript-record
- вы можете найти Builder.purs там, который обеспечивает merge
и build
функции:
> import Data.Record.Builder (build, merge)
> name = {name: "Jim"}
> age = {age: 37}
> :t (build (merge age) name)
{ name :: String
, age :: Int
}
API Примечание:
Этот API выглядит сложнее с первого взгляда - особенно когда вы сравниваете его с простым unionMerge name age
call (unionMerge
- в конце этого ответа). Причина существования Builder
существования (и, следовательно, этого API) - это производительность. Я могу заверить вас, что это:
> build (merge name >>> merge age) {email: "[email protected]"}
создает только одну новую запись. Но это:
> unionMerge name (unionMerge age {email: "[email protected]"})
создает две записи во время исполнения.
Что еще более интересно, как Builder
, build
и merge
реализованы - Builder
является Newtype обертка функции (и ее состав просто композиция функций) и build
просто функционировать приложение на скопированной версии записи:
newtype Builder a b = Builder (a -> b)
build (Builder b) r1 = b (copyRecord r1)
В merge
есть unsafeMerge
выполняется:
merge r2 = Builder \r1 -> unsafeMerge r1 r2
Так ж мы что-то набираем? Поскольку мы можем быть уверены, что промежуточные результаты не могут избежать функциональной области, поэтому все преобразования могут быть выполнены на месте. Другими словами, это intermediate
значение:
> intermediate = unionMerge name {email: "[email protected]"}
> unionMerge age intermediate
не может быть «извлечены» отсюда:
> build (merge name >>> merge age) {email: "[email protected]"}
К.П системой типов:
кажется, что система типа Purescript может справиться с этим теперь, благодаря класс Union
типа от 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.
Что есть этот "магический тип" (источник: slide 23):
Union r1 r2 r3 | r1 r2 -> r3, r1 r3 -> r2
СТАРЫЙ МЕТОД (по-прежнему в силе, но не рекомендуется):
Существует purescript-records пакет, который предоставляет unionMerge
, который делает именно то, что вы хотите (в новых psci нам не нужно использовать let
):
> import Data.Record (unionMerge)
> name = {name: "Jim"}
> age = {age: 37}
> :t (unionMerge age name)
{ name :: String
, age :: Int
}
Прохладный, спасибо за объяснение. Но просто для того, чтобы немного рассказать о проблемах: как это работает с рядом Eff rowtype. Насколько я понимаю, тип строки Eff - это то, как «составлен» из разных типов эффектов. Как это работает? –
Он опирается на унифицированные типы, поэтому в приведенном выше примере, если мы будем называть 'something' с' {name :: String, age :: Int, address :: String} ', мы закончим с' r ~ (age: : Int, address :: String) 'in' {name :: String | r} '. «Эффект» работает аналогичным образом, у нас никогда не было чего-то, где два разных значения «eff» объединяются из разных аргументов для создания нового. –
ОК, я думаю, что не знаю. Большое спасибо. –