docs: def etype(self) -> Tuple[str, str]:
          '''Returns the expression's type.'''
          if self._expr[0] in ['number', 'boolean']:
              return ('constant', str(type(self._expr[1])))
          elif self._expr[0] == 'pvar_expr':
              return ('pvar', self._expr[1][0])
          elif self._expr[0] == 'randomvar':
              return ('randomvar', self._expr[1][0])
          elif self._expr[0] in ['+', '-', '*', '/']:
              return ('arithmetic', self._expr[0])
          elif self._expr[0] in ['^', '&', '|', '~', '=>', '<=>']:
              return ('boolean', self._expr[0])
          elif self._expr[0] in ['>=', '<=', '<', '>', '==', '~=']:
              return ('relational', self._expr[0])
          elif self._expr[0] == 'func':
              return ('func', self._expr[1][0])
          elif self._expr[0] == 'sum':
              return ('aggregation', 'sum')
          elif self._expr[0] == 'prod':
              return ('aggregation', 'prod')
          elif self._expr[0] == 'avg':
              return ('aggregation', 'avg')
          elif self._expr[0] == 'max':
              return ('aggregation', 'maximum')
          elif self._expr[0] == 'min':
              return ('aggregation', 'minimum')
          elif self._expr[0] == 'forall':
              return ('aggregation', 'forall')
          elif self._expr[0] == 'exists':
              return ('aggregation', 'exists')
          elif self._expr[0] == 'if':
              return ('control', 'if')
          else:
              return ('UNKOWN', 'UNKOWN')