Дискуссия началась при обсуждении Хаскеля 2010
Мой тезис состоит в том, что в Хаскеле поддержка зависимых типов хуже, чем в с++. (А как дело обстоит с Template Haskell?)
И пока что Miguel не представил определение зависимых типов (или ссылку на нее), по которому можно однозначно рассудить, есть ли в с++ зависимые типы. Боюсь, что пока я не реализую ему на шаблонах всю agda, он не согласится на наличие зависимых типов в с++ :-)
В процессе обсуждение родилось задание, похожее вот на это:
создаем вектор a с размерностью вводимой юзером
создаем вектор b с размерностью вводимой юзером
попытка перемножить несовместимые вектора a*b не компилируется
создаем вектор с с размерностью, равной размерности вектора а
попытка перемножить совместимые вектора a*с компилируется
выводим результат — скалярное произведение
Вот как я это сделал:
/*
$ g++ -DTRY dependent-type5.cxx
dependent-type5.cxx: In function ‘int main()’:
dependent-type5.cxx:68: error: no match for ‘operator*’ in ‘a * b’
dependent-type5.cxx:35: note: candidates are: double Vector<dimension>::operator*(const Vector<dimension>&) [with unsigned int* dimension = (& x)]
$ g++ dependent-type5.cxx
$ ./a.out
please enter dimension for vector a: 2
please enter element #0 for vector a: 1
please enter element #1 for vector a: 2
please enter dimension for vector b: 1
please enter element #0 for vector b: 1
please enter element #0 for vector c: 1
please enter element #1 for vector c: 2
a*c = 5
please enter element #0 for vector d: 1
please enter element #1 for vector d: 2
f(a)= 5
*/
#include <iostream>
#include <vector>
template<unsigned int* dimension> class Vector
{
public:
Vector(const char* msg): v( *dimension = *dimension ? *dimension : get_dimension(msg) ), dim(dimension)
{
for(int i=0; i<*dimension; i++) {
std::cout << "please enter element #" << i << " for vector " << msg << ": ";
std::cin >> v[i];
}
}
double operator* (const Vector<dimension>& that) /// вот тут мы следим за размерностью! зависимые типы, да.
{
double result=0;
for(int i=0; i<*dimension; i++)
result += v[i] * that.v[i];
return result;
}
private:
std::vector<double> v;
const unsigned int* const dim; /// для полноты картины
static unsigned int get_dimension(const char* msg)
{
unsigned int result;
std::cout << "please enter dimension for vector " << msg << ": ";
std::cin >> result;
return result;
}
};
template<unsigned int* dimension> double f(Vector<dimension> a)
{
Vector<dimension> d("d");
return a*d;
}
unsigned int x=0, y=0;
int main()
{
Vector<&x> a("a"); /// создаем вектор a с размерностью вводимой юзером
Vector<&y> b("b"); /// создаем вектор b с размерностью вводимой юзером
#ifdef TRY
double z0 = a*b; /// попытка перемножить несовместимые вектора a*b не компилируется
#endif
Vector<&x> c("c"); /// создаем вектор с с размерностью, равной размерности вектора а
/// (это можно записать по-другому: typeof(a) c("c"); но вероятно это не нужно)
/// (однако если все же нужно, потребуется с++0х)
double z1 = a*c; /// попытка перемножить совместимые вектора a*с компилируется
std::cout << "a*c = " << z1 << "\n"; /// выводим результат -- скалярное произведение
double z2 = f(a); /// теперь считаем то же самое, но как вызов функции f -- компилируется
/// (важно то, что размерность в явном виде в функцию f не передается)
std::cout << "f(a)= " << z2 << "\n"; /// снова выводим результат -- скалярное произведение
return 0;
}
Комментарий: если размерность, поданная вектору, нулевая, он ее читает от юзера, а если ненулевая — то использует.
(Кто знает Qi? интересно было бы взглянуть на решение на нем)
Решение на Template Haskell с UnsafeIO наверно подойдет, но интересно было бы попугать народ полноценным решением без UnsafeIO :-)
И еще меня интересуе, как переписать на (Template?) Haskell вот это (даже если тут нет зависимых типов):
const int n=17;
...
Z<n> f(int x) { return mod<n>(x+(n/2)); }