Эквивалент класса данных ярлыка объектива в стиле кортежа `_1`?

Согласно его документации, библиотека Haskell lens _1 предоставляет линзу для кортежей.

Для записей данных вместо этого есть несколько других функций, таких как makeLenses, автоматически генерирующих линзы на основе имен полей записи.

К сожалению, я имею дело с классами данных без именованных полей, то есть у меня появляется makeLenses. Это заставляет меня задуматься. _1 кажется довольно удобным, но, как следует из его документации, не работает с классами данных. Есть ли аналог аналогичного уровня удобства?

> :set -package lens
> import Control.Lens
> (1,2) ^. _1
1
> data Bar = Bar String deriving Show
> bar = Bar "abc"
> bar ^. _1

<interactive>:271:1: error:
    • Non type-variable argument in the constraint: Field1 Bar Bar b b
      (Use FlexibleContexts to permit this)
    • When checking the inferred type
        it :: forall b. Field1 Bar Bar b b => b

Добавляя расширение FlexibleContexts, я сталкиваюсь с другой ошибкой:

bar ^. _1

<interactive>:6:1: error:
    • No instance for (Field1 Bar Bar () ()) arising from a use of ‘it’
    • In the first argument of ‘print’, namely ‘it’
      In a stmt of an interactive GHCi command: print it

person Kiara Grouwstra    schedule 12.01.2020    source источник
comment
makeLenses может создавать экземпляры Fieldn классов. Странно, что нет. Может быть, открыть отчет об ошибке и/или запрос на извлечение. github.com/ekmett/lens   -  person luqui    schedule 12.01.2020
comment
Если вы хотите получить доступ к полям по положению, есть также generic-lens.   -  person Carl    schedule 12.01.2020
comment
@luqui спасибо, это звучит довольно круто! На самом деле я еще не пробовал makeLenses здесь, но не мог понять это. Это, вероятно, на мне, так как я считаю, что операторы, сгенерированные шаблоном haskell, немного непрозрачны для отладки, но другая библиотека, похоже, сделала это за меня!   -  person Kiara Grouwstra    schedule 13.01.2020


Ответы (1)


Field1 имеет общую реализацию по умолчанию, поэтому вы, вероятно, можете добавить экземпляр самостоятельно:

{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics (Generic)

data Bar = Bar String deriving (Show, Generic)

instance Field1 Bar Bar String String

generic-lens также обеспечивает ту же функциональность, не требуя этого стандартного экземпляра. _1 называется position @1 (из Data.Generics.Product (.Positions)).

person Li-yao Xia    schedule 12.01.2020
comment
Спасибо! У меня сработало -- generic-lens выглядит неплохо! :) - person Kiara Grouwstra; 13.01.2020
comment
whelp, думаю, в моем реальном случае использования нескольких непересекающихся конструкторов это больше не работает. Ну что ж! - person Kiara Grouwstra; 13.01.2020