Синтаксис записи в Haskell и классы типов

Предположим, что у меня есть два типа данных Foo и Bar. У Foo есть поля x и y. Бар имеет поля x и z. Я хочу иметь возможность написать функцию, которая принимает либо Foo, либо Bar в качестве параметра, извлекает значение x, выполняет некоторые вычисления, а затем возвращает новый Foo или Bar с соответствующим значением x.

Вот один из подходов:

class HasX a where
    getX :: a -> Int
    setX :: a -> Int -> a

data Foo = Foo Int Int deriving Show

instance HasX Foo where
    getX (Foo x _) = x
    setX (Foo _ y) val = Foo val y

getY (Foo _ z) = z
setY (Foo x _) val = Foo x val

data Bar = Bar Int Int deriving Show

instance HasX Bar where
    getX (Bar x _) = x
    setX (Bar _ z) val = Bar val z

getZ (Bar _ z) = z
setZ (Bar x _) val = Bar x val

modifyX :: (HasX a) => a -> a
modifyX hasX = setX hasX $ getX hasX + 5

Проблема в том, что писать все эти методы получения и установки очень сложно, особенно если я заменю Foo и Bar реальными типами данных, которые имеют много полей.

Haskell»Синтаксис записей s дает гораздо лучший способ определения этих записей. Но если я попытаюсь определить записи следующим образом:

data Foo = Foo {x :: Int, y :: Int} deriving Show
data Bar = Foo {x :: Int, z :: Int} deriving Show

Я получу сообщение о том, что x определено несколько раз. И я'Я не вижу способа сделать их частью класса типов, чтобы я мог передать их в modifyX.

Есть ли хороший чистый способ решения этой проблемы, или я застрял в определении своих собственных методов получения и установки? Другими словами, есть ли способ соединить функции, созданные синтаксисом записи, с классами типов (как геттерами, так и сеттерами)?

РЕДАКТИРОВАТЬ

Вот'это настоящая проблема, яЯ пытаюсь решить. Я'я пишу серию связанных программ, которые все используют System.Console.GetOpt для анализа своих параметров командной строки. Будет много параметров командной строки, которые являются общими для этих программ, но некоторые программы могут иметь дополнительные параметры. Я'Мне бы хотелось, чтобы каждая программа могла определять запись, содержащую все значения ее опций. Затем я начинаю со значения записи по умолчанию, которое затем преобразуется через монаду StateT и GetOpt, чтобы получить окончательную запись, отражающую аргументы командной строки. Для одной программы этот подход работает очень хорошо, но яЯ пытаюсь найти способ повторно использовать код во всех программах.

Ответы на вопрос(4)

Ваш ответ на вопрос