Tuesday, October 23, 2007

Discriminated unions in Mercury

While reading the Mercury tutorial I learned how to define discriminated unions or algebraic datatypes.

Discriminated unions provide a way to define new structured data types.

For example here's a couple of type definitions that represent very simple arithmetic expressions:


:- type expression ---> const(int)
; var(string)
; binaryOperation(expression,operator,expression).
:- type operator ---> add ; subtract.


These definitions specify arithmetic expression parts such as constants(const), variables(var), binary operations(binaryOperation), etc.

Given these definitions we can instantiate them by calling the constructors:


main(!IO) :-
X = binaryOperation(var("x"),add,const(10)),


Also we can use Mercury's unification to easily manipulate them, for example the following function writes the content of the expression to the output:


:- func operator_to_string(operator) = string.
operator_to_string(add) = "+".
operator_to_string(subtract) = "-".

:- pred write_expression(expression::in,io::di,io::uo) is det.

write_expression(const(C),!IO) :-
io.write_int(C,!IO).
write_expression(var(S),!IO) :-
io.write_string(S,!IO).
write_expression(binaryOperation(Operand1,Operator,Operand2) ,!IO) :-
write_expression(Operand1,!IO),
io.write_string(operator_to_string(Operator),!IO),
write_expression(Operand2,!IO).


Calling this predicate like this:


main(!IO) :-
X = binaryOperation(var("x"),add,const(10)),
write_expression(X,!IO).

Generates:

x+10