私はより多くの異なる型を作成するためにコード内にnewtype
ラッパーを使用しています。私はまた、リード/ショーを使って、特に強く型付けされた設定ファイルのシンプルな形式として、たくさんの安価なシリアル化を行います。今日はこのに走った:データ構造を含む派生クラスのインスタンスが使用されていません
例は次のように開始し、私は、アンラップのためにという名前のフィールドと一緒に、のIntをラップアラウンドする簡単なのnewtypeを定義しますから、これらのいずれかを読み取ることが
module Main where
import Debug.Trace (trace)
import Text.Read (readEither)
newtype Bar = Bar { unBar :: Int }
deriving Show
カスタムインスタンス単純なInt構文です。ここでのアイデアは、 "Bar {unBar = 42}"の代わりに "42"を設定ファイルに入れることができれば嬉しいです。
このインスタンスにはトレースがあり、このインスタンスがいつ表示されるかがわかります問題を観察するときに実際に使用されます。
instance Read Bar where
readsPrec _ s = [(Bar i, "")]
where i = read (trace ("[debug \"" ++ s ++ "\"]") s)
バーを含む別のタイプ。これは自動的に読み取りを派生させます。
data Foo = Foo { bar :: Bar }
deriving (Read, Show)
main :: IO()
main = do
だけでバータイプをデシリアライズすると、正常に動作して
print $ ((readEither "42") :: Either String Bar)
putStrLn ""
上記読むインスタンスを使用しますが、バーを含むいくつかの理由はFooのために、そして自動的に読む派生、ドリルダウンしてピックアップされていませんバーのインスタンス!
print $ ((readEither "Foo { bar = 42 }") :: Either String Foo)
putStrLn ""
のでOK(トレースからのデバッグメッセージがいずれかの表示されていないことに注意してください)、どのようにバーのデフォルトの表示形式については、デフォルトは右読むと一致する必要がありますか?
print $ ((readEither "Foo { bar = Bar { unBar = 42 } }") :: Either String Foo)
いいえ!どちらもうまくいかない!ここでも、デバッグメッセージはありません。ここで
は実行出力です:
$ stack exec readbug
[debug "42"]
Right (Bar {unBar = 42})
Left "Prelude.read: no parse"
Left "Prelude.read: no parse"
これは私にはバグだらけに見えるが、私はそれが間違ってやっていることを聞いてみたいです。
上記のコードの完全な使用例があります。ファイルsrc/Main.lhs
をtest project on darcshub
これは非常に良い質問です。誰かがあなたのコードのデバッグを開始したことをいかに簡単にしたのが大好きです。うまくいけば私の答えはあなたが持っている特定の問題を特定するのに役立ちます。それはさておき、私はデバッグ以外にも 'Read'を使うことを勧めないでしょう。そして、' read 'を確認してください。 show = id'。私は設定をJSON(エンコード/デコードに 'aeson'を使います)に入れたり、(カスタムパーサーを主張するなら)' attoparsec'や 'megaparsec'のようなものを使います。 'Read'は非効率なパーサです。なぜならどこにでも戻ってくるからです。 – Alec
あなたは間違っています: 'Foo' *の派生インスタンスはあなたが書いた' Bar'に対して 'Read'インスタンスを使用しています! 'Bar'が残りの入力をすべて消費したと誤って報告しているので、' Bar'の値を強制するのは面倒です(そのため、 'trace'を使ってサンクを強制することはありません)。 'Foo'読者は成功するために'} 'を見ません。 –
@Alec私はconfigsのためのJSONの使用を考えていませんでした。入力と階層構造を保持します。そして、あなたは他の言語/システムで使用可能な設定ファイルで終わります。私は今少し新しいタイプでこれを探検します。ありがとう! – dino