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