I need to describe in Standard-ML a language made of properties and values. My property system is made of properties which can have values, like for example:
color: red | yellow | blue | transparent
align: left | center | right
bgcolor: red | yellow | blue | transparent
I created this sml file which tries to describe these properties:
datatype colorvalue = Transparent
| Yellow
| Blue
| Red
datatype bgcolorvalue = Transparent
| Yellow
| Blue
| Red
datatype alignvalue = Left
| Center
| Right
(* Generic property: it can be any of the above *)
datatype property = Color of colorvalue
| BgColor of bgcolorvalue
| Align of alignvalue
(* Some values *)
val prop1: property = Color Transparent
val prop2: property = BgColor Transparent
When I compile this in MoscowML I get:
,File "c:\Users\myuser\documents\myproj\property.sml", line 21, characters 31-42:
! val prop1: property = Color Transparent
! ^^^^^^^^^^^
! Type clash: expression of type
! bgcolorvalue
! cannot have type
! colorvalue
So I think that the problem is that color
and bgcolor
share a common property value: transparent
which reflects in datatypes colorvalue
and bgcolorvalue
to share constructor Transparent
. Actually they share all values, thus all constructors.
It is easy to see that trying to use the same constructor in different types in the same scope would create problems with type inference. For example, what should the type of
fun heat Transparent = Yellow
| heat Yellow = Red
| heat Red = Blue
| heat Blue = Blue;
be? colorvalue ->colorvalue
or bgbcolorvalue -> bgbcolorvalue
or colorvalue -> bgbcolorvalue
or bgbcolorvalue -> colorvalue
?
The easiest workaround would be to adopt different naming conventions for the constructors. You could also use structures (which is how SML keeps e.g. different uses of the name map
in the basis library without any clashes). Something like:
structure Color = struct
datatype value = Transparent
| Yellow
| Blue
| Red
end
structure BGBColor = struct
datatype value = Transparent
| Yellow
| Blue
| Red
end;
Then you can do things like:
- val a = Color.Transparent;
val a = Transparent : Color.value
- val b = BGBColor.Transparent;
val b = Transparent : BGBColor.value
This last was run in the SML/NJ REPL and illustrates how there are now no clashes.