Navigation
Synopsis Generic function that can count constructors in a value of any algebraic data type.
Description In ColoredTrees, we have seen a function that can count the number of red nodes in a ColoredTree. Is it possible to define a function that can count constructors in a value of any algerbaic data type?

We exploit the subtype relation (see Rascal:StaticTyping) between Rascal:AlgebraicDataTypes and the type Rascal:Node to achieve this.

In real applications this becomes relevant when counting, for instance, statement types in programs.
Examples
module demo::common::CountConstructors

import Node;
import Map;

// Define a ColoredTree data type

data ColoredTree = leaf(int N)      
                 | red(ColoredTree left, ColoredTree right) 
                 | black(ColoredTree left, ColoredTree right);
                 
public ColoredTree CT = red(black(leaf(1), red(leaf(2),leaf(3))), black(leaf(3), leaf(4)));

// Define a Card data type.
             
data Suite = hearts() | diamonds() | clubs() | spades();

data Card =  two(Suite s) | three(Suite s) | four(Suite s) | five(Suite s) |
             six(Suite s) | seven(Suite s) | eight(Suite s) | nine(Suite s) | ten(Suite s) |
             jack(Suite s) | queen(Suite s) | king(Suite s) | ace(Suite s);
             
data Hand = hand(list[Card] cards);

public Hand H = hand([two(hearts()), jack(diamonds()), six(hearts()), ace(spades())]);

// Count frequencies of constructors

public map[str,int] count(node N){      
  freq = ();                            
  visit(N){                             
    case node M: { name = getName(M);   
                   freq[name] ? 0 += 1; 
                 }
  }
  return freq;
}

public map[str,int] countRelevant(node N, set[str] relevant) = domainR(count(N), relevant); 
Two data types are introduced ColoredTree and Hand together with an example value of each (CT, respectively, H).

The function count is defined at :
  • introduces an empty map to maintain the frequencies.
  • defines a visit of argument N; it traverses the complete value of N.
  • defines the case that we encounter a node and we update its frequency count. First the name of the constructor is retrieved (using Rascal:getName) and then the frequency is updated. The Rascal:IsDefined operator is used to provide a default value of 0 when the name was not yet in the map.
  • the map freq is returned as result.
A variant countRelevant is defined at ; it gets is an extra argument of relevant constructors names that is used to filter the map that is returned by count using Rascal:domainR.
rascal>import demo::common::CountConstructors;
ok
rascal>count(CT);
map[str, int]: ("red":2,"leaf":5,"black":2)
rascal>count(H);
map[str, int]: ("six":1,"ace":1,"two":1,"hearts":2,"spades":1,"hand":1,"diamonds":1,"jack":1)
rascal>countRelevant(H, {"hearts", "spades"});
map[str, int]: ("hearts":2,"spades":1)
Is this page unclear, or have you spotted an error? Please add a comment below and help us to improve it. For all other questions and remarks, visit ask.rascal-mpl.org.