2017-03-09 5 views
0
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でそれをどうやって行うのか分かりません。おそらくカスタムパーサーを書くことを除いて、明らかにそれを行うためのよりよい方法が必要です。多分、addTaskremoveTaskなど(Generic, ToJSON, FromJSON)を得るために言語拡張を使用するのと同じように...関数型をhaskellでjsonにシリアル化するには?

EDIT。 「あなたは機能をシリアライズできません」と言うすべての人々にとって。

この質問に対する回答を読む。

Instance Show for function

言った、それは実際にあなたに 多くを与えるためにショーを定義することはできませんか?関数の詳細。 - Louis Wasserman May 12 '12 at 14:51

確かです。タイプを示すことができます(Typeableで指定します)。 QuickCheckのように入力と出力の一部が表示されることがあります。

EDIT2。さて、私はシリアル化で関数名を持つことはできません。しかしこれはテンプレートHaskellで行うことができますか?私はaesonがHaskellテンプレートを介したシリアライゼーションをサポートしていることを知っていますが、ハスケルの新人はそのやり方を理解できません。

+0

機能を「表示」したり、シリアライズしたり、比較したり、吟味したりすることはできません。 –

+0

@ n.mええと...私は明らかに、関数アプリケーションを直列化し、手で逆シリアル化することはできますか?なぜこれは自動的に行うことが不可能であるべきですか?これはむしろ整備士です...あなたは関数名を持っています。あなたはその型を知っています。 – user1685095

+0

@ n.m。参照透過などのために関数を表示することはできません。私が望むものは何もする必要はありません。私は関数名と引数を見たいと思っています。それだけです。 – user1685095

答えて

2

はあなたの関数や評価関数のデータ型作る:線間のビットを読み取る

data TaskFunction = AddTask Task | RemoveTask String 
    deriving (Eq, Show, Generic, ToJSON, FromJSON) 

eval :: TaskFunction -> Storage -> Storage 
eval (AddTask t) = addTask t 
eval (RemoveTask t) = removeTask t 

changes = [AddTask (Task "1" "Description" [] []), RemoveTask "1"] 

main = putStrLn . show $ foldl (\s c -> c s) s (eval <$> changes) 
+0

ええ、それは私が欲しくない明らかな解決策です。 evalは単に 'apply'です。なぜこの定型コードが必要なのかわかりません。 – user1685095

+3

私は狂ったと言いますが、私は複雑な一回限りの魔法の解決策よりも定型文を好む。これは明白で理解しやすい。 – user2297560

+0

@ user1685095 "なぜこの定型コードが必要なのかわかりません" - 関数をシリアライズすることはできませんが、それが行うことの適切なマテリアライズド表現をシリアル化することができます。 – duplode

3

を、ここでの定期的な質問は「なぜ私は(簡単に)機能をシリアル化できないのですか?」であり、いくつかの人々が言及しているが、はっきりと説明されていない答えは、ハスケルが参照透明性に専念しているということです。参照透過性は、プログラムの意味を変えずに定義をその定義された値(またはその逆)に置き換えることができると言います。

foo x y = x + y + 3 

この動作を持っているでしょう:

> serializeFunction (foo 5) 
"foo 5" 

私はあなたがあまりにも反対しないだろうと思い

だから今、我々は、このコードの存在下で仮想的なserializeFunctionを、持っていたと仮定してみましょうもし私がその存在の中でそれを主張していれば、激しくも、私はそれを主張しています。

we woul dがこの振る舞い "欲しい":

> serializeFunction (bar 5) 
"bar 5" 

をそして今、我々は理由

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

しかし"foo 5""bar 5"等しくない参照透明性によって、問題を抱えています。

明らかなフォローアップの質問は、なぜ参照透過性を要求するのかです。少なくとも2つの理由があります。まず、上記のような等式推論が可能なため、リファクタリングの負担が軽減されます。第2に、必要なランタイム情報の量を減らし、パフォーマンスを向上させます。

もちろん、参照透過を尊重する関数の表現を考え出すことができれば、問題はありません。ここでいくつかのアイデアは、その方向にある:(CANもbe read back in)関数の

  • 機能の種類を印刷

    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

  • 組み合わせたデータ型を作成します名前をつけてその名前を印刷すると、その名前が印刷されます。

    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) 
    

    (とこのアイデアのより完全な作業のためにもcloud haskell参照)

  • あなたが気にすべての式を表すことができ代数的データ型を構築したが、すでにShowインスタンスを持っているだけで基本的なタイプが含まれていることをシリアライズ(例えば

しかし、裸の関数の名前を印刷することは、参照用の透明性と矛盾しています。

+0

私は 'Typeable'インスタンスがHackageのどこかに存在すると確信しています。誰かが知っている場合は、私にコメントを残すか、先に進んで、私のサンプルインスタンスをそのリンクに直接置き換えてください。 –

+0

説明をありがとうが、テンプレートHaskellで定型句を避けることが可能でしょうか?もしそうなら、エーゼンでそれをする方法よりも? – user1685095

+0

@ user1685095私はあなたにそれを打ち、あなたが立ち往生した場所を詳述する新鮮な質問を開くことをお勧めします。私はまた、あなたが慎重に自分のリンクを読んで、他の人たちがすでに行った作業を複製しないようにすることをお勧めします。 –

関連する問題