Haskell 是否可以从数据类型中删除函数类型,以允许deriveJSON?
我有几个代表应用程序状态的数据类型。在数据类型的不同位置,我有嵌入式函数或一元操作,例如Haskell 是否可以从数据类型中删除函数类型,以允许deriveJSON?,haskell,generic-programming,aeson,Haskell,Generic Programming,Aeson,我有几个代表应用程序状态的数据类型。在数据类型的不同位置,我有嵌入式函数或一元操作,例如 data Foo = Foo Int (ActionM String) data Bar = Bar Foo (Maybe Bar) (ActionM ()) 我需要将这些数据类型中的大多数编码为json,以便将其发送到浏览器进行显示。使用deriveJSON(来自Aeson包)不起作用,因为无法派生ActionM的实例。然而,我实际上并不希望这些信息被发送出去。我目前有一种方法可以工作,但基本上是复制粘
data Foo = Foo Int (ActionM String)
data Bar = Bar Foo (Maybe Bar) (ActionM ())
我需要将这些数据类型中的大多数编码为json,以便将其发送到浏览器进行显示。使用deriveJSON(来自Aeson包)不起作用,因为无法派生ActionM的实例。然而,我实际上并不希望这些信息被发送出去。我目前有一种方法可以工作,但基本上是复制粘贴全套数据类型并手动删除嵌入的ActionM字段
我(想我)需要一些东西中的一个。或者
- 这是一种告诉deriveJSON忽略它无法理解的字段,并可能将它们解析回未定义的
。据我所知,这是不存在的 - 一种在删除这些字段的情况下自动生成并行数据类型集的方法。所以我想写一些像
applyMagic条
回来
data Foo' = Foo' Int
data Bar' = Bar' Foo' (Maybe Bar')
这有可能吗?我该怎么做呢?这是一个过于简单的解决方案,但是你不能像这样做吗
data Foo' = Foo' Int
type Foo = (ActionM String, Foo')
当您想要序列化时,只需获取元组的第二个元素
元组是的一个实例,因此您还可以使用函数,如ask
和extract
编辑。Bar
是一种更复杂的情况,因为它是递归类型。但可以使用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()))Foo
是用ActionM()
值注释的Foo
值的非空列表
Cofree-Maybe-Foo'
是一个非空的Foo'
值列表,没有额外的注释(Cofree-Maybe-Foo
是CofreeT-Maybe-Identity-Foo'
的同义词,其中Identity
起到了次要的作用。)
要将一个转换为另一个,applyMagic
首先使用fmap extract
将所有Foo
s转换为Foo'
s,然后使用fromcomonadjust
删除CofreeT
下面的“注释层”
一般来说,带有“额外上下文”的值通常可以用comonads建模。如果
ActionM
是data
或newtype
您可以为它定义一个ToJSON
实例,将其编码为一些简单的JSON值(例如0或“”),那么您可以自动派生Foo
的ToJSON。它仍然会包含一个额外的简单值,但它会为您节省大量的工作。您如何将此扩展到包含Bar
?@ajp我已将我的答案扩展到包含Bar
。