diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp
index e110ee46c2772ad2c5cb7f22440e53b2b9a1ff9a..73a423032357b1fa2e4d6301ddbe927ac899358d 100644
--- a/src/language/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ASTNodeDataTypeBuilder.cpp
@@ -6,8 +6,56 @@
 
 #include <CFunctionEmbedder.hpp>
 
+ASTNodeDataType
+ASTNodeDataTypeBuilder::_buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNode& name_node) const
+{
+  ASTNodeDataType data_type{ASTNodeDataType::undefined_t};
+  if (type_node.is_type<language::type_expression>()) {
+    if (type_node.children.size() != name_node.children.size()) {
+      std::ostringstream message;
+      message << "number of product spaces (" << type_node.children.size() << ") " << rang::fgB::yellow
+              << type_node.string() << rang::style::reset << rang::style::bold << " differs from number of variables ("
+              << name_node.children.size() << ") " << rang::fgB::yellow << name_node.string() << rang::style::reset
+              << std::ends;
+      throw parse_error(message.str(), name_node.begin());
+    }
+
+    for (size_t i = 0; i < type_node.children.size(); ++i) {
+      auto& sub_type_node = *type_node.children[i];
+      auto& sub_name_node = *name_node.children[i];
+      _buildDeclarationNodeDataTypes(sub_type_node, sub_name_node);
+    }
+    data_type = ASTNodeDataType::typename_t;
+  } else {
+    if (type_node.is_type<language::B_set>()) {
+      data_type = ASTNodeDataType::bool_t;
+    } else if (type_node.is_type<language::Z_set>()) {
+      data_type = ASTNodeDataType::int_t;
+    } else if (type_node.is_type<language::N_set>()) {
+      data_type = ASTNodeDataType::unsigned_int_t;
+    } else if (type_node.is_type<language::R_set>()) {
+      data_type = ASTNodeDataType::double_t;
+    } else if (type_node.is_type<language::string_type>()) {
+      data_type = ASTNodeDataType::string_t;
+    }
+
+    Assert(name_node.is_type<language::name>());
+    name_node.m_data_type     = data_type;
+    const std::string& symbol = name_node.string();
+
+    std::shared_ptr<SymbolTable>& symbol_table = name_node.m_symbol_table;
+
+    auto [i_symbol, found] = symbol_table->find(symbol, name_node.begin());
+    Assert(found);
+    i_symbol->attributes().setDataType(data_type);
+  }
+
+  Assert(data_type != ASTNodeDataType::undefined_t);   // LCOV_EXCL_LINE
+  return data_type;
+}
+
 void
-ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n)
+ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
 {
   if (n.is_type<language::block>() or n.is_type<language::for_statement>()) {
     for (auto& child : n.children) {
@@ -33,33 +81,10 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n)
         n.m_data_type = ASTNodeDataType::void_t;
       } else if (n.is_type<language::declaration>()) {
         auto& type_node = *(n.children[0]);
-        ASTNodeDataType data_type{ASTNodeDataType::undefined_t};
-        if (type_node.is_type<language::B_set>()) {
-          data_type = ASTNodeDataType::bool_t;
-        } else if (type_node.is_type<language::Z_set>()) {
-          data_type = ASTNodeDataType::int_t;
-        } else if (type_node.is_type<language::N_set>()) {
-          data_type = ASTNodeDataType::unsigned_int_t;
-        } else if (type_node.is_type<language::R_set>()) {
-          data_type = ASTNodeDataType::double_t;
-        } else if (type_node.is_type<language::string_type>()) {
-          data_type = ASTNodeDataType::string_t;
-        } else if (type_node.is_type<language::type_expression>()) {
-          data_type = ASTNodeDataType::typename_t;
-        }
-
-        Assert(data_type != ASTNodeDataType::undefined_t);   // LCOV_EXCL_LINE
+        auto& name_node = *(n.children[1]);
 
-        type_node.m_data_type      = ASTNodeDataType::typename_t;
-        n.children[1]->m_data_type = data_type;
-        const std::string& symbol  = n.children[1]->string();
-
-        std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
-
-        auto [i_symbol, found] = symbol_table->find(symbol, n.children[1]->begin());
-        Assert(found);
-        i_symbol->attributes().setDataType(data_type);
-        n.m_data_type = data_type;
+        type_node.m_data_type = _buildDeclarationNodeDataTypes(type_node, name_node);
+        n.m_data_type         = type_node.m_data_type;
       } else if (n.is_type<language::let_declaration>()) {
         n.children[0]->m_data_type = ASTNodeDataType::function_t;
 
@@ -91,8 +116,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n)
 
         if (nb_parameter_domains != nb_parameter_names) {
           std::ostringstream message;
-          message << "Compound data type deduction is not yet implemented\n"
-                  << "note: number of product spaces (" << nb_parameter_domains << ") " << rang::fgB::yellow
+          message << "note: number of product spaces (" << nb_parameter_domains << ") " << rang::fgB::yellow
                   << parameters_domain_node.string() << rang::style::reset << rang::style::bold
                   << " differs from number of variables (" << nb_parameter_names << ") " << rang::fgB::yellow
                   << parameters_name_node.string() << rang::style::reset << std::ends;
diff --git a/src/language/ASTNodeDataTypeBuilder.hpp b/src/language/ASTNodeDataTypeBuilder.hpp
index 126c8d44285a998599c14314a404ddfdab0d3591..ccec5e057fbdcfbaed37a2e1cb82b1e7e47179e0 100644
--- a/src/language/ASTNodeDataTypeBuilder.hpp
+++ b/src/language/ASTNodeDataTypeBuilder.hpp
@@ -6,7 +6,9 @@
 class ASTNodeDataTypeBuilder
 {
  private:
-  void _buildNodeDataTypes(ASTNode& node);
+  ASTNodeDataType _buildDeclarationNodeDataTypes(ASTNode& type_node, ASTNode& name_node) const;
+
+  void _buildNodeDataTypes(ASTNode& node) const;
 
  public:
   ASTNodeDataTypeBuilder(ASTNode& root_node);
diff --git a/src/language/ASTNodeDataVariant.hpp b/src/language/ASTNodeDataVariant.hpp
index 46f4d16583375d000fc4201d7a6dc81cf7125801..96d94022971d807cfda4c6eb2989ba89c308906f 100644
--- a/src/language/ASTNodeDataVariant.hpp
+++ b/src/language/ASTNodeDataVariant.hpp
@@ -4,20 +4,53 @@
 #include <variant>
 #include <vector>
 
-struct CompoundDataVariant;
+#include <PugsAssert.hpp>
+
+class CompoundDataVariant;
 
 using ASTNodeDataVariant =
   std::variant<std::monostate, bool, uint64_t, int64_t, double, std::string, CompoundDataVariant>;
 
-struct CompoundDataVariant
+class CompoundDataVariant
 {
+ private:
   std::vector<ASTNodeDataVariant> m_data_vector;
-  friend std::ostream&
-  operator<<(std::ostream& os, const CompoundDataVariant&)
+
+  std::ostream&
+  _printComponent(std::ostream& os, const ASTNodeDataVariant& value) const
   {
-    os << " *CompoundDataVariant* ";
+    std::visit(
+      [&](auto&& v) {
+        if constexpr (std::is_same_v<std::decay_t<decltype(v)>, std::monostate>) {
+          os << " -- ";
+        } else {
+          os << v;
+        }
+      },
+      value);
     return os;
   }
+
+  std::ostream&
+  _print(std::ostream& os) const
+  {
+    Assert(m_data_vector.size() > 0, "unexpected compound data size");
+    os << '(';
+    this->_printComponent(os, m_data_vector[0]);
+    for (size_t i = 1; i < m_data_vector.size(); ++i) {
+      os << ", ";
+      this->_printComponent(os, m_data_vector[i]);
+    }
+    os << ')';
+    return os;
+  }
+
+ public:
+  friend std::ostream&
+  operator<<(std::ostream& os, const CompoundDataVariant& compound)
+  {
+    return compound._print(os);
+  }
 };
 
 #endif   // AST_NODE_DATA_VARIANT_HPP
diff --git a/src/language/ASTSymbolInitializationChecker.cpp b/src/language/ASTSymbolInitializationChecker.cpp
index f6ccf552434314dfbbb5fd4f1bf5bb765d2088ef..0698b6fad33485f568a776c8f3a6442ff263197a 100644
--- a/src/language/ASTSymbolInitializationChecker.cpp
+++ b/src/language/ASTSymbolInitializationChecker.cpp
@@ -8,12 +8,16 @@ void
 ASTSymbolInitializationChecker::_checkSymbolInitialization(ASTNode& node)
 {
   if (node.is_type<language::declaration>()) {
-    const std::string& symbol = node.children[1]->string();
-    auto [i_symbol, found]    = node.m_symbol_table->find(symbol, node.children[1]->begin());
-    Assert(found, "unexpected error, should have been detected through declaration checking");
-    if (node.children.size() == 3) {
-      this->_checkSymbolInitialization(*node.children[2]);
-      i_symbol->attributes().setIsInitialized();
+    if (node.children[1]->is_type<language::name>()) {
+      const std::string& symbol = node.children[1]->string();
+      auto [i_symbol, found]    = node.m_symbol_table->find(symbol, node.children[1]->begin());
+      Assert(found, "unexpected error, should have been detected through declaration checking");
+      if (node.children.size() == 3) {
+        this->_checkSymbolInitialization(*node.children[2]);
+        i_symbol->attributes().setIsInitialized();
+      }
+    } else {
+      std::cerr << __FILE__ << ':' << __LINE__ << ": '" << node.children[1]->name() << "' NIY!\n";
     }
   } else if (node.is_type<language::let_declaration>()) {
     const std::string& symbol = node.children[0]->string();
diff --git a/src/language/ASTSymbolTableBuilder.cpp b/src/language/ASTSymbolTableBuilder.cpp
index 87a549c020d90690ff768ffe26703dcedffab58d..d78100060862518d5f68934b9b99ca01444e6ae1 100644
--- a/src/language/ASTSymbolTableBuilder.cpp
+++ b/src/language/ASTSymbolTableBuilder.cpp
@@ -38,15 +38,26 @@ ASTSymbolTableBuilder::buildSymbolTable(ASTNode& n, std::shared_ptr<SymbolTable>
     n.m_symbol_table = symbol_table;
     if (n.has_content()) {
       if (n.is_type<language::declaration>()) {
-        const std::string& symbol = n.children[1]->string();
-        auto [i_symbol, success]  = symbol_table->add(symbol, n.children[1]->begin());
-        if (not success) {
-          std::ostringstream error_message;
-          error_message << "symbol '" << rang::fg::red << symbol << rang::fg::reset << "' was already defined!";
-          throw parse_error(error_message.str(), std::vector{n.begin()});
+        auto register_symbol = [&](const ASTNode& argument_node) {
+          auto [i_symbol, success] = symbol_table->add(argument_node.string(), argument_node.begin());
+          if (not success) {
+            std::ostringstream error_message;
+            error_message << "symbol '" << rang::fg::red << argument_node.string() << rang::fg::reset
+                          << "' was already defined!";
+            throw parse_error(error_message.str(), std::vector{argument_node.begin()});
+          }
+        };
+
+        if (n.children[1]->is_type<language::name>()) {
+          register_symbol(*n.children[1]);
+        } else {   // treats the case of list of parameters
+          Assert(n.children[1]->is_type<language::name_list>());
+          for (auto& child : n.children[1]->children) {
+            register_symbol(*child);
+          }
         }
       } else if (n.is_type<language::function_definition>()) {
-        auto register_symbol = [&](const ASTNode& argument_node) {
+        auto register_and_initialize_symbol = [&](const ASTNode& argument_node) {
           auto [i_symbol, success] = symbol_table->add(argument_node.string(), argument_node.begin());
           if (not success) {
             std::ostringstream error_message;
@@ -59,11 +70,11 @@ ASTSymbolTableBuilder::buildSymbolTable(ASTNode& n, std::shared_ptr<SymbolTable>
         };
 
         if (n.children[0]->is_type<language::name>()) {
-          register_symbol(*n.children[0]);
+          register_and_initialize_symbol(*n.children[0]);
         } else {   // treats the case of list of parameters
           Assert(n.children[0]->is_type<language::name_list>());
           for (auto& child : n.children[0]->children) {
-            register_symbol(*child);
+            register_and_initialize_symbol(*child);
           }
         }
       } else if (n.is_type<language::name>()) {
diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp
index f3d245ecd131b11806b0c14748415892c8a68297..b44f873c0223703dfd42ee424ca799bbfb0aa130 100644
--- a/src/language/PEGGrammar.hpp
+++ b/src/language/PEGGrammar.hpp
@@ -213,7 +213,8 @@ struct affect_op : sor< eq_op, multiplyeq_op, divideeq_op, pluseq_op, minuseq_op
 
 struct affectation : seq< NAME , if_must< affect_op,  sor< expression_list, expression > > >{};
 
-struct declaration : if_must< type_expression, NAME, opt< if_must< seq< one< '=' >, ignored >, sor< expression_list, expression > > > >{};
+struct name_list;
+struct declaration : if_must< type_expression, sor< NAME, name_list>, opt< if_must< seq< one< '=' >, ignored >, sor< expression_list, expression > > > >{};
 
 struct type_mapping : seq< type_expression, RIGHT_ARROW, type_expression >{};