如何使用类型级别的可选字段表示数据?

Mas*_*tic 4 haskell

我正在研究控制流的数据,它有一个值(多态,可以是其他),它也可以有一个验证器函数来检查值是否仍然很好,并且可以有一个"刷新值"的函数(返回带有新值的新数据).

在vanilla Haskell中,它看起来像这样:

data MyData a = MyData
  {value :: a
  ,validator :: Maybe (a -> Bool)
  ,refresher :: Maybe (MyData a -> MyData a)}
Run Code Online (Sandbox Code Playgroud)

我真正想要的是这些类型:

data Refreshable = Refreshable | NotRefreshable
data Validatable = Validatable | NotValidatable
MyData (r :: Refreshable) (v :: Validatable)
Run Code Online (Sandbox Code Playgroud)

我已经做到了,但只有Refreshable.我也想这样做,Validatable但我遇到了构造函数的问题.仅仅因为Refreshable我需要有两个构造函数,一个用于可刷新数据,另一个用于不可刷新数据.有了可验证的,我需要有4个构造函数!(用于可刷新和可验证,不可刷新和可验证,可验证和不可刷新,以及不可刷新和不可验证的).想象一下,如果我以后需要另一个可选字段.更糟糕的是:几乎所有的领域都是相同的,除了那些正在改变的领域,因此有太多的重复.


我也尝试用类型类/类型系来修改这种情况.
例如,MyData 'Refreshable 'NotValidatable只是成为Refreshable data => data,我可以实例MyData或只是删除它可以作为一个实例的更具体的数据.

这也是有问题的,因为它们不再是真正的领域; 即我没有验证器就无法获取数据,使用验证器(不是类型级别)将其更改为相同的数据.


这可能是一个XY问题; 我认为一个更简洁的方法是使数据类型,如Refreshable aValidatable a谱写他们MyData,但我不知道该怎么做.我不能包装它们因为订单会改变一切.

有干净的方法吗?或者我应该坚持使用4个构造函数?或者也许Haskell还没有为这类事做好准备呢?(没有双关语:P).

chi*_*chi 6

这样的东西会满足你的要求吗?

import Control.Applicative (Const)
import Data.Functor.Identity

data MyData kv kr a = MyData
  {value :: a
  ,validator :: kv (a -> Bool)
  ,refresher :: kr (MyData a -> MyData a)}

-- examples
type FullData a      = Data Identity   Identity   a
type EmptyData a     = Data (Const ()) (Const ()) a
type ValidableData a = Data Identity   (Const ()) a
Run Code Online (Sandbox Code Playgroud)

需要一些包装/展开(for Identity).

它可以定义助记符别名type Present = Identitytype Missing = Const (),与一些扩展.


或者,

data MyData (v :: Opt) (r :: Opt) a = MyData
  {value :: a
  ,validator :: Validator v a
  ,refresher :: Refresher r a}

data Opt = Yes | No

type family Validator (o :: Opt) a where
    Validator Yes = (a -> Bool)
    Validator No  = ()
-- etc.

-- examples
type FullData a      = Data Yes Yes a
type EmptyData a     = Data No  No  a
type ValidableData a = Data Yes No  a
Run Code Online (Sandbox Code Playgroud)