data Task = Task
{ id :: String
, description :: String
, dependsOn :: [String]
, dependentTasks :: [String]
} deriving (Eq, Show, Generic, ToJSON, FromJSON)
type Storage = Map String Task
s :: Storage
s = empty
addTask :: Task -> Storage -> Storage
addTask (Task id desc dep dept) = insert id (Task id desc dep dept)
removeTask :: String -> Storage -> Storage
removeTask tid = delete tid
changes = [addTask (Task "1" "Description" [] []), removeTask "1"]
main = putStrLn . show $ foldl (\s c -> c s) s changes
假设我有以下代码。我想存储changes
列表在 json 文件中。但我不知道如何使用 Aeson 来做到这一点,除了编写自定义解析器之外,显然肯定有更好的方法来做到这一点。就像也许使用语言扩展来派生(Generic, ToJSON, FromJSON)
for addTask
and removeTask
etc...
编辑。对于所有说“你不能序列化函数”的人。
阅读此问题答案的评论。
函数的实例显示 https://stackoverflow.com/questions/10551210/instance-show-for-function
也就是说,不可能定义 Show 来真正为您提供更多
?有关该功能的详细信息。 – 路易斯·沃瑟曼 2012 年 5 月 12 日 14:51
就是这样。它可以显示类型(通过 Typeable 给出);或者它可以显示一些输入和输出(如 QuickCheck 中所做的那样)。
编辑2。好吧,我知道序列化中不能有函数名称。但这可以通过 Haskell 模板来完成吗?我看到 aeson 通过模板 Haskell 支持序列化,但作为 Haskell 的新手,不知道如何做到这一点。
仔细阅读字里行间,这里反复出现的一个问题是:“为什么我不能(轻松地)序列化函数?”答案——有几个人提到过,但没有明确解释——是 Haskell 致力于引用透明性。引用透明度表示您可以用定义的值替换定义(反之亦然),而无需更改程序的含义。
现在,假设我们有一个假设serializeFunction
,在存在此代码的情况下:
foo x y = x + y + 3
会有这样的行为:
> serializeFunction (foo 5)
"foo 5"
我想如果我也当着所有人的面声称这一点,你不会太强烈地反对
bar x y = x + y + 3
我们会“想要”这种行为:
> serializeFunction (bar 5)
"bar 5"
现在我们有一个问题,因为通过引用透明度
serializeFunction (foo 5)
= { definition of foo }
serializeFunction (\y -> 5 + y + 3)
= { definition of bar }
serializeFunction (bar 5)
but "foo 5"
不相等"bar 5"
.
明显的后续问题是:为什么我们要求引用透明度?至少有两个很好的理由:首先,它允许像上面这样的等式推理,从而减轻重构的负担;其次,它减少了所需的运行时信息量,从而提高了性能。
当然,如果您能够提出尊重引用透明度的函数表示,那就不会造成任何问题。以下是这个方向的一些想法:
-
打印函数的类型
instance (Typeable a, Typeable b) => Show (a -> b) where
show = show . typeOf
-- can only write a Read instance for trivial functions
打印输入输出行为 http://hackage.haskell.org/package/universe-reverse-instances-1.0/docs/src/Data-Universe-Instances-Show.html函数的(也可以被读回 http://hackage.haskell.org/package/universe-reverse-instances-1.0/docs/src/Data-Universe-Instances-Read.html)
-
创建一个将函数与其名称相结合的数据类型,然后打印该名称
data Named a = Named String a
instance Show (Named a) where
show (Named n _) = n
-- perhaps you could write an instance Read (Map String a -> Named a)
(另请参阅云哈斯克尔 http://hackage.haskell.org/package/distributed-process为了更完整地实现这个想法)
构造一个代数数据类型,它可以表示您关心的所有表达式,但仅包含已经具有的基本类型Show
实例并序列化该实例(例如,如其他答案中所述)
但是打印裸函数的名称与引用透明度相冲突。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)