Re[13]: Что такого привлекательного в Nemerle?
От: Воронков Василий Россия  
Дата: 01.04.10 12:10
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Изначально задача стояла в том, чтобы перечислить все возможные покерные комбинации в порядке от самой сильной к самой слабой, и для каждой из них вычислить уникальный хэш. Список должен быть таким: AKQJTs, KQJT9s, ..., 65432s, A5432s, AAAAK, AAAAQ, ..., AAAA2, KKKKA, KKKKQ, ... (всего 7462 комбинаций, s в конце означает, что все карты одной масти — suited). Это и делает мой код на C#.


Если речь идет о том, что все карты даны в произвольном порядке и не сгруппированы, то проще всего их вначале отсортировать
Потом ты можешь построить матч по образцу голова-хвост (x::y::xs::..) и перебрать там все основные комбинации (матч эвалюируется последовательно) — пара, тройка, четверка, стрит.
Re[11]: Что такого привлекательного в Nemerle?
От: Воронков Василий Россия  
Дата: 01.04.10 12:14
Оценка: 1 (1)
Здравствуйте, FR, Вы писали:

FR>А какие проблемы у F# с императивным кодом?

FR>Я вот сейчас на OCaml, гоню сплошной императивный код (оптимизация) никаких неудобств не вижу.

Проблем нет. Но чтобы писать императивно на F#, придется потратить куда больше времени на изучение F#, чем в случае с Немерле, где императивный код очень похож на таковой в шарпе.
Re[14]: Что такого привлекательного в Nemerle?
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 01.04.10 12:30
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Если речь идет о том, что все карты даны в произвольном порядке и не сгруппированы, то проще всего их вначале отсортировать

ВВ>Потом ты можешь построить матч по образцу голова-хвост (x::y::xs::..) и перебрать там все основные комбинации (матч эвалюируется последовательно) — пара, тройка, четверка, стрит.

Это долго. Если, например, я выпущу какой-нить покерный калькулятор, который будет в 10 раз медленнее бесплатных аналогов, то кого он заинтересует? Пусть даже и будут дополнительные возможности В общем максимальная производительность будем считать требованием, прописанным в ТЗ.

В общем случае используется такой трюк: каждому достоинству карты сопоставляется простое число. Например, двойке сопоставляется 2, тройке — 3, четверке — 5, пятерке — 7, шестерке — 11, семерке — 13, восьмерке — 17, девятке — 19, десятке — 23, валету — 29, даме — 31, королю — 37, тузу — 41. Тогда (если не учитывать флеш) одинаковые по старшинству комбинации будут иметь одинаковое произведения этих простых чисел. Т. е. для того, чтобы определить старшинство комбинации надо будет четыре умножений + одно обращение к таблице. В случае возможного флеша (видно по таблице CMP) необходимо будет выполнить проверку на флеш (четыре OR + AND + CMP) и взять из таблицы другое значение. Итого для вычисления достоинства комбинации нам придется потратить от 10 (не флеш) до 20 (флеш) машинных инструкций плюс одно-два ветвления.

Другое дело, что эту таблицу надо сформировать, возможно оптимизировать по размеру... Это некритичная ко времени задача вполне может быть написана на том средстве, которое для этого будет наиболее удобным. Вот эту утилиту я и реализовывал.
Re[21]: Что такого привлекательного в Nemerle?
От: FR  
Дата: 01.04.10 12:32
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Ну, вот отсюда ноги и растут. Будучи помноженным на объем дотнетных сборок получается форменная проблема.


Так я все-таки похоже торможу. В C# (и в Немерли) тоже ведь необходимо предварительное объявление, в чем же разница с F#?

FR>>но также есть возможность предварительного (неконкретизированного) объявления типов и сигнатур функций. Для этого есть .mli файлы во многом аналог сишных заголовочных файлов.


VD>Да какая разница? Все равно важно файлы в определенной последовательности держать или держать все в одном файле и уже в нем последовательность отслеживать.


Все таки непонятно, можно проиллюстрировать на примере?

VD>В ОКамле, возможно, остроту проблемы снимало тот факт, что модули ОКамла значительно меньше модулей дотнета (сборок).


Ну большущие модули там тоже есть например в ocaml-win32.

VD>Зато в ОКамле дургих проблем хватает. Невозможность создать перегрузку и т.п.


Это-то тут причем?

VD>Ужас. Каменный век.


В чем тут каменный век-то?

FR>>В OCaml подобная заморочка есть только у линкера, в исходном же коде можно произвольно располагать.


VD>Ну, как же произвольно если ты сам выше сказал, что типы должно быть известны заранее?


Мы в чем-то друг-друга так и не поняли.
Re[12]: Что такого привлекательного в Nemerle?
От: FR  
Дата: 01.04.10 12:35
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Проблем нет. Но чтобы писать императивно на F#, придется потратить куда больше времени на изучение F#, чем в случае с Немерле, где императивный код очень похож на таковой в шарпе.


Если в F# не расширили императивное подмножество в сравнении с OCaml'ом то там практически нечего изучать, по сути классический паскаль
Re[15]: Что такого привлекательного в Nemerle?
От: Воронков Василий Россия  
Дата: 01.04.10 13:35
Оценка:
Здравствуйте, Mystic, Вы писали:

M>Здравствуйте, Воронков Василий, Вы писали:


ВВ>>Если речь идет о том, что все карты даны в произвольном порядке и не сгруппированы, то проще всего их вначале отсортировать

ВВ>>Потом ты можешь построить матч по образцу голова-хвост (x::y::xs::..) и перебрать там все основные комбинации (матч эвалюируется последовательно) — пара, тройка, четверка, стрит.

M>Это долго. Если, например, я выпущу какой-нить покерный калькулятор, который будет в 10 раз медленнее бесплатных аналогов, то кого он заинтересует? Пусть даже и будут дополнительные возможности В общем максимальная производительность будем считать требованием, прописанным в ТЗ.


Тебе же таблицу надо генерить. Так казалось бы зачем производительность коду, который генерит таблицу? Запустил его один раз, отработал — и все.
Плюс ты недооцениваешь производительность ФП-кода. Единственная проблема матчей в том, что они не компилируются в джамп-таблицу, но у тебя самого джамп-таблицей и не пахнет. В остальном Немерле очень неплохо оптимизирует матчи. Наконец он поддерживает оптимизацию хвостовой рекурсии. Так что производительность может быть более чем приемлимая.

Основная философия ФП — никакой premature optimization
Re[19]: Что такого привлекательного в Nemerle?
От: Воронков Василий Россия  
Дата: 01.04.10 13:52
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Попробуй поменять местами строки:

VD>
VD>    | [] -> 0 
VD>    | x::xs -> x.GetRank() + (xs |> getRank)
VD>


Не помогает. Видимо, не сдюжил таки вывод типов.

ВВ>>Кризис среднего возраста видимо Хочется написать свой язык программирования.

VD>Лучше помог бы нам в работе над Nemerle 2.

Немерле 2? А чем это отличается от просто Немерле? С нуля хотите переделать что ли?

ВВ>>Да и 100% managed embeddable script штука вообще полезная.

VD>Дык есть железные Питон и Руби же. Плюс джава скрип никто не отменял.

Джава скрипт достал К тому же скрипт с полноценной поддержкой ФП все же явление редкое.
Ну и наконец надо же вначале "на собаках" потренироваться

VD>К тому же в качестве такового можно и немерл использовать. Как видишь по количеству кода он очень то уступает скриптам, а по скорости и надежности сильно их превосходит. Макросы позволяют интегрировать в язык нужные DSL-и, что резко повышает уровень скрипта.


Дело не в краткости кода. Во многих случаях компиляция вносит очень сильный оверхед. Это если речь идет именно о встраиваемом скрипте, который можно поменять на лету и перезапустить.
В таком сценарии Немерле мне кажется не очень подойдет, очень уж тяжелая сборка у него.
Re[20]: Что такого привлекательного в Nemerle?
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.04.10 14:32
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

VD>>Попробуй поменять местами строки:

VD>>
VD>>    | [] -> 0 
VD>>    | x::xs -> x.GetRank() + (xs |> getRank)
VD>>


ВВ>Не помогает. Видимо, не сдюжил таки вывод типов.


А попробуй уточнить тип у "[]". Просто интересна причина.

ВВ>Немерле 2? А чем это отличается от просто Немерле? С нуля хотите переделать что ли?


Отличия будут не очень большими, но очень полезными. Во-первых, хотим заменить подсистему парсинга сделав ее декларативной на основе PEG. Это позволит снять большинство ограничений и сделать синтаксис более расширяемым. Во-вторых, хотим переписать на бело, так чтобы избавиться от имеющихся проблем. В частности сделать движок компилятора многопоточным, версионным, чтобы не было проблем в интеграции и извлекалась выгода от многоголовых камней современных процессоров. Кроме того попросту нужно переписать компилятор, чтобы он был более понятным и легко изменяемым.

ВВ>Джава скрипт достал К тому же скрипт с полноценной поддержкой ФП все же явление редкое.


Эрланг — весьма популярен в узких кругах.

ВВ>Ну и наконец надо же вначале "на собаках" потренироваться


Тренироваться лучше на кошках. Вот Немерл — отличный пушистый котенок с больным животиком. Можно мучить сколько угодно, хозяева даже не заметят .

ВВ>Дело не в краткости кода. Во многих случаях компиляция вносит очень сильный оверхед. Это если речь идет именно о встраиваемом скрипте, который можно поменять на лету и перезапустить.


Это не проблема. Компилятор полностью менеджед. Мелкие куски компилируются в мгновение ока. Зато скорость на уровне шарпа.

ВВ>В таком сценарии Немерле мне кажется не очень подойдет, очень уж тяжелая сборка у него.


А какая реальная задача то?

ЗЫ

Я (да и многие другие) использую немерл в весьма скриптовых целях уже несколько лет. Получается весьма не плохо. В прочем, я уже неплохо с ним знаком...
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[22]: Что такого привлекательного в Nemerle?
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.04.10 14:39
Оценка:
Здравствуйте, FR, Вы писали:

FR>Так я все-таки похоже торможу. В C# (и в Немерли) тоже ведь необходимо предварительное объявление, в чем же разница с F#?


Нет, такой необходимости нет. Тип просто должен быть. А где совершенно не важно. Предварительное объявление нужно только для локальных переменных и локальных функций. Но на то они и локальные.

FR>Все таки непонятно, можно проиллюстрировать на примере?


Представ. У тебя два типа в разных файлах. Если один использует второй, то или этот второй должен находиться в файле идущем по порядку раньше, или ты вынужден будешь внести его описание в первый файл. В любом случае получается зависимость от расположения.

В Немерле и Шарпе я могу объявить один тип в одном файле, а другой в другом. И мне будет совершенно все равно где и как расположены файлы. Я всегда смогу использовать один тип из другого (в том числе рекурсивно) без дополнительных объявлений и каких бы то ни было лишних телодвижений.

VD>>Зато в ОКамле дургих проблем хватает. Невозможность создать перегрузку и т.п.


FR>Это-то тут причем?


В F# перегрузка поддерживается. Не так полноценно как в Nemerle или C#, но все же. Это позволяет намного проще интегрироваться с дотнетом и си-подобными языками. Но алгоритм вывода типов при этом резко усложняется.

VD>>Ужас. Каменный век.


FR>В чем тут каменный век-то?


В наличии предеклараций. Это было простительно для С/С++ учитываях дремучесть их просхождения. Но в языке высокого уровня это просто жутко выглядит.

FR>>>В OCaml подобная заморочка есть только у линкера, в исходном же коде можно произвольно располагать.


VD>>Ну, как же произвольно если ты сам выше сказал, что типы должно быть известны заранее?


FR>Мы в чем-то друг-друга так и не поняли.


Видимо.
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[23]: Что такого привлекательного в Nemerle?
От: FR  
Дата: 01.04.10 15:30
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Нет, такой необходимости нет. Тип просто должен быть. А где совершенно не важно. Предварительное объявление нужно только для локальных переменных и локальных функций. Но на то они и локальные.


Вообще-то в OCaml также, просто нужно использовать <имя модуля>.<функция> например Printf.printf никакого предварительного объявления типа open Printf при этом не нужно. Но ограничения на взаиморекурсивность все-таки есть.

FR>>Все таки непонятно, можно проиллюстрировать на примере?


VD>Представ. У тебя два типа в разных файлах. Если один использует второй, то или этот второй должен находиться в файле идущем по порядку раньше, или ты вынужден будешь внести его описание в первый файл. В любом случае получается зависимость от расположения.


Да такое есть, но только для линкера в сборочном файле важен порядок следования модулей, в исходниках этого не видно.

VD>В Немерле и Шарпе я могу объявить один тип в одном файле, а другой в другом. И мне будет совершенно все равно где и как расположены файлы. Я всегда смогу использовать один тип из другого (в том числе рекурсивно) без дополнительных объявлений и каких бы то ни было лишних телодвижений.


Если не рекурсивно то и в Ocaml также.

FR>>В чем тут каменный век-то?


VD>В наличии предеклараций. Это было простительно для С/С++ учитываях дремучесть их просхождения. Но в языке высокого уровня это просто жутко выглядит.


Предекларации опциональны. Не хочешь не используешь.
Re[24]: Что такого привлекательного в Nemerle?
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.04.10 16:12
Оценка: +1
Здравствуйте, FR, Вы писали:

FR>Вообще-то в OCaml также, просто нужно использовать <имя модуля>.<функция> например Printf.printf никакого предварительного объявления типа open Printf при этом не нужно. Но ограничения на взаиморекурсивность все-таки есть.


Мне не слышат? В F# модулем является сборка! Так что считай, что большая часть кода программы у тебя в одном модуле.

FR>Да такое есть, но только для линкера в сборочном файле важен порядок следования модулей, в исходниках этого не видно.


Ну, а как это задать в проекте? Или ты мэйком пользуешся?

VD>>В Немерле и Шарпе я могу объявить один тип в одном файле, а другой в другом. И мне будет совершенно все равно где и как расположены файлы. Я всегда смогу использовать один тип из другого (в том числе рекурсивно) без дополнительных объявлений и каких бы то ни было лишних телодвижений.


FR>Если не рекурсивно то и в Ocaml также.


Да не так же. И ты сам об этом говоришь. Я тебе еще раз подчеркиваю, работа ведется в рамках одного модуля. В дотнете видимость типов определяется пространствами иемен. В этом, возможно главное, отличие F#-а от ОКамла.

FR>Предекларации опциональны. Не хочешь не используешь.


Ага. Колхоз дело добровольное. Хочешь вступай, хочешь не вступай. Все равно корову отымим (с).
Так и тут. Хочешь предекларации делай, хочешь описания последовательно выстраивай.
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[25]: Что такого привлекательного в Nemerle?
От: FR  
Дата: 01.04.10 16:49
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Мне не слышат? В F# модулем является сборка! Так что считай, что большая часть кода программы у тебя в одном модуле.


Торможу я сегодня
Сижу читаю спецификацию F#, да оказывается не только функторы выкинули

Кстати в OCaml такое вполне легко эмулируется, так как модули не обязаны совпадать с единицами трансляции, в такой единице может быть
сколько угодно (в том числе и взаимно рекурсивных) вложенных модулей. Правда не получится растащить один namespace на несколько разных
единиц трансляции.

FR>>Да такое есть, но только для линкера в сборочном файле важен порядок следования модулей, в исходниках этого не видно.


VD>Ну, а как это задать в проекте? Или ты мэйком пользуешся?


Я да мейком, у меня смесь с С++, а так тот же ocamlbuild все сам разруливает.
Задать просто, определить зависимости и располагать более общие объектники перед их использующими.

VD>Да не так же. И ты сам об этом говоришь. Я тебе еще раз подчеркиваю, работа ведется в рамках одного модуля. В дотнете видимость типов определяется пространствами иемен. В этом, возможно главное, отличие F#-а от ОКамла.


Угу.

VD>Ага. Колхоз дело добровольное. Хочешь вступай, хочешь не вступай. Все равно корову отымим (с).

VD>Так и тут. Хочешь предекларации делай, хочешь описания последовательно выстраивай.

Нет если предеклараций нет, то просто считается что все глобальные объявления ml файла доступны.

.mli позволяет скрыть ненужное. При этом .mli логически это сигнатура (интерфейс модуля):

module A: sig (* содержимое файла a.mli *) end
      = struct (* содержимое файла a.ml *) end;;
Re[26]: Что такого привлекательного в Nemerle?
От: VladD2 Российская Империя www.nemerle.org
Дата: 01.04.10 16:55
Оценка:
Здравствуйте, FR, Вы писали:

FR>Задать просто, определить зависимости и располагать более общие объектники перед их использующими.


Дык это и есть вручную выставить порядок файлов.
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[16]: Что такого привлекательного в Nemerle?
От: Mystic Украина http://mystic2000.newmail.ru
Дата: 01.04.10 18:34
Оценка:
Здравствуйте, Воронков Василий, Вы писали:

ВВ>Тебе же таблицу надо генерить. Так казалось бы зачем производительность коду, который генерит таблицу? Запустил его один раз, отработал — и все.


Я скачу от одной задачи к другой (генерация таблицы и оценивание), отсюда непонятки. Если у нас задача сгенерировать таблицу, то основная проблема не в оценке произвольной руки, а в том, чтобы сгенерировать все возможные 7462 комбинаций. И если мы их сгенерируем в порядке от самой сильной к самой слабой (или наоборот), то у нас автоматически для каждой комбинации будет ее сила. Оценка рук может потребоваться только в том случае, когда мы генерируем все возможные комбинации в произвольном порядке. Но этот вариант мне не очень по душе. Да и как их генерировать все в произвольном порядке я слабо себе представляю, кроме самого лобового решения перебирать все 2598960 сочетаний из 52 по 5.

Если брать конкретно вычисление силы руки на C, то чтобы было понятно, оно ориентировочно будет выглядеть так:

inline int is_flush_5(const card_t* cards)
{
  // Проверяем, все ли карты одной масти. Предполагаем, что масти это степени двойки
  // (например, 0x01 это пики, 0x02 это трефы, 0x04 это бубны и 0x08 это червы

  return cards[0].get_suit() == 
    0
    | cards[1].get_suit()
    | cards[2].get_suit()
    | cards[3].get_suit()
    | cards[4].get_suit()
  ;  
}

inline int evaluate_5(const card_t* cards)
{
  // Вычисляем хэш как произведение простых чисел, которые соответствуют номиналу карты
  // В общем случае номинал карты удобно выражать этим простым числом
  int product = 1
    * cards[0].get_primary_nominal()
    * cards[1].get_primary_nominal()
    * cards[2].get_primary_nominal()
    * cards[3].get_primary_nominal()
    * cards[4].get_primary_nominal()
  ;

  // По хэш-таблице получаем интересующий нас элемент, 
  // MOD используется для оптимизации размера
  // MAGIC_HASH_DIVIDER можно подобрать таким образом, 
  // чтобы все product % MAGIC_HASH_DIVIDER были различны
  hand_info_t* hand_info = magic_hash_table + (product % MAGIC_HASH_DIVIDER);

  // Если не может быть флеша (есть повторы карт), то можно сразу вернуть силу руки
  if (hand_info->no_flush) return hand_info->normal_rank;

  // Может быть флеш, поэтому надо сделать дополнительную проверку
  return is_flush_5(cards) ? hand_info->flush_rank : hand_info->normal_rank;
}


Если, например, предположить, что card_t определен так:

enum nominal_t = 
{
  NOMINAL_2 =  2,
  NOMINAL_3 =  3,
  NOMINAL_4 =  5,
  NOMINAL_5 =  7,
  NOMINAL_6 = 11,
  NOMINAL_7 = 13,
  NOMINAL_8 = 17,
  NOMINAL_9 = 19,
  NOMINAL_T = 23,
  NOMINAL_J = 29,
  NOMINAL_Q = 31,
  NOMINAL_K = 37,
  NOMINAL_A = 41
};

enum suit_t =
{
  SUIT_S = 0x01,
  SUIT_C = 0x02,
  SUIT_D = 0x04,
  SUIT_H = 0x08
};

class card_t
{
public:
  card_t(suit_t suit, nominal_t nominal): _suit(suit), _nominal(nominal) {}
  inline suit_t get_suit() const { return _suit; }
  inline int get_primary_nominal() const { return _nomimal; }
private:
  suit_t _suit;
  nominal_t _nominal;
};


то вычисления сведены к минимуму.



ВВ>Плюс ты недооцениваешь производительность ФП-кода. Единственная проблема матчей в том, что они не компилируются в джамп-таблицу, но у тебя самого джамп-таблицей и не пахнет. В остальном Немерле очень неплохо оптимизирует матчи. Наконец он поддерживает оптимизацию хвостовой рекурсии. Так что производительность может быть более чем приемлимая.


ВВ>Основная философия ФП — никакой premature optimization


Естественно у меня нет никаких match-ей. Мне вообще не нужно вычислять силу комбинации, потому что в том коде, что я приводил раньше, я их сразу генерирую в нужном мне порядке. Вот небольшой анализ:

    
/* Этот код генерирует все 2860 комбинаций "пара" от самой сильной AAKQJ к самой слабой 22543 */

static public void Pair()
{
/* Четыре цикла, каждый в каждом, это самый простой императивный способ генерирования сочетаний. */

  for (int Base = 13; Base >= 1; --Base)
  for (int Kicker1 = 13; Kicker1 >= 1; --Kicker1)
  for (int Kicker2 = Kicker1 - 1; Kicker2 >= 1; --Kicker2)
  for (int Kicker3 = Kicker2 - 1; Kicker3 >= 1; --Kicker3)
  {

    // Небольшие проблемы с порядком (Base учитывается в первую очередь), поэтому
    // надо добавить сравнения
    if (Base == Kicker1) continue;
    if (Base == Kicker2) continue;
    if (Base == Kicker3) continue;

    // Можно добавлять
    AddNormal(Primary[Base] * Primary[Base] * Primary[Kicker1] * Primary[Kicker2] * Primary[Kicker3]);
  }
}


Однажды овладев этим способом генерации сочетаний в лексикографиеском порядке в средней школе я применяю всю жизнь В общем случае, если надо сгенерировать все сочетания c1, c2, c3 в лексикографическом порядке, то самое простое написать

  for(c1 = 0;    c1 <= M; ++c1)
  for(c2 = c1+1; c2 <= M; ++c2)
  for(c3 = c2+1; c3 <= M; ++c3)


В результате мы получим
      0, 1, 2
      0, 1, 3
      0, 1, 4
      ...
      0, 1, M 
      0, 2, 3
      0, 2, 4
      ...
      0, 2, M 

      ...

      M-2, M-1, M


NOTE: Вот в этом случае я особенно надеялся на помощь немерле, как раз в генерации таких сочетаний Например, некоторый могучий макрос

generate_combination(0..M, c1, c2, c3)
{
  Write("{0}, {1}, {2}", c1, c2, c3);
}


где первый параметр список, сочетания (определенной длины) которого мы генерируем. c1, c2, c3 это переменные, куда заносятся текущие значения. Или какой-то трюк со списками... Но ума не хватило Но мой императивный идеал

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

Конечно, небольшой копипаст, но в данном случае он ИМХО оправдан. А в случае императивного Nemerle я представлял в своем больном воображении такой аналог: (синтаксис map взят из головы, вообще больше псевдокод):

generate_combination(map(13..1, x => get_primary(x)), base)
generate_combination(map(13..1, x => get_primary(x)), kicker1, kicker2, kicker3)
{
  if ([base] intersect [kicker1, kicker2, kicker3]) != []) continue; // intersect это пересечение списков
  add_normal(base * base * kicker1 * kicker2 * kicker3); 
}


Ну а до функционального аналога... Я вижу так:

  all_base_combinations = generate_combination_list(map(13..1, x => get_primary(x)), 1);
  // Например, вернули ленивый список всех сочетаний длины 1 в лексикографическом порядке
  // Опять же map беру из головы

  all_kicker_combinations = generate_combination_list(map(13..1, x => get_primary(x)), 3);
  // Например, вернули ленивый список всех сочетаний длины 3 в лексикографическом порядке
  // Результат [ [41, 37, 31], [41, 37, 29], [41, 37, 23], ...]

  foreach(base in all_base_combinations)
    foreach(kickers in all_base_combinations)
    {
      if (intersect(base, kickers) == [])
        add(product(map(base, x => x * x)) * product(kickers));
    }


Хотя есть императивный foreach... Но в принципе от него просто избавиться написав нужные функции обработки списков
Re[27]: Что такого привлекательного в Nemerle?
От: FR  
Дата: 02.04.10 10:53
Оценка:
Здравствуйте, VladD2, Вы писали:

VD>Дык это и есть вручную выставить порядок файлов.


Угу если мейком пользуешься, приходится вручную. Системы сборки все сами делают.
Re[26]: Что такого привлекательного в Nemerle?
От: Аноним  
Дата: 02.04.10 14:02
Оценка:
VD>>Мне не слышат? В F# модулем является сборка! Так что считай, что большая часть кода программы у тебя в одном модуле.

FR>Торможу я сегодня

FR>Сижу читаю спецификацию F#, да оказывается не только функторы выкинули

Но модули же есть в спецификации, 10.2 Module definition.
Или это какие-то другие модули?
Re[27]: Что такого привлекательного в Nemerle?
От: FR  
Дата: 02.04.10 15:16
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Но модули же есть в спецификации, 10.2 Module definition.

А>Или это какие-то другие модули?

Урезанные, как я понял сигнатуры задавать нельзя кроме как в fsi файле (это и понятно без полиморфности модулей они не очень и нужны),
локальных http://caml.inria.fr/pub/docs/manual-ocaml/manual021.html#toc74 и рекурсивных http://caml.inria.fr/pub/docs/manual-ocaml/manual021.html#toc75
модулей тоже нет.
Re[28]: Что такого привлекательного в Nemerle?
От: VladD2 Российская Империя www.nemerle.org
Дата: 02.04.10 15:49
Оценка:
Здравствуйте, FR, Вы писали:

FR>Урезанные, как я понял сигнатуры задавать нельзя кроме как в fsi файле (это и понятно без полиморфности модулей они не очень и нужны),

FR>локальных http://caml.inria.fr/pub/docs/manual-ocaml/manual021.html#toc74 и рекурсивных http://caml.inria.fr/pub/docs/manual-ocaml/manual021.html#toc75
FR>модулей тоже нет.

Я правильно понимаю, что в F# модуль — это просто разновидность типа?
http://nemerle.org/Banners/?g=dark
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[29]: Что такого привлекательного в Nemerle?
От: FR  
Дата: 02.04.10 16:03
Оценка:
Здравствуйте, VladD2, Вы писали:


VD>Я правильно понимаю, что в F# модуль — это просто разновидность типа?


Мне кажется разновидность namespace.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.