私はいくつかの特殊なフォームだけで普通の木に非常に似ているいくつかのデータ型を持っています。ネストされたフィールドをレンズで初期化する便利な方法
data NestedTree = NT
{ _dummy :: Int
, _tree :: HashMap String NestedTree
} deriving (Show)
makeLenses ''NestedTree
レンズを使用してデータ型のインスタンスを必須に初期化したいとします。
example :: NestedTree
example = flip execState (NT 0 mempty) $ do
dummy .= 3
tree.at "foo" ?= flip execState (NT 0 mempty) (dummy .= 10)
あなたは私が(NT 3 mempty)
との最初(NT 0 mempty)
を置き換えることができ、この例で観察することができますが、これはポイントではありません。ここで私は今、得たものです。私が望むのは、この素敵な命令的なスタイルを使ってネストされたHashMap
を初期化することもできます。より正確な、私はこのような何かを書くことができるようにしたい:
example :: NestedTree
example = flip execState (NT 0 mempty) $ do
dummy .= 3
tree.at "foo" ?= flip execState (NT 0 mempty) $ do
dummy .= 10
tree.at "foo nested" ?= NT 5 mempty
tree.at "bar" ?= flip execState (NT 0 mempty) $ do
dummy .= 15
tree.at "bar nested" ?= NT (-3) mempty
私の実際のデータ構造はより複雑であり、それは非常にすぐに単純なレコードを使用して、それを初期化するために、本当に醜いとなります。だから私はある種のDSLを使いたいと思っています。しかし、上記のコードはコンパイルされていないことに気付くことができます。
($)
の優先順位が最も低く、私はtree.at "foo" ?= flip execState (NT 0 mempty) $ do
と書くことはできません。しかし、実際には入れ子になったdo
の周りに()
を追加したくありません。
このような関数を書くために、任意の演算子を$
とdo
と混在させる良い方法はありますか?私は本当にwordsAssign = (?=)
のようないくつかのヘルパーを紹介し、私は?=
オペレータが好きなので
wordsAssign (tree.at "foo") $ flip execState (NT 0 mempty) $ do
のような関数を呼び出す必要はありません。たぶん私は間違ったことをやっているのですが、私がやりたいこのようなことは、手作業で書かれた演算子を使ってレンズなしで行うことができますか?
感謝を!私はこのアプローチを試み、それは魔法のように機能します。もし誰かが興味があれば:ズーム機能(https://github.com/serokell/log-warper/blob/91d82ed1b3a331ed4a8e0f458390f985028d1817/src/System/Wlog/LoggerConfig.hs#L120)で私を助けるユーティリティ機能、そしてここで私がどのように使用するか(https ://github.com/serokell/log-warper/blob/91d82ed1b3a331ed4a8e0f458390f985028d1817/test/Test/Wlog/RollingSpec.hs#L69) – Shersh