5

read と show (それ自体は問題ではありません) を使用してシリアライゼーション/デシリアライゼーションを作成しようとしていますが、データ型を拡張できる (ただし縮小しない) という意味で拡張可能です。

このタイプがあるとします:

data Foo = { bar :: Int } deriving (Show, Read)

そしてリスト:

foos = [Foo 1, Foo 2]

簡単にファイルに逆シリアル化できます。

hPutStrLn fileHand . ppShow $ foos

次に、シリアル化して戻すことができます。

!str <- hGetContents fileHand
let foosFromFile = fromMaybe [] $ (readMaybe :: String -> Maybe [Foo]) str

しかし、数か月後、'baz' フィールドを Foo 型に追加したいとします。古い形式のファイルからの直接のシリアル化は、読み取りでは機能しなくなります。ファイルを変換する必要があります (これはあまり必要ありません)。

では、ファイルからデータをシリアル化し、不足しているフィールドにデフォルト値を入力するためのエレガントな (プログラム自体に明示的なバージョン管理ロジックを配置することなく) ソリューションはありますか? 多分いくつかのタイプのトリック?

ありがとう。

4

4 に答える 4

4

ユースケースによっては、Yesod からの永続化を使用して、データベース内のデータを永続化することもできます。引用:

持続性は、型安全性と簡潔な宣言構文の基本原則に従います。その他の優れた機能は次のとおりです。

  • データベースに依存しません。PostgreSQL、SQLite、MySQL、および MongoDB に対するファースト クラスのサポートがあり、実験的な CouchDB のサポートが進行中です。
  • 本質的に非リレーショナルであるため、より多くのストレージ層を同時にサポートでき、結合によって発生するパフォーマンスのボトルネックの一部に制約されることはありません。
  • SQL データベースを扱う際のフラストレーションの主な原因は、スキーマの変更です。Persistent は、データベースの移行を自動的に実行できます。

Persistentは、次のような場合にデータの変更を処理します。

次の場合、スキーマが自動的に変更されます。

  • フィールドのデータ型が変更されました。ただし、データを変換できない場合、データベースはこの変更に反対する場合があります。
  • フィールドが追加されました。ただし、フィールドが null ではなく、既定値が指定されておらず (既定値については後で説明します)、データベースに既にデータがある場合、データベースはこれを許可しません。
  • フィールドが非 null から null に変換されます。反対の場合、Persistent はデータベースの承認を条件として変換を試みます。
  • 真新しいエンティティが追加されます。
于 2013-08-16T08:37:25.523 に答える
3

自分のものにアクセスしながらデータ レイアウトを変更できるようにしたいというのは、データベース管理システムを発明する決定的な動機の 1 つです。データを単純な SQLite テーブルにドロップすることを検討したことはありますか? あなたがやろうとしていることはやり過ぎかもしれませんが、いくつかの利点があります。

  • ほぼ間違いなく、テキストベースのエンコーディングよりも効率的です。
  • アプリケーションの外部から簡単に読み取ることができます (たとえば、正しいものが保存されていることを確認するため)。
  • 「ファイルの変換」は単純な SQL クエリになります。
  • 列セレクターとして使用しない場合でも*、古いコードはアプリケーションの新しいバージョンで作成されたものを読み取ることができます。(つまり、上位互換性と下位互換性があります)。
  • または、DB スキーマを読み取り、まだ存在しない列のデフォルト値を提供する単純なボイラープレート コードを読み書きすることもできます。

これがあなたのケースに適しているかどうかはわかりませんが、考える価値はあります。

于 2013-08-16T07:47:39.427 に答える
2

はい。多態的なフィールドを追加するだけです:

data Foo a = { bar :: Int, extra :: a } deriving (Show, Read)

a次に、シリアル化可能でなければならない制約を使用して、シリアル化インスタンスを定義します。

instance (Serialize a) => Serialize (Foo a) where ...

余分なフィールドを使用していない場合は、 a を挿入するだけ()です.()Serialize

編集:おっと、きれいな印刷について話していることに気づきました。同等の解決策は、次のような型クラスを定義することです。

class PrettyPrint a where
    pp :: a -> String

instance PrettyPrint () where
    pp () = ""

instance (PrettyPrint a) => PrettyPrint (Foo a) where
    pp = ... -- You fill this in
于 2013-08-16T06:23:02.167 に答える