2016-10-21 5 views
2

Есть ли способ сделать следующее в системе типов легко?Применить функцию ко всем полям записи на уровне уровня

data Product = Product { 
    id :: ProductId 
    , name :: Text 
    , sku :: SKU, quantity :: Int 
    , description :: Maybe Text 
    } 

data Omittable a = Omit | Present a 
type ProductWithOmittableFields = Omittable Product 

-- ProductWithOmittableFields is now equivalent to:\ 
-- 
-- data ProductWithOmittableFields = ProductWithOmmitableFields { 
--  id :: Omittable ProductId 
-- ,name :: Omittable Text 
-- ,sku : : Omittable SKU 
-- ,quantity :: Omittable Int 
-- ,desciption :: Omittable (Maybe Text) 
-- } 

Это в основном своего рода контейнера (функтора?), Который применяется к каждому полю записи на уровне типа.

Является ли эта идея лучше представленной библиотекой расширяемых записей?

Редактировать В случае использования мы получим ProductWithOmittableFields с уровня пользовательского интерфейса, представляющего набор полей, которые были изменены пользователем; мы получим Product из БД, и мы будем объединять их, чтобы получить новое значение Product

+1

«Является ли эта идея лучше представленной библиотекой расширяемых записей?» Существует библиотека под названием «generics-sop», которая позволяет вам делать что-то подобное. См. Другие вопросы: http://stackoverflow.com/questions/39020787/is-there-a-way-to-apply-maybe-constructor-to-each-field-of-record-with-generics и http://stackoverflow.com/questions/38248692/whats-a-better-way-of-managing-large-haskell-records – danidiaz

ответ

4

Возможный способ:

import Control.Functor.Identity 

data Product k = Product { 
    id :: k ProductId 
    , name :: k Text 
    , sku :: k SKU 
    , quantity :: k Int 
    , description :: k (Maybe Text) 
    } 

data Omittable a = Omit | Present a 
type ProductWithOmittableFields = Product Omittable 
type ProductWithRegularFields = Product Identity 

Примеры:

testOmit :: ProductWithOmittableFields 
testOmit = Product 
    { id = Present someProductId 
    , name = Omit 
    ... } 

testReg :: ProductWithRegularFields 
testReg = Product 
    { id = Identity someProductId 
    , name = Identity someText 
    ... } 

Этот подход имеет только небольшое неудобство обертывания каждого поля с помощью Identity в обычном случае.

+0

Каков самый простой способ получить 'ProductWithRegularFields' из' Product Identity' на уровне значений (т. е. во время выполнения)? –

+0

@SaurabhNanda Вам не нужно ничего делать, они точно такие же. Выше я использовал синонимы типа 'type T =' вместо объявления данных новых типов T = ... '. – chi

+0

позвольте мне перефразировать. Как получить значение «Product», где каждое поле НЕ является «Identity x»? –

Смежные вопросы