Haskell记录语法和类型类

Cli*_*ler 14 haskell types class record

假设我有两种数据类型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
Run Code Online (Sandbox Code Playgroud)

问题是所有这些getter和setter都很难写,特别是如果我用具有大量字段的真实数据类型替换Foo和Bar.

Haskell的记录语法提供了一种更好的方法来定义这些记录.但是,如果我尝试定义这样的记录

data Foo = Foo {x :: Int, y :: Int} deriving Show
data Bar = Foo {x :: Int, z :: Int} deriving Show
Run Code Online (Sandbox Code Playgroud)

我会收到一个错误,说x被多次定义.并且,我没有看到任何方法使这些类型的类,以便我可以将它们传递给modifyX.

有没有一个很好的解决这个问题的方法,还是我坚持定义自己的吸气剂和制定者?换句话说,有没有办法将记录语法创建的函数与类型类(getter和setter)连接起来?

编辑

这是我正在努力解决的真正问题.我正在编写一系列相关程序,它们都使用System.Console.GetOpt来解析它们的命令行选项.这些程序中会有很多命令行选项,但有些程序可能有额外的选项.我希望每个程序能够定义包含其所有选项值的记录.然后我从一个默认记录值开始,然后通过StateT monad和GetOpt进行转换,以获得反映命令行参数的最终记录.对于单个程序,这种方法非常有效,但我正在尝试找到一种在所有程序中重用代码的方法.

Dan*_*Dan 5

您需要可扩展记录,我收集这些记录是Haskell中最受关注的主题之一.目前似乎没有就如何实施它达成多少共识.

在您的情况下,似乎可能使用异构列表而不是普通记录,就像在HList中实现的那样.

再说一遍,你似乎只有两个级别:普通和程序.因此,您可能只应为每个程序定义公共选项的公共记录类型和特定于程序的记录类型,并在这些类型的元组上使用StateT.对于常见的东西,您可以添加fst由公共访问器组成的别名,这样对于调用者来说它是不可见的.