如何将函数类型序列化为haskell中的json? [英] How to serialize function type to json in haskell?

查看:104
本文介绍了如何将函数类型序列化为haskell中的json?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  data Task =任务
{id :: String
,description :: String
,dependsOn :: [String]
, dependentTasks :: [String]
}派生(Eq,Show,Generic,ToJSON,FromJSON)

类型Storage = Map String任务

s :: Storage
s =空

addTask ::任务 - >存储 - >存储
addTask(任务id desc dep dept)=插入id(任务id desc dep dept)

removeTask :: String - >存储 - >存储
removeTask tid =删除tid

变化= [addTask(任务1描述[] []),removeTask1]

main = putStrLn。显示$ foldl(\s c - > c s)s更改

假设我有以下代码。我想在json文件中存储修改列表。但是我不知道如何与Aeson做到这一点,除了编写自定义解析器外,还有一个更好的方法可以做到这一点。就像可能使用语言扩展为 addTask removeTask派生(Generic,ToJSON,FromJSON) etc ...



编辑。对于所有说你不能序列化函数的人。



阅读评论以回答这个问题。



实例显示功能


也就是说,不可能将Show定义为实际给你多
?有关功能的细节。 - 路易Wasserman 12年5月12日在14:51



当然是。它可以显示类型(通过Typeable给出);或者它可以显示一些输入和输出(就像在QuickCheck中完成的那样)。

编辑2。好的,我知道我不能在序列化中使用函数名。但是,这可以通过模板Haskell完成吗?我看到aeson支持通过模板Haskell进行序列化,但作为Haskell的新手无法弄清楚如何做到这一点。 解决方案

在一行之间进行阅读,这里一个反复出现的问题是,为什么我不能序列化一个函数(很容易)?答案 - 几个人提到但没有明确解释 - 是Haskell致力于参照透明度。引用透明性表示,您可以用定义的值替换定义(反之亦然),而不会改变程序的含义。

所以,现在假设我们有一个假设 serializeFunction ,其中包含以下代码:

  foo xy = x + y + 3 

会有这样的行为:

 > serializeFunction(foo 5)
foo 5

我想你也不会反对如果我还声称在

  bar xy = x + y + 3 

我们会想要这种行为:

 > serializeFunction(bar 5)
bar 5

现在我们有一个问题,因为by reference transparency

$ $ $ $ $ $ $ $ $ b $ serializeFunction(\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\') y - > 5 + y + 3)
= {bar的定义}
serializeFunction(bar 5)

foo 5不等于bar 5



显而易见的后续问题是:为什么我们要求引用透明度?至少有两个很好的理由:第一,它允许像上面那样的等式推理,从而减轻了重构的负担;其次,它减少了所需的运行时信息量,从而提高了性能。

当然,如果您能够提出一个尊重参照透明度的函数表示形式,这没有问题。这里有一些方向:


  • 打印函数的类型

      instance(Typeable a,Typeable b)=>显示(a  - > b)其中
    show = show。 typeOf
    - 只能为平凡函数写一个Read实例


  • 打印输入输出行为(也可以

     数据名称a =命名字符串a 
    实例显示(命名a)其中
    show(Named n _)= n
    - 也许你可以写一个实例Read(Map String a - >命名a)

    (另请参阅云haskell 以获得更完整的工作这个想法)


  • 构造一个代数数据类型,它可以表示您关心的所有表达式,但仅包含已具有 Show 的基本类型>实例和序列化(例如如其他答案中所述)


    但是打印一个裸函数的名字与引用透明性有冲突。

  • >

    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
    

    Suppose I have the following code. I want to store changes list in a json file. But I don't know how to do that with Aeson, aside probably from writing a custom parser and there must be a better way to do that obviously. Like maybe using language extension to derive (Generic, ToJSON, FromJSON) for addTask and removeTask etc...

    EDIT. For all people that say "You can't serialize function".

    Read the comments to an answer to this question.

    Instance Show for function

    That said, it's not possible to define Show to actually give you more ? detail about the function. – Louis Wasserman May 12 '12 at 14:51

    Sure it is. It can show the type (given via Typeable); or it can show some of the inputs and outputs (as is done in QuickCheck).

    EDIT2. Okay, I got that I can't have function name in serialization. But can this be done via template Haskell? I see that aeson supports serialization via template Haskell, but as newcomer to Haskell can't figure out how to do that.

    解决方案

    Reading between the lines a bit, a recurring question here is, "Why can't I serialize a function (easily)?" The answer -- which several people have mentioned, but not explained clearly -- is that Haskell is dedicated to referential transparency. Referential transparency says that you can replace a definition with its defined value (and vice versa) without changing the meaning of the program.

    So now, let's suppose we had a hypothetical serializeFunction, which in the presence of this code:

    foo x y = x + y + 3
    

    Would have this behavior:

    > serializeFunction (foo 5)
    "foo 5"
    

    I guess you wouldn't object too strenuously if I also claimed that in the presence of

    bar x y = x + y + 3
    

    we would "want" this behavior:

    > serializeFunction (bar 5)
    "bar 5"
    

    And now we have a problem, because by referential transparency

      serializeFunction (foo 5)
    = { definition of foo }
      serializeFunction (\y -> 5 + y + 3)
    = { definition of bar }
      serializeFunction (bar 5)
    

    but "foo 5" does not equal "bar 5".

    The obvious followup question is: why do we demand referential transparency? There are at least two good reasons: first, it allows equational reasoning like above, hence eases the burden of refactoring; and second, it reduces the amount of runtime information that's needed, hence improving performance.

    Of course, if you can come up with a representation of functions that respects referential transparency, that poses no problems. Here are some ideas in that direction:

    • printing the type of the function

      instance (Typeable a, Typeable b) => Show (a -> b) where
          show = show . typeOf
      -- can only write a Read instance for trivial functions
      

    • printing the input-output behavior of the function (which can also be read back in)

    • creating a data type that combines a function with its name, and then printing that name

      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)
      

      (and see also cloud haskell for a more complete working of this idea)

    • constructing an algebraic data type that can represent all the expressions you care about but contains only basic types that already have a Show instance and serializing that (e.g. as described in the other answer)

    But printing a bare function's name is in conflict with referential transparency.

    这篇关于如何将函数类型序列化为haskell中的json?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆