Что такое идиоматический c способ получения значения с помощью «пути» foo / x / bar, где x изменяется? - PullRequest
0 голосов
/ 25 марта 2020

Я хотел бы сделать что-то вроде foo ^. x . bar, где x будет представлять различные имена, и каждое имя может иметь различный тип: x = {x1 :: X1, x2 :: X2, ..., xn :: Xn} (псевдокод).

В настоящее время я понимаю, что для каждого x мне понадобится отдельная линза, но есть ли способ абстрагироваться по промежуточным путям, используя некоторую форму подстановочного знака? Похоже, проблема в настоящее время состоит в том, что не все пути, которые могут быть сгенерированы путем замены в реальных типах (например, из Prism) подстановочного знака x, будут генерировать допустимые типы, поскольку некоторые типы могут не иметь дочерних узлов соответствующего типа (bar в примере выше).

В качестве более конкретного примера моя актуальная проблема связана с кодом, сгенерированным из прото-линзы. Имена, соответствующие набору x, например, prediction и freshFeatures в сгенерированном коде ниже:

historical ::
  forall f s a.
  (Prelude.Functor f,
   Data.ProtoLens.Field.HasField s "historical" a) =>
  Lens.Family2.LensLike' f s a
historical = Data.ProtoLens.Field.field @"historical"
maybe'dairycompTypes ::
  forall f s a.
  (Prelude.Functor f,
   Data.ProtoLens.Field.HasField s "maybe'dairycompTypes" a) =>
  Lens.Family2.LensLike' f s a
maybe'dairycompTypes
  = Data.ProtoLens.Field.field @"maybe'dairycompTypes"
maybe'freshFeatures ::
  forall f s a.
  (Prelude.Functor f,
   Data.ProtoLens.Field.HasField s "maybe'freshFeatures" a) =>
  Lens.Family2.LensLike' f s a
maybe'freshFeatures
  = Data.ProtoLens.Field.field @"maybe'freshFeatures"
maybe'historical ::
  forall f s a.
  (Prelude.Functor f,
   Data.ProtoLens.Field.HasField s "maybe'historical" a) =>
  Lens.Family2.LensLike' f s a
maybe'historical = Data.ProtoLens.Field.field @"maybe'historical"
maybe'penCap ::
  forall f s a.
  (Prelude.Functor f,
   Data.ProtoLens.Field.HasField s "maybe'penCap" a) =>
  Lens.Family2.LensLike' f s a
maybe'penCap = Data.ProtoLens.Field.field @"maybe'penCap"
maybe'prediction ::
  forall f s a.
  (Prelude.Functor f,
   Data.ProtoLens.Field.HasField s "maybe'prediction" a) =>
  Lens.Family2.LensLike' f s a
maybe'prediction = Data.ProtoLens.Field.field @"maybe'prediction"
penCap ::
  forall f s a.
  (Prelude.Functor f, Data.ProtoLens.Field.HasField s "penCap" a) =>
  Lens.Family2.LensLike' f s a
penCap = Data.ProtoLens.Field.field @"penCap"
prediction ::
  forall f s a.
  (Prelude.Functor f,
   Data.ProtoLens.Field.HasField s "prediction" a) =>
  Lens.Family2.LensLike' f s a
prediction = Data.ProtoLens.Field.field @"prediction"

prediction и freshFeatures, тогда имеют поля key, которые соответствуют bar в исходном примере. Поэтому я хотел бы получить доступ к key без указания родительского типа данных, prediction, freshFeatures, et c. Опять же, предостережение в том, что некоторые конструкторы-братья и сестры на одном уровне prediction и freshFeatures могут не иметь key. Я ожидаю, что opti c вернет Nothing в этом случае и Just key, если найден key.

Кроме того, в случае, если это полезно, вот авто сгенерированный код Prism для рассматриваемого конструктора данных:

_DairyCompEntry'PenCap ::
  Data.ProtoLens.Prism.Prism' DairyCompEntry'DairycompTypes Proto.Pencap.PerFilePenCapacityData
_DairyCompEntry'PenCap
  = Data.ProtoLens.Prism.prism'
      DairyCompEntry'PenCap
      (\ p__
         -> case p__ of
              (DairyCompEntry'PenCap p__val) -> Prelude.Just p__val
              _otherwise -> Prelude.Nothing)
_DairyCompEntry'Historical ::
  Data.ProtoLens.Prism.Prism' DairyCompEntry'DairycompTypes Proto.Historical.PerFileHistoricalData
_DairyCompEntry'Historical
  = Data.ProtoLens.Prism.prism'
      DairyCompEntry'Historical
      (\ p__
         -> case p__ of
              (DairyCompEntry'Historical p__val) -> Prelude.Just p__val
              _otherwise -> Prelude.Nothing)
_DairyCompEntry'Prediction ::
  Data.ProtoLens.Prism.Prism' DairyCompEntry'DairycompTypes Proto.CowPrediction.PerFilePredictionData
_DairyCompEntry'Prediction
  = Data.ProtoLens.Prism.prism'
      DairyCompEntry'Prediction
      (\ p__
         -> case p__ of
              (DairyCompEntry'Prediction p__val) -> Prelude.Just p__val
              _otherwise -> Prelude.Nothing)
_DairyCompEntry'FreshFeatures ::
  Data.ProtoLens.Prism.Prism' DairyCompEntry'DairycompTypes Proto.FreshFeatures.PerFileFreshFeatureData
_DairyCompEntry'FreshFeatures
  = Data.ProtoLens.Prism.prism'
      DairyCompEntry'FreshFeatures
      (\ p__
         -> case p__ of
              (DairyCompEntry'FreshFeatures p__val) -> Prelude.Just p__val
              _otherwise -> Prelude.Nothing)
...