【问题标题】:Apply a function to all fields in a record at the type-level在类型级别将函数应用于记录中的所有字段
【发布时间】:2016-10-22 09:38:46
【问题描述】:

有没有办法在类型系统中轻松做到以下几点?

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)
--  }

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

用可扩展的记录库能更好地表达这个想法吗?

edit用例是我们会从UI层得到一个ProductWithOmittableFields,代表已经被用户改变的字段集合;我们将从数据库中得到一个Product,我们将它们合并得到Product的新值

【问题讨论】:

标签: haskell types


【解决方案1】:

一种可能的方式:

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 包装每个字段的小不便。

【讨论】:

  • 在价值级别(即运行时)从Product Identity 获取ProductWithRegularFields 的最简单方法是什么?
  • @SaurabhNanda 您无需执行任何操作,它们是完全相同的类型。上面我使用了类型同义词type T = ,而不是声明新类型data T = ...
  • 让我改写一下。如何在每个字段都不是 Identity x 的情况下获得 Product 值?
  • 在这种方法中,每个字段都有k x 的类型,对于一些k。它不能有 x 类型。
  • @SaurabhNanda chi 是对的。另一方面,Identity a 一个 a 值,除了烦人的 Identity 包装器。您可以在使用(<$>)(<*>) 操作基础值时假装包装器不存在,或者使用runIdentity 摆脱包装器。
猜你喜欢
  • 2014-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-25
  • 1970-01-01
  • 2014-10-27
  • 1970-01-01
  • 2018-11-11
相关资源
最近更新 更多