可以从数据类型中一般性地删除函数类型,以允许deriveJSON?

时间:2015-07-12 08:30:07

标签: haskell generic-programming aeson

我有几种表示应用程序状态的数据类型。在数据类型的各个地方,我有嵌入函数或monadic动作,例如

data Foo = Foo Int (ActionM String)
data Bar = Bar Foo (Maybe Bar) (ActionM ())

我需要将大多数这些数据类型编码为json,以便将其发送到浏览器进行显示。使用deriveJSON(来自Aeson包)不起作用,因为无法派生ActionM的实例。但是,我实际上并不希望这些位被发送。我目前有一种方法可行,但基本上是复制粘贴整套数据类型并手动删除嵌入的ActionM字段。

我(我想)我需要做一件事。任

  • 一种告诉deriveJSON只是忽略它无法弄清楚的字段的方法,并且可能会将它们解析回undefined。据我所知,这不存在
  • 一种自动生成并行数据类型集的方法,删除了这些字段。所以我想写一些像
  • 这样的东西

applyMagic Bar

然后回来

data Foo' = Foo' Int
data Bar' = Bar' Foo' (Maybe Bar')

这是否有可能,我该怎么做?

1 个答案:

答案 0 :(得分:1)

这是一个简单的解决方案,但你不能做像

这样的事情
data Foo' = Foo' Int

type Foo = (ActionM String, Foo')

并且只想在序列化时获取元组的第二个元素?

元组是ComonadEnv的一个实例,因此您也可以使用askextract等函数。

编辑。 Bar是一个更复杂的案例,因为它是一种递归类型。但它可以使用CofreeT comonad转换器来处理:

import Data.Functor.Identity
import Data.Bifunctor (second)
import Control.Comonad -- from 'comonad'
import Control.Comonad.Hoist.Class
import Control.Comonad.Trans.Cofree -- from 'free'

-- Orphan ComonadHoist instance that will likely be added in future
-- versions of free
instance Functor f => ComonadHoist (CofreeT f) where
    cohoist g = CofreeT . fmap (second (cohoist g)) . g . runCofreeT

type Bar = CofreeT Maybe ((,) (ActionM ())) Foo
type Bar' = Cofree Maybe Foo'

applyMagic :: Bar -> Bar'
applyMagic = cohoist (Identity . extract) . fmap extract

CofreeT Maybe ((,) (ActionM ())) FooFoo值的非空列表,已使用ActionM ()值进行注释。

Cofree Maybe Foo'Foo'值的非空列表,没有额外注释(Cofree Maybe FooCofreeT Maybe Identity Foo'的同义词,其中Identity用作琐碎的comonad。)。

要将一个转换为另一个,applyMagic首先使用fmap extract将所有Foo转换为Foo',然后使用cohoist来自{ {1}}删除ComonadHoist下面的“注释图层”。

通常,具有“额外上下文”的值通常可以使用comonad建模。