我有几种表示应用程序状态的数据类型。在数据类型的各个地方,我有嵌入函数或monadic动作,例如
data Foo = Foo Int (ActionM String)
data Bar = Bar Foo (Maybe Bar) (ActionM ())
我需要将大多数这些数据类型编码为json,以便将其发送到浏览器进行显示。使用deriveJSON(来自Aeson包)不起作用,因为无法派生ActionM的实例。但是,我实际上并不希望这些位被发送。我目前有一种方法可行,但基本上是复制粘贴整套数据类型并手动删除嵌入的ActionM字段。
我(我想)我需要做一件事。任
undefined
。据我所知,这不存在 applyMagic Bar
然后回来
data Foo' = Foo' Int
data Bar' = Bar' Foo' (Maybe Bar')
这是否有可能,我该怎么做?
答案 0 :(得分:1)
这是一个简单的解决方案,但你不能做像
这样的事情data Foo' = Foo' Int
type Foo = (ActionM String, Foo')
并且只想在序列化时获取元组的第二个元素?
元组是ComonadEnv
的一个实例,因此您也可以使用ask
和extract
等函数。
编辑。 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 ())) Foo
是Foo
值的非空列表,已使用ActionM ()
值进行注释。
Cofree Maybe Foo'
是Foo'
值的非空列表,没有额外注释(Cofree Maybe Foo
是CofreeT Maybe Identity Foo'
的同义词,其中Identity
用作琐碎的comonad。)。
要将一个转换为另一个,applyMagic
首先使用fmap extract
将所有Foo
转换为Foo'
,然后使用cohoist
来自{ {1}}删除ComonadHoist
下面的“注释图层”。
通常,具有“额外上下文”的值通常可以使用comonad建模。