将函数应用于类型级别的记录中的所有字段

Sau*_*nda 2 haskell types

有没有办法在类型系统中轻松完成以下操作?

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)
--  }
Run Code Online (Sandbox Code Playgroud)

它基本上是某种容器(仿函数?),它应用于类型级别的记录的每个字段.

这个想法是否可以用可扩展的记录库更好地表示?

编辑用例是我们将从ProductWithOmittableFieldsUI层获取一个,表示用户已更改的字段集; 我们将从Product数据库中获取一个,我们将合并它们以获得新值Product

chi*_*chi 5

一种可能的方式:

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
Run Code Online (Sandbox Code Playgroud)

例子:

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

testReg :: ProductWithRegularFields
testReg = Product
     { id = Identity someProductId
     , name = Identity someText
     ... }
Run Code Online (Sandbox Code Playgroud)

这种方法仅具有Identity在常规情况下用每个字段包裹的轻微不便.