我正在学习Haskell,我目前正在为数据成员发现“访问器”。让我们假设我有一些虚拟的2D顶点信息,其中一种有一些颜色,另一种则有一些纹理坐标(tc):
data SVertex = VertexC (Float, Float) Int
| VertexTC (Float, Float) (Float, Float)
deriving(Show)创建记录访问器的一种繁琐方法是用模式编写函数:
position (VertexC (x,y) c ) = (x,y)
position (VertexTC (x,y) c ) = (x,y)
tc (VertexTC _ tc) = tc
color :: SVertex -> Int
color (VertexC _ c) = c现在,一个积极的特性是,我可以为那些没有“颜色”或“tc”的访问器添加访问器(“color”和“tc”):
position (VertexC (x,y) c ) = (x,y)
position (VertexTC (x,y) c ) = (x,y) -- no header, here... still works
tc (VertexTC _ tc) = tc
tc (VertexC _ _) = (0,0) -- to returns something even if the field doesn't exist
color :: SVertex -> Int
color (VertexC _ c) = c
color (VertexTC _ _) = 0 -- return something even if field doesn't exist它允许我给没有任何纹理的顶点默认的0值-和弦或颜色0给没有颜色的顶点。一切都好..。
现在,我的问题是:我目前正在读到,有一种很好的方法可以在数据声明中给访问者命名。在我的例子中,我会得到什么(使用‘质数’来避免名称冲突):
data SVertex' = VertexC' {
position' :: (Float, Float),
color' :: Int
}
| VertexTC' {
position' :: (Float, Float),
tc' :: (Float, Float)
} deriving(Show)这让我可以达到同样的目标:“位置”、“tc”和“颜色”访问器是为我创建的!
但是:我没有找到为不存在的字段提供默认访问器的方法。例如,当在‘顶点C’上请求tc时;或在VertexTC上请求颜色时.关于第一种方法,我可以让它成为现实。在第二种方便的方法中,恐怕是不可能的。当我尝试添加其他函数模式时,如
color' (VertexTC' _ _) = 0编译器告诉我“多个‘颜色’声明等等”。这似乎是因为第二个声明不是在编译器之前创建的隐式声明之后完成的.
你知道解决办法吗?
发布于 2016-11-06 01:45:31
正如您刚才所发现的,记录与sum类型(即带有多个构造函数的类型)并不很好地混合在一起,因为它们会导致无法摆脱的不愉快的部分访问。另一种选择是只对实际需要的字段使用sum类型,而不是将SVertex作为一个整体作为一个sum类型。这样,就可以获得尽可能多的好访问器,同时避免部分访问。
data VertexPaint = VertexC Int | VertexTC (Float, Float)
deriving (Show)
data SVertex = SVertex
{ position :: (Float, Float)
, paintjob :: VertexPaint
} deriving (Show)如果您想要一个color函数,您仍然必须单独定义它,就像第一次尝试那样。(在这里,我将使用Maybe Int结果,因为这通常比返回任意的缺省值更安全。)
color :: SVertex -> Maybe Int
color v = case paintjob v of
VertexC c -> Just c
VertexTC _ -> Nothing正如Alec所建议的,https://hackage.haskell.org/package/lens库提供了大量工具以更方便的方式处理这种情况。在任何情况下,在这个答案中定义的类型将与镜头很好地工作。
https://stackoverflow.com/questions/40444501
复制相似问题