Я пытался перевести следующий код Haskell на С++:
data List t = Nil | Cons t (List t)
Прямой перевод типа алгебраических данных в шаблон Visitor без учета состояния дает следующий код Java
interface List<T> {
<R> R accept(ListVisitor<T,R> v);
}
interface ListVisitor<T,R> {
R visitNil();
R visitCons(T head, List<T> tail);
}
class Nil<T> implements List<T> {
@Override
public <R> R accept(ListVisitor<T,R> v) {
return v.visitNil();
}
}
class Cons<T> implements List<T> {
public final T head;
public final List<T> tail;
public Cons(T head, List<T> tail) {
this.head = head;
this.tail = tail;
}
@Override
public <R> R accept(ListVisitor<T,R> v) {
return v.visitCons(head, tail);
}
}
Ниже приведен код С++, который у меня есть до сих пор:
template<class T> class List;
template<class T, class R> class ListVisitor {
virtual R visitNil() = 0;
virtual R visitCons(T head, List<T> tail) = 0;
};
template<class T> class List {
template<class R> virtual R accept(ListVisitor<T,R> v) = 0;
};
Обратите внимание, что версия Java использует виртуальную общую функцию accept
. Когда я переводил его на С++, я получаю функцию виртуального шаблона, которая не разрешена С++.
Есть ли решение для него, кроме как сделать accept
return void
и требовать, чтобы посетители были с сохранением состояния?
Update: В соответствии с запросом, вот несколько примеров того, как можно использовать интерфейсы (по модулю интеллектуальных указателей и возможных ошибок компиляции):
template<class T> struct LengthVisitor : ListVisitor<T, int> {
bool visitNil() { return 0; }
bool visitCons(const T&, const List<T> &tail) { return 1 + tail.accept(*this); }
};
template<class T> struct ConcatVisitor : ListVisitor<T, const List<T> *> {
const List<T> *right;
ConcatVisitor(const List<T> *right) : right(right) {}
List<T> * visitNil() { return right; }
List<T> * visitCons(const T &head, const List<T> & tail) {
return new Cons(head, tail.accept(*this));
}
};
Другой пример: более высокая функция fold
в Java может быть найдена здесь: http://hpaste.org/54650