Commit a5cf614d by Pietro Abate

```Original author: cvscast
Date: 2003-07-05 10:28:28+00:00```
parent 93019664
 ... ... @@ -74,14 +74,23 @@ code.

Let us examine a more complex example. We want to transform the representation of persons introduced in Section , using different tags Let us examine a more complex example. Recall the types used to represent persons that we defined in Section "Getting started" that for the purpose of the example we can simplify as follows:

[ Name Children ] type MPerson = [ Name Children ] type Children = [ Person* ] type Name = [ PCDATA ] ]]>

We want to transform this representation of persons into a different representation that uses different tags <man> and <woman> instead of the gender attribute and, conversely, using an attribute instead of the gender attribute and, conversely, that uses an attribute instead of an element for the name. We also want to distinguish the children of a person into two different sequences, one of sons, composed of men (i.e. elements tagged by <man>), and the other of daughters, composed of ... ... @@ -95,14 +104,76 @@ type Woman = [ Sons Daughters ] type Sons = [ Man* ] type Daughters = [ Woman* ] ]]>

Here is a possible way to implement such a transformation:

Man ; FPerson -> Woman}}) [ n [(mc::MPerson | fc::FPerson)*] ] -> (* the above pattern collects all the MPerson in mc, and all the FPerson in fc *) let tag = match g with "F" -> `woman | "M" -> `man in let s = map mc with x -> split x in let d = map fc with x -> split x in <(tag) name=n>[ s d ] ;; ]]>

The function split is declared to be an overloaded function that, when applied to a MPerson, returns an element of type Man and that, when applied to a FPerson, returns an element of type Woman. The body is composed of a single pattern matching

[ {{n}} [({{mc}}::MPerson | {{fc}}::FPerson)*] ] -> ]]>

whose pattern binds four variables: g is bound to the gender of the argument of the function, n is bound to its name, mc is bound to the sequence of all children that are of type MPerson, and fc is bound to the sequence of all children that are of type FPerson.

On the next line we define tag to be `man or `woman according to the value of g. Then we apply split recursively to the elements of mc and fc.

{{split}} x in let d = map fc with x -> split x in <(tag) name=n>[ {{s}} d ] ;; ]]>

Here is the use of overloading: since mc is of type [MPerson*]}, then by the overloaded type of split we can deduce that s is of type [Man*]}; similarly we deduce for d the type [Woman*]. From this the type checker deduces that the expressions <sons>s and <daughters> are of type Sons and Daughters, and therefore it returns for the split function the type (MPerson -> Man) & (FPerson -> Woman). Note that the use of overloading here is critical: although split has also type Person ->(Man | Woman) (since split is of type MPerson->Man & FPerson->Woman, which is a subtype), had we declared split of that type, the function would not have type-checked: in the recursive calls we would have been able to deduce for s and for d the type [ (Man | Woman)* ], which is not enough to type-check the result. If, for example, we wanted to define the same transformation in XDuce we would need first to apply a filter (that is our transform) to the children so as to separate male from females (while in CDuce we obtain it simply by a pattern) and then resort to two auxiliary functions that have nearly the same definition and differ only on their type, one being of type MPerson -> Man, the other of type FPerson -> Woman. The same transformation can be elegantly defined in XSLT with a moderate nloc increase, but only at the expense of loosing static type safety and type based optimization: see the page for preliminary benchmarks.

Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!