migmit: (Default)
[personal profile] migmit

Вот есть хаскельный код (пример упрощён до предела):

data P a = P a (forall b. b -> P (a, b))
Нормально компилится, если указать прагму LANGUAGE RankNTypes в GHC или ключик -98 в Hugs-е.
Можно написать несколько "генераторов" для такого P:
sameValue :: a -> P a
sameValue x = P x (\y -> sameValue (x, y))

firstRest :: a -> a -> P a
firstRest x y = P x (\z -> sameValue (y, z))

switching :: a -> a -> P a
switching x y = P x (\z -> switching (y, z) (x, z))
Как сделать это на C++???
Я попробовал, моего плюс-фу не хватило. Светилы, если вы есть, можете подсказать?
Хочется что-то вроде этого:

#include <map>
template <class A> class P {
  A car;
  template <class B> virtual P<std::pair<A,B> > cdr (B) = 0;
};

Не заработает, ибо template и virtual вместе не живут. Убрать virtual нельзя - класс определяется как абстрактный, реализация функции cdr будет разной (см. выше), но эту разницу надо скрыть "под капотом", указывая везде базовый класс.
Как?

Originally posted on migmit.vox.com

Date: 2009-02-06 12:46 pm (UTC)
From: [identity profile] esil0x.livejournal.com
Я сейчас попробовал реализовать FirstRest с дополнительным параметром шаблона и подумал вот о чём.
Какая задача у объекта P? У него имеется переменная car и шаблонная функция cdr. Если нас устраивает статический полиморфизм, то вообще не обязательно, чтобы SameValue и FirstRes являлись одним и тем же шаблоном. Будет достаточно, если они будут удовлетворять определённым ограничениям.

Например, можно реализовать это таким образом:

 < A>  SameValue {
:
  A car;

  SameValue(A arg): car(arg) {}
  
   < B>
   cdr_result {
     SameValue<std::pair<A,B> > type;
  };
  
  < B> SameValue<std::pair<A,B> > cdr(B arg2) {
    SameValue<std::pair<A,B> > result(std::make_pair(->car, arg2));
     result;
  }
};

 < A>  FirstRest {
:
  A car;

  FirstRest(A first, A rest): car(first), rest_(rest) {}

   < B>
   cdr_result {
     SameValue<std::pair<A,B> > type;
  };
  
  < B> SameValue<std::pair<A,B> > cdr(B arg2) {
    SameValue<std::pair<A,B> > result(std::make_pair(rest_, arg2));
     result;
  }
:
  A rest_;
};

 main() {
     FirstRest<> P1;
     P1::cdr_result<std::string>::type P2;
     P2::cdr_result<>::type P3;

    P1 p1(, );
    P2 p2 = p1.cdr(std::string());
    P3 p3 = p2.cdr();
        
     ;
} Но нужно понять, действительно ли не требуется динамического полиморфизма (например хранить указатели на объекты в одном и том же списке). Т. е. нужно учитывать то, какое будет использование. Если окажется, что всё-таки нужна иерархия классов, то тогда уже будут проблемы.
()

Date: 2009-02-06 01:19 pm (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
Гм. Вполне представляю себе использование типа int f(P a, P b) {... a.cdr(b.car) ...} - ну, или что-то в этом духе. Насчёт списков не задумывался пока. Ну и плюс - A car указывается в каждом из них, что есть бойлерплейт.