Haskell accessors for non-existing records -
i learning haskell , discovering 'accessors' data members. let's assume have dummy 2d vertex information, 1 type has color, other has texture coordinate (tc):
data svertex = vertexc (float, float) int | vertextc (float, float) (float, float) deriving(show)
one tedious way create accessors records write functions patterns:
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
now, positive feature add accessors ('color' , 'tc') ones don't have 'color' or '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) -- returns if field doesn't exist color :: svertex -> int color (vertexc _ c) = c color (vertextc _ _) = 0 -- return if field doesn't exist
it allows me give default 0 values vertices don't have texture-coords or color 0 vertices don't have color... good...
now, question: reading there nice way give accessor names right data declaration. in case here (using 'prime' avoid name conflict):
data svertex' = vertexc' { position' :: (float, float), color' :: int } | vertextc' { position' :: (float, float), tc' :: (float, float) } deriving(show)
this allows me reach same goal: "position' ", "tc' " , "color' " accessors created me!
however: didn't find way give default accessor fields don't exist. example when requesting tc on 'vertexc'; or requesting color on vertextc... on first approach, make happen. in convenient second approach, fear not possible. when try add other function pattern
color' (vertextc' _ _) = 0
the compiler tells me "multiple declarations of ‘color’ etc.". , seems because second declaration not done following previous implicit 1 created compiler...
do know workaround ?
as have found out, records don't mix sum types (that is, types multiple constructors), lead unpleasant partial accessors can't rid of. 1 alternative using sum type fields require it, rather making svertex
whole sum type. way, many nice accessors possible while avoiding partial ones.
data vertexpaint = vertexc int | vertextc (float, float) deriving (show) data svertex = svertex { position :: (float, float) , paintjob :: vertexpaint } deriving (show)
if want color
function, still have define separately, in first attempt. (here use maybe int
result, more not safer bet returning arbitrary default.)
color :: svertex -> maybe int color v = case paintjob v of vertexc c -> c vertextc _ -> nothing
as alec suggests, lens library provides plenty of tools deal sort of situation in more convenient ways. in case, types defined in answer work lens.
Comments
Post a Comment