Ответ 1
Вы не можете сделать это со стандартной функцией. Наилучший подход - иметь функцию отображения для каждого поля. К счастью, вы можете сгенерировать их автоматически с помощью небольшого шаблона haskell из библиотеки lens. Он будет выглядеть примерно так:
data ManyFields a b c d = MF { _f1 :: a, _f2 :: b, _f3 :: c, _f4 :: d }
makeLenses ''ManyFields
Это создает объектив для каждого поля ManyFields
. Объектив - это простая конструкция, которая позволяет вам как получить доступ, так и изменить значение там - изменения могут быть даже полиморфными, как и карта! Обратите внимание, что каждое поле имеет префикс с подчеркиванием: объектив имеет то же имя, что и поле, минус подчеркивание.
Теперь вы можете получить доступ к таким значениям:
> foo = MF 'a' "b" 3 False
> foo^.f1
'a'
Вы можете установить значения с помощью оператора set
. При использовании с объективом он создает функцию сеттера:
> :t set f1
set f1 :: a' -> ManyFields a b c d -> ManyFields a' b c d
Чтобы использовать его, вы можете сделать это:
> set f1 () foo
MF () "b" 3 False
Поскольку у вас есть геттер и сеттер, написание функции карты довольно тривиально. К счастью, нам даже не нужно этого делать: библиотека предоставляет функцию под названием over
:
> :t over f1
over f1 :: (a -> a') -> ManyFields a b c d -> ManyFields a' b c d
Если вам больше нужны операторы infix, set
также можно назвать .~
, а over можно назвать %~
. (У последнего есть мнемоника: %
- мода или "модификация": P.) Это также полезно для оператора &
, который просто $
перевернут. Таким образом, следующие две версии равны:
> over f1 ord foo
MF 97 "b" 3 False
> foo & f1 %~ ord
MF 97 "b" 3 False
Я лично считаю, что операторов немного. Если вы не будете использовать объективы повсюду, я буду придерживаться set
и over
.
Я не знаю хорошего решения для функций zip, как вы описали. Но просмотрите всю библиотеку объективов - она довольно большая, и вы никогда не знаете, что найдете.