LINUX.ORG.RU

5-й номер журнала «Практика функционального программирования»

 , , , , , ,


0

0

Вышел новый, пятый номер журнала «Практика функционального программирования». В новом номере опубликованы следующие статьи:

  • Инструменты интроспекции в Erlang/OTP. Максим Трескин
  • Экономия ошибок. С. Зефиров, А. Сафронов, В. Шабанов, Е. Мельников
  • Введение в F#. Евгений Лазин, Максим Моисеев, Давид Сорокин
  • Лисп — философия разработки. Всеволод Дёмкин, Александр Манзюк
  • Оптимизирующие парсер-комбинаторы. Дмитрий Попов
  • Модель типизации Хиндли — Милнера и пример её реализации на языке Haskell. Роман Душкин

Также в этом номере опубликованы результаты конкурса, который был объявлен в 3-м номере журнала.

>>> Подробности

★★★★★

Проверено: maxcom ()
Ответ на: комментарий от mv

> А ты что именно хочешь сделать этим кодом?

ну ты же с++ знаешь — вот я хочу сделать стандартную вещь, про которую лень даже рассказывать, но если попросишь — расскажу

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

ну ты же с++ знаешь — вот я хочу сделать стандартную вещь, про которую лень даже рассказывать, но если попросишь — расскажу

Я вижу здесь диспетчеризацию. Также я вижу класс Figure, объекты которого нельзя создавать. Тебе нужна диспетчеризация или запрет на создание объектов класса Figure?

mv ★★★★★
()

Уважаемые лисперы. Особенно коммон лисперы. Вы, я надеюсь, понимайте, что пока что у вас все «сыровато». Займитесь вы лучше написанием библиотек к CL, пишите больше хороших открытых проектов на лиспе. Сделайте нормальный компелятор и какое-нибудь жалкое подобие божественному cpan'у. Тогда вы реально ПОМОЖЕТЕ лиспу, тогда я посмотрю и скажу: «Да, кроме emacs'а эту штуку можно юзать и еще там-то и там-то, может быть где-то даже перл заменить сможет.», помогайте своему языку.

oh
()
Ответ на: комментарий от mv

мне нужно все (ну или исключая то, что по-твоему пользы не дает, с последующим доказательством бесполезности)

пока что я вижу пользу в:

1. рантаймовая диспетчеризация
2. запрет на создание объектов класса Figure
3. возможность класть в массив фигур инстансы только производных классов^W^W тех классов, у которых есть draw и rotate, причем draw и rotate не случайно совпавшие по именам, а проектировавшися как реализация интерфейса (например, rotate(2*PI) проектировалась как ничего не меняющая)

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

возможность класть в массив фигур инстансы только производных классов^W^W тех классов, у которых есть draw и rotate

class Figure 
{ 
public: 
  virtual void draw()=0; 
  virtual void rotate(float)=0; 
}; 
class Square: public Figure 
{ 
   /// определяем draw && rotate 
}; 
class Circle
{ 
   /// определяем draw && rotate 
}; 

Circle можно ложить вместе со Square?

mv ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

довольно много;


К чему тогда, пример с массивом?

лучше расскажи про defmethod на том примере, что я запостил


Пожалуйста:

(defgeneric draw (obj))

(defgeneric rotate (obj))

(defclass square () 
  ...)

(defmethod draw ((obj square))
  ...)

(defmethod rotate ((obj square))
  ...)

Здесь видно, что для класса square реализуется необходимый интерфейс и при этом потребности в каких-либо абстрактных классах нет.

А попробуй теперь изобразить такое:

(defgeneric draw (obj context))

(defclass square ()
  ...)

(defmethod draw ((obj square) (context CDC))
  ...)

(defmethod draw ((obj square) (context PDFContext))
  ...)

(defmethod draw ((obj square) (context ImageContext))
  ...)

Здесь показана простейшая вариация на тему мультиметодов, реализации которых для C++ посвящена не одна сотня страниц уважаемых авторов (включая Александреску), но хорошего решения нет ни у кого. Кстати, известный паттерн Visitor (я об этом уже говорил выше) уродлив сам по себе, но на фоне CLOS выглядит чем-то средневековым.

archimag ★★★
()
Ответ на: комментарий от www_linux_org_ru

вот давай-ка, изобрази на C++ или Java:

(defclass opponent () ())

(defclass mouse (opponent) ())

(defclass cat (opponent) ())

(defclass elephant (opponent) ())

(defclass ninja (opponent) ())

(defgeneric fight (opponent1 opponent2))

(defmethod fight ((opponent1 mouse) (opponent2 mouse))
  (format t "big fat mouse eats small mouse. big fat mouse wins.~%")
  'mouse)

(defmethod fight ((opponent1 mouse) (opponent2 cat))
  (format t "cat catches mouse. cat wins.~%")
  'cat)

(defmethod fight ((opponent1 mouse) (opponent2 elephant))
  (format t "mouse scares elephant. mouse wins.~%")
  'mouse)

(defmethod fight ((opponent1 mouse) (opponent2 ninja))
  (format t "ninja cuts mouse. ninja wins.~%")
  'ninja)

(defmethod fight ((opponent1 cat) (opponent2 cat))
  (format t "agile cat jumps over clumsy cat. agile cat wins.~%")
  'cat)

(defmethod fight ((opponent1 cat) (opponent2 mouse))
  (format t "cat catches mouse. cat wins.~%")
  'cat)

(defmethod fight ((opponent1 cat) (opponent2 elephant))
  (format t "elephant tramples cat. elephant wins.~%")
  'elephant)

(defmethod fight ((opponent1 cat) (opponent2 ninja))
  (format t "ninja cuts cat. ninja wins.~%")
  'ninja)

(defmethod fight ((opponent1 elephant) (opponent2 elephant))
  (format t "strong elephant knocks down weak elephant. strong elephant wins.~%")
  'elephant)

(defmethod fight ((opponent1 elephant) (opponent2 mouse))
  (format t "mouse scares elephant. mouse wins.~%")
  'mouse)

(defmethod fight ((opponent1 elephant) (opponent2 cat))
  (format t "elephant tramples cat. elephant wins.~%")
  'elephant)

(defmethod fight ((opponent1 elephant) (opponent2 ninja))
  (format t "elephant tramples ninja. elephant wins.~%")
  'elephant)

(defmethod fight ((opponent1 ninja) (opponent2 ninja))
  (format t "good ninja kills bad ninja. good ninja wins.~%")
  'ninja)

(defmethod fight ((opponent1 ninja) (opponent2 mouse))
  (format t "ninja cuts mouse. ninja wins.~%")
  'ninja)

(defmethod fight ((opponent1 ninja) (opponent2 cat))
  (format t "ninja cuts cat. ninja wins.~%")
  'ninja)

(defmethod fight ((opponent1 ninja) (opponent2 elephant))
  (format t "elephant tramples ninja. elephant wins.~%")
  'elephant)

(defun fight! (fighters)
  (reduce #'(lambda (op1 op2)
              (fight (make-instance op1) (make-instance op2)))
          fighters))

CL-USER> (time (fight! '(mouse cat elephant ninja elephant cat mouse elephant mouse ninja elephant cat)))
cat catches mouse. cat wins.
elephant tramples cat. elephant wins.
elephant tramples ninja. elephant wins.
strong elephant knocks down weak elephant. strong elephant wins.
elephant tramples cat. elephant wins.
mouse scares elephant. mouse wins.
mouse scares elephant. mouse wins.
big fat mouse eats small mouse. big fat mouse wins.
ninja cuts mouse. ninja wins.
elephant tramples ninja. elephant wins.
elephant tramples cat. elephant wins.
Evaluation took:
  0.001 seconds of real time
  0.000000 seconds of total run time (0.000000 user, 0.000000 system)
  0.00% CPU
  289,014 processor cycles
  0 bytes consed
  
ELEPHANT
anonymous
()
Ответ на: комментарий от archimag

Пожалуйста:

Ну вот, ты всё испортил! Я хотел показать, что на CL можно реализовать даже тот бред, который грезится плюсовикам ;)

mv ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> рантаймовая диспетчеризация

Есть, по нескольким параметрам, а не только по одному как в C++.

запрет на создание объектов класса Figure


Поскольку такого класса просто нет (ибо абстрактные классы не нужны), то и создать его нельзя.

возможность класть в массив фигур инстансы только

производных классов^W^W тех классов



Извините, у нас динамическая типизация. Впрочем, для объекта можно проверять определена ли для него реализация draw и rotate, так что при желании можно сделать и проверки.

причем draw и rotate не случайно совпавшие по именам,

а проектировавшися как реализация интерфейса



Никаких случайностей. Если определена defgeneric, то с данным именем может связываться только реализация методов.

archimag ★★★
()
Ответ на: комментарий от www_linux_org_ru

А можно по подробнее: ссылкой или примером?

Svoloch ★★★
()
Ответ на: комментарий от anonymous

вот давай-ка, изобрази на C++ или Java:

struct opponent {};
struct cat : public opponent	{};
struct mouse : public opponent	{};
...

struct fighters	{ std::type_info p1; std::type_info p2; };
struct result 	{ int winner; std::string msg; };

#define TYPE( x )		typeid(decltype(x()))
#define PAIR			{ TYPE( x ), TYPE( y ) ) }

static std::map<fighters,result> gPairs;

opponent fight( std::vector<opponent>& ops )
{
	if( !ops.size() )
	{
		return opponent();
	}
	else if( ops.size() == 1 )
	{
		return ops[ 0 ];
	}
	else
	{
		result& res = gPairs[ { typeid( ops[ 0 ] ), typeid( ops[ 1 ] ) } ];
		if( !res.winner ) ops[ 1 ] = ops[ 0 ];
		ops.erase( ops.begin() );
		std::cout << res.msg;

		return fight( ops );
	}
}

int main( int argc, char** argv ) 
{ 
	results[ PAIR( mouse, mouse ) ] = { 0, "big fat mouse eats small mouse. big fat mouse wins." };
	results[ PAIR( cat	, mouse ) ] = { 0, "cat catches mouse. cat wins." };
	...

	std::vector<opponent> ops = { cat(), mouse(), mouse() };
	opponent winner = fight( ops );
} 
lester ★★★★
()
Ответ на: комментарий от anonymous

> плюсисты поджали хвост и ретировались? Аууууу?!

Х.з., у меня сейчас половина рунета отвалилась (и ЛОР в том числе), пришлось экстренно прокси организовать на сервере в Германии ;)

archimag ★★★
()
Ответ на: комментарий от lester

очипятался - вместо results надо gPairs, но думаю суть решения понятна

lester ★★★★
()
Ответ на: комментарий от anonymous

> нет уж, :-) давай для всего зверинца, чтобы выразительность и LOC сравнивать

для каждого зверя будет по две дополнительные строки - лень копипастить :)

lester ★★★★
()
Ответ на: комментарий от lester

> и что же его заменило?

Есть такая замечательная книга «Исскуство программирование для Unix» Э.Рэймонд, там все хорошо расписано, пересказывать целую главу мне как-то в лом.

archimag ★★★
()
Ответ на: комментарий от archimag

это просто чудесно - но ты мог бы сказать, что вот везде юникс выкинули и заменили на ..., или не мог бы?

lester ★★★★
()
Ответ на: комментарий от lester

теперь выбери кого-нибудь с улицы, и покажи два листинга. В котором будет более понятно?

Можно также перфоманс померять на больших списках. Думаю плюсы не намного выйграют, при условии, что будет задействован весь зверинец с ниньзяй.

anonymous
()
Ответ на: комментарий от anonymous

теперь выбери кого-нибудь с улицы, и покажи два листинга. В котором будет более понятно?

я не спорю - в данном случае С++ используется криво, причем без необходимости, я б просто ввел ID и получил:

winner[ MOUSE, CAT 	 ] = { CAT	  , "cat catches mouse. cat wins." };
winner[ MOUSE, MOUSE	] = { MOUSE	, "big fat mouse eats small mouse. big fat mouse wins." };

и человек с улицы явно бы понял это быстрее :)

lester ★★★★
()
Ответ на: комментарий от anonymous

> теперь выбери кого-нибудь с улицы, и покажи два листинга.

В котором будет более понятно?


Пример слишком простой и сила мультиметодов не раскрыта. Что-нибудь более реалистичное и в C++ начнётся полная ж... Точнее, приходиться тратить много сил на продумывание архитектуры, а в CLOS всё решается тривиально.

archimag ★★★
()
Ответ на: комментарий от lester

> я не спорю - в данном случае С++ используется криво, причем без необходимости, я б просто ввел ID и получил:

тогда польза C++ вообще не просматривается. Это можно и на C забабахать.

anonymous
()
Ответ на: комментарий от anonymous

> тогда польза C++ вообще не просматривается. Это можно и на C забабахать.

в С уже есть ассоциативные контейнеры?

lester ★★★★
()
Ответ на: комментарий от lester

+1 давайте что-нибудь придумаем

anonymous
()
Ответ на: комментарий от archimag

Поскольку такого класса просто нет (ибо абстрактные классы не нужны), то и создать его нельзя.

причем draw и rotate не случайно совпавшие по именам, а проектировавшися как реализация интерфейса

Извините, у нас динамическая типизация. Впрочем, для объекта можно проверять определена ли для него реализация draw и rotate, так что при желании можно сделать и проверки.

говняные рантаймовые проверки, в отличие от наших статических?

и еще — я не зря писал насчет сопадения по именам; в с++ может быть

class Something
{
  void draw() { /* тоже отрисовка */ }
  void rotate(int) { /* угол в градусах, писалось без оглядки на Figurе */}
};

и поскольку не сказано «public: Figurе», то никто и не сможет положить его в массив указателей на Figurе; а в МОР?

Поскольку такого класса просто нет (ибо абстрактные классы не нужны), то и создать его нельзя.

хорошо, пусть класса нет; но нужно ЧТО_ТО, что должно иметь название и на что можно сослаться в виде «мы реализуем интерфейс ЧТО_ТО», а если не сослаться — тогда в массив (а лучше vector) из ЧТО_ТО этот объект уже не положить

З.Ы. а без ЧТО_ТО «интерфейс и реализацию» на уровне «int a[3]; a[2]=42»

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от anonymous

> с помощью табличек и тех же ID?

ну значит, кроме С ничего не надо :)

lester ★★★★
()
Ответ на: комментарий от www_linux_org_ru

и где же там простыня? все по делу.

anonymous
()
Ответ на: комментарий от archimag

> Здесь показана простейшая вариация на тему мультиметодов, реализации которых для C++ посвящена не одна сотня страниц уважаемых авторов (включая Александреску), но хорошего решения нет ни у кого.

мультиметоды в стиле map< Pair<MyType,MyType>, MyFunction > (ну или int a[5][5], если иронично) пишутся без проблем и без сотен страниц; Александреску и К исследовали вопросы «мультиметоды и статическая проверка»

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> мультиметоды в стиле map< Pair<MyType,MyType>, MyFunction > (ну или int a[5][5], если иронично) пишутся без проблем

с появлением в C++ decltype, auto и лямбд ( это уже все доступно в стабильных версиях компиляторов ) - это действительно стало просто и красиво

lester ★★★★
()
Ответ на: комментарий от archimag

> Точнее, приходиться тратить много сил на продумывание архитектуры, а в CLOS всё решается тривиально.

если согласится на poor man's solution, а именно отстутствие статических проверок, то все тоже будет тривиально

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> говняные рантаймовые проверки, в отличие от наших статических?

Эти ваши статические проверки дают только оптимизацию и больше ничего. Это давно известно на примере всех динамических языков. Ничего за последние 20 лет не пропустил?

поскольку не сказано «public: Figurе», то никто и не сможет

положить его в массив указателей на Figurе;



Да ладно, что, приведение типов уже запретили? Если в массиве нужны только те объекты, которые реализуют необходимый интерфейс, то кто в здравом уме будет класть туда что-то другое?

нужно ЧТО_ТО, что должно иметь название и на что можно сослаться

в виде «мы реализуем интерфейс ЧТО_ТО»



Про «утиную типизацию» никогда ничего не слышал? Она, кстати, используется в шаблонах C++ и это очень удобно.

а без ЧТО_ТО «интерфейс и реализацию» на уровне «int a[3]; a[2]=42»


Ну вот, а говорил, что разбираешься в виртуальных функциях. Бросай курить эту гадость, точно тебе говорю.

archimag ★★★
()
Ответ на: комментарий от lester

> с появлением в C++ decltype, auto и лямбд ( это уже все доступно в стабильных версиях компиляторов ) - это действительно стало просто и красиво

может и проще, чем было, если плюсатник ничего лучшего не пробовал, но уж красиво - это вряд ли.

anonymous
()
Ответ на: комментарий от www_linux_org_ru

> мультиметоды в стиле map< Pair<MyType,MyType>, MyFunction >

(ну или int a[5][5], если иронично) пишутся без проблем и

без сотен страниц;



Только не надо сказок рассказывать, я писал в таком стиле, угу.

archimag ★★★
()
Ответ на: комментарий от anonymous

может и проще, чем было, если плюсатник ничего лучшего не пробовал, но уж красиво - это вряд ли.

BATTLE( ninja, cat ) = [ auto ninja, auto cat ]{ cout << "ninja cuts cat. ninja wins.\n"; return ninja; };

вроде не так уж и страшно

lester ★★★★
()
Ответ на: комментарий от archimag

> я писал в таком стиле, угу.

ну и зря - это ж криво

lester ★★★★
()
Ответ на: комментарий от anonymous

> лучше, да. ну все равно лямбда страшная :)

согласен - смотрится немного чужеродно, но зато работает

lester ★★★★
()
Ответ на: комментарий от anonymous

> Аууууу?!

у тебя make-instance возвращает х.з. что

тебе надо изображать 1 к 1, т.е. прикрутить дин. типизацию поверх плюсов? без проблем.

или переписать это под статику?

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от lester

> с появлением в C++ decltype, auto и лямбд ( это уже все доступно в

стабильных версиях компиляторов ) - это действительно стало просто

и красиво



В C++ нет мультиметодов, decltype, auto и лямбд не имеют к этому никакого отношения, а если они позволяют украсить старые костыли, то костыли ведь никуда не деваются, они просто чуть симпотичней стали.

archimag ★★★
()
Ответ на: комментарий от archimag

> Да ладно, что, приведение типов уже запретили?

не умеешь пользоваться кастами — ССЗБ

Если в массиве нужны только те объекты, которые реализуют необходимый интерфейс, то кто в здравом уме будет класть туда что-то другое?

твой коллега, которому ты не все успел объяснить,положит туда Something, а потом ты будешь удивляться, почему оно крутится не так, как другие

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от archimag

> В C++ нет мультиметодов

их много где нет - никто от этого не страдает

а если они позволяют украсить старые костыли, то костыли ведь никуда не деваются, они просто чуть симпотичней стали.


согласен - потому я и написал, что я б в таком стиле и не писал бы, гораздо быстрей взять Id у объектов и получить результат без извращений, предварительно декларативно задав отношения между объектами

lester ★★★★
()
Ответ на: комментарий от www_linux_org_ru

> у тебя make-instance возвращает х.з. что

ы? можно конечно проверок наставить на входной параметр, но это к задаче не относится. задачка детская и простенькая.

тебе надо изображать 1 к 1, т.е. прикрутить дин. типизацию поверх плюсов? без проблем.

или переписать это под статику?

меня интересует, как можно красивое решение.

anonymous
()
Ответ на: комментарий от mv

> Circle можно ложить вместе со Square?

можно (а лучше все-таки указатели или ссылки на Circle, я их изначально имел в виду, но пропускаю как очевидное)

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от lester

Вспомнил реальный пример. Я когда-то писал под Autocad с ObjectARX. У меня набор своих классов, производных от классов автокада. У них был общий набор методов, но выразить через какой-либо интерфейс я этого не могу, ибо множественное наследование было исключено (связано со спецификой ObjectARX), да и указатель то я получал на ARX-объект. Т.е. мне надо было на основе этого указателя выяснить истинный тип объекта, привести указатель к этому типу и вызвать необходимый метод. Подобных методов было пара десятков, а необходимость в их вызове была повсеместной и встречалась по всему коду.

Для решения это проблемы я создал список «моих» типов и использовал его в качестве параметра шаблонов, которые перебирали эти типы, находили подходящий тип, производили приведение и вызывали необходимый метод. Окружающие (люди из моей команды) смотрели на этот код с восхищением: он делал совершенную волшебную вещь, позволял вызвать нужный метод, не являющийся частью какого-либо интерфейса, у объекта неизвестного типа.

Такие весёлые были шаблоны, рекурсивные, завязанные на частичную специализацию. Их было относительно легко писать и расширять. Правда, в один прекрасный момент случилась неприятность: компилятор от MS стал падать, крича от том что имя типа не помещается в выделенному буфере (получались длинные имена). Суть не в этом, это мы кое-как разрулили, но тоже характерная проблема. А суть в том, что подобная проблема вообще невозможна в CL. В CL можно было бы просто брать и вызывать необходимые методы. И рулить по многим параметрам. И вообще, много чего ещё, что совершенно не реально для C++.

archimag ★★★
()
Ответ на: комментарий от anonymous

меня интересует, как можно красивое решение.

на С++ пожалуй это будет так:

opponent fight( stack<opponent>& ops )
{ 
	if( ops.size() == 0 ) return opponent();
	if( ops.size() == 1 ) return ops.pop();
	ops.push( WINNER( ops.pop(), ops.pop() ) );
	return fight( ops );
}

...
BATTLE( ninja, cat ) = [ auto ninja, auto cat ]{ cout << "ninja cuts cat. ninja wins.\n"; return ninja; };
BATTLE( cat, mouse ) = [ auto cat, auto mouse ]{ cout << "cat catches mouse. cat wins.\n"; return cat; };

...
stack<opponent> ops = { cat(), mouse(), mouse() }; 
opponent winner = fight( ops );

это если обязательно надо использовать «костыли», а не id( id не так «красив» конечно, но зато быстр )

lester ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.