21

タイプを考えると

data Prisoner = P { _name   :: String
                  , _rank   :: Int
                  , _cereal :: Cereal }

data Cereal = C { _number             :: Int
                , _percentDailyValue  :: Map String Float
                , _mascot             :: String }

パターン マッチングを使用して、誰かの名前、ランク、およびシリアル番号を抽出できます。

getNameRankAndCerealNumber_0 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_0 (P { _name=name
                                , _rank=rank
                                , _cereal = C { _number=cerealNumber }}
                             ) = (name, rank, cerealNumber)

または、レンズを使用して各部分を個別に抽出することもできます

makeLenses ''Cereal
makeLenses ''Prisoner

getNameRankAndCerealNumber_1 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_1 p = (p ^. name, p ^. rank, p ^. cereal.number)

データ構造の 1 回の走査で 3 つすべてを同時に抽出する方法はありますか?

Getterを組み合わせる何らかのGetter s a -> Getter s b -> Getter s (a,b)方法

4

2 に答える 2

25

から newtypeのApplicativeインスタンスを使用できます。ReifiedGetterControl.Lens.Reified

runGetter $ (,) <$> Getter number <*> Getter mascot

一般に、newtypes は、Control.Lens.Reifiedゲッターとフォールドの非常に便利なインスタンスを多数提供します。

注#1 : レンズをゲッターとして結合し、代わりにゲッターを取得していることに注意してください。「焦点」が重なると問題が発生するため、この方法では複合レンズを取得できません。その場合、適切なセッターの動作は何でしょうか?

注#2 :横並び機能を使用すると、2 つのレンズを組み合わせて、製品の 2 つの半分で機能する本物のレンズを得ることができます。これは、レンズが重なっていないことを確認できるため、前のケースとは異なります。alongside型がタプルであるか、タプルと同型である場合に便利です。

于 2014-11-03T20:56:53.777 に答える
7

上記のdanidiazの答えGetter Prisoner (String, Int, Int)を具体化して、 usingを構築することができましたReifiedGetter

getNameRankAndCerealNumber_2 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_2 = p ^. nameRankAndCerealNumber_2

nameRankAndCerealNumber_2 :: Getter Prisoner (String, Int, Int)
nameRankAndCerealNumber_2 = runGetter ((,,) <$> Getter name <*> Getter rank <*> Getter (cereal.number))

との間との間との間を手動で作成する必要がありましたが、Lens' Prisoner (String, Int, Int)を使用しています。alongsideIso'PrisonerHList [String, Int, Int]HList [a,b,c](a,b,c)

getNameRankAndCerealNumber_3 :: Prisoner -> (String, Int, Int)
getNameRankAndCerealNumber_3 p = p ^. nameRankAndCerealNumber_3

setNameRankAndCerealNumber_3 :: (String, Int, Int) -> Prisoner -> Prisoner
setNameRankAndCerealNumber_3 t p = p & nameRankAndCerealNumber_3 .~ t

nameRankAndCerealNumber_3 :: Lens' Prisoner (String, Int, Int)
nameRankAndCerealNumber_3 = hlist . alongside id (alongside id number) . triple
  where triple :: Iso' (a,(b,c)) (a,b,c)
        triple = dimap (\(a,(b,c)) -> (a,b,c)) (fmap $ \(a,b,c) -> (a,(b,c)))
        hlist :: Iso' Prisoner (String, (Int, Cereal))
        hlist = dimap (\(P n r c) -> (n,(r,c))) (fmap $ \(n,(r,c)) -> P n r c)

これを行う簡単な方法があるかもしれませんが、それは別の問題です。

于 2014-11-07T03:17:32.640 に答える