[英]Haskell record syntax and type classes
假设我有两种数据类型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
问题是所有这些getter和setter都很难写,特别是如果我用具有大量字段的真实数据类型替换Foo和Bar。
Haskell的记录语法提供了一种更好的方法来定义这些记录。 但是,如果我尝试定义这样的记录
data Foo = Foo {x :: Int, y :: Int} deriving Show
data Bar = Foo {x :: Int, z :: Int} deriving Show
我会收到一个错误,说x被多次定义。 并且,我没有看到任何方法使这些类型的类,以便我可以将它们传递给modifyX。
有没有一个很好的解决这个问题的方法,还是我坚持定义自己的吸气剂和制定者? 换句话说,有没有办法将记录语法创建的函数与类型类(getter和setter)连接起来?
编辑
这是我正在努力解决的真正问题。 我正在编写一系列相关程序,它们都使用System.Console.GetOpt来解析它们的命令行选项。 这些程序中会有很多命令行选项,但有些程序可能有额外的选项。 我希望每个程序能够定义包含其所有选项值的记录。 然后我从一个默认记录值开始,然后通过StateT monad和GetOpt进行转换,以获得反映命令行参数的最终记录。 对于单个程序,这种方法非常有效,但我正在尝试找到一种在所有程序中重用代码的方法。
你可以使用像这样的代码
data Foo = Foo { fooX :: Int, fooY :: Int } deriving (Show)
data Bar = Bar { barX :: Int, barZ :: Int } deriving (Show)
instance HasX Foo where
getX = fooX
setX r x' = r { fooX = x' }
instance HasX Bar where
getX = barX
setX r x' = r { barX = x' }
你在代码中建模什么? 如果我们对这个问题有了更多的了解,我们可以建议一些不那么尴尬的东西,而不是这种面向对象的设计。
对我来说似乎是一个泛型工作。 如果你可以使用不同的newtype标记你的Int,那么你就可以编写(使用uniplate,模块PlateData):
data Foo = Foo Something Another deriving (Data,Typeable)
data Bar = Bar Another Thing deriving (Data, Typerable)
data Opts = F Foo | B Bar
newtype Something = S Int
newtype Another = A Int
newtype Thing = T Int
getAnothers opts = [ x | A x <- universeBi opts ]
这将从Opts内的任何地方提取所有的另一个。
也可以进行修改。
如果您创建了Foldable的类型实例,则会获得一个toList函数,您可以将其用作访问者的基础。
如果Foldable不是你的任何东西,那么正确的方法是将你想要的接口定义为类型类,并找出一种自动生成派生值的好方法。
也许是通过做出来的
deriving(Data)
您可以使用gmap组合器来关闭您的访问权限。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.