2016-03-14 4 views
5

Учитывая меня на следующие записи в purescript:Комбинат записей в Purescript

let name = {name: "Jim"} 
let age = {age: 37} 

является возможность объединить эти две записи, как некоторые в общем виде? Что-то вроде:

name 'comb' age 

таким образом, что я получаю следующую запись:

{name: "Jim", age: 37} 

почему-то кажется, что это возможно с Eff ROWTYPE, но мне интересно, если это будет возможно с «нормальным 'записей. Я новичок в purescript и это синтаксис записи.

Большое спасибо.

ответ

5

Это невозможно сделать в данный момент, так как у нас нет способа сказать, что в строке нет какой-либо ярлыка или другой. Можно иметь открытый тип записи:

something :: forall r. { name :: String | r } -> ... 

Но это позволяет только принять запись с name и любые другие метки, это не поможет нам, если мы хотим объединить, расширить или вычитать от записей в его нынешнем виде.

Проблема с объединения произвольных записей мы бы сигнатуру типа так:

comb :: forall r1 r2. { | r1 } -> { | r2 } -> ??? 

Нам нужно каким-то образом сказать результат (???) является объединением r1 и r2, но и мы Возможно, вам захочется сказать, что метки r1 не перекрываются с r2.

В будущем это может быть возможно через row constraints.

+0

Прохладный, спасибо за объяснение. Но просто для того, чтобы немного рассказать о проблемах: как это работает с рядом Eff rowtype. Насколько я понимаю, тип строки Eff - это то, как «составлен» из разных типов эффектов. Как это работает? –

+0

Он опирается на унифицированные типы, поэтому в приведенном выше примере, если мы будем называть 'something' с' {name :: String, age :: Int, address :: String} ', мы закончим с' r ~ (age: : Int, address :: String) 'in' {name :: String | r} '. «Эффект» работает аналогичным образом, у нас никогда не было чего-то, где два разных значения «eff» объединяются из разных аргументов для создания нового. –

+0

ОК, я думаю, что не знаю. Большое спасибо. –

7

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 
} 
Смежные вопросы