2

私の目的のために、ある種の「プロパティ」を持つマップのようなコンテナーが必要です。オブジェクトが異なるプロパティを持つ可能性があります。プロパティにアクセスするために、私はControl.Lensを使用することにしました。これは非常に興味深いものです。しかし、そのようなロジックのレンズのような方法を見つけることができません。プロパティへのアクセス時に、それが存在しない場合は、代わりにデフォルト値を追加し、新しい値を返します。しかし、そこにある場合は、それを使用してください。

つまり、prop_testは True を返す必要があります。

type PropertyMap = Map.Map Int String
data Properties = Properties { _propertyMap :: PropertyMap }
  deriving (Eq)

makeLenses ''Properties

emptyProperties = Properties Map.empty

propertyLens pIndex = propertyMap . at pIndex . traverse

property1 = propertyLens 1
property2 = propertyLens 2
property3 = propertyLens 3

obj1Properties :: State Properties ()
obj1Properties = do
    property1 .= "Property1 value"
    property2 .= "Property2 value"

obj2Properties :: State Properties ()
obj2Properties = do
    property1 .= "Property1 value"
    property3 .= "Property3 value"

prop_test = op1 /= emptyProperties
    where
        op1 = execState obj1Properties emptyProperties

しかし今、op1 は emptyProperties と同じです。デフォルト値には、Data.Default を使用できます。どうすればこれを処理できますか? または、おそらく別の方法を使用する必要がありますか?たとえば、プロパティの存在をアンパックしてチェックする State モナドのラッパー関数です。

また、Control.Lens (または別のレンズ パッケージ) の実例へのリンクを教えてください。

4

2 に答える 2

3

Properties'Monoid' のインスタンスを作成し、2 つのマップのmempty和集合のように適切なものを作成するemptyPropertiesmappend、Lens ライブラリは正しいことを行います。

別の方法は、トラバーサル用に特別に設計されたコンビネータ (0 以上の結果を返すことができるレンズ) の 1 つを使用し、欠落しているケースを処理することです。(^?)which が を生成するMaybe tか、 which が を生成するかについてのドキュメントを参照して(^..)ください[t]

于 2013-09-15T06:46:22.403 に答える
0

ジョン F. ミラーの回答のおかげで、それについて考えていると、プロパティの使用を簡素化するためにラッパー関数が必要であることに気付きました。したがって、コードは次のようになります。

type PropertyMap = Map.Map Int String
data Properties = Properties { _propertyMap :: PropertyMap }
  deriving (Eq, Show)

emptyProperties = Properties Map.empty

makeLenses ''Properties

newtype PAccessor = PAccessor { pKey :: Int }

property1 = PAccessor 1
property2 = PAccessor 2
property3 = PAccessor 3

(|=) accessor v = do
    ps <- get
    put $ propertyMap . at (pKey accessor) ?~ v $ ps

setProperty = (|=)

getProperty accessor = do
    ps <- get
    return $ ps ^. propertyMap . ix (pKey accessor)

maybeProperty accessor = do
    ps <- get
    return $ ps ^. propertyMap . at (pKey accessor)

obj1Properties :: State Properties String
obj1Properties = do
    property1 |= "Property1 value"
    property2 |= "Property2 value"
    p1Val <- getProperty property1
    p3Val <- getProperty property3 -- Returns default value (empty string)
    return (p1Val ++ p3Val)

obj2Properties :: State Properties String
obj2Properties = do
    property2 |= "Property2 value"
    property3 |= "Property3 value"
    Nothing <- maybeProperty property1
    Just p2Val <- maybeProperty property2
    return p2Val

expectedProps1 = Properties $ Map.fromList [ (1, "Property1 value")
                                           , (2, "Property2 value") ]

expectedProps2 = Properties $ Map.fromList [ (2, "Property2 value")
                                           , (3, "Property3 value") ]

prop_test1 = (props == expectedProps1) && (val == "Property1 value")
    where
        (val, props) = runState obj1Properties emptyProperties

prop_test2 = (props == expectedProps2) && (val == "Property2 value")
    where
        (val, props) = runState obj2Properties emptyProperties

prop_test3 = val == "Property2 value"
    where
        val = evalState obj2Properties emptyProperties

すべてのテスト関数がパスします。つまり、結果は True に等しくなります。おまけとして、コードは と の違いを示していixますat。このソリューションを改善しようとしますが、今のところ問題ないようです。

于 2013-09-15T11:29:02.090 に答える