Здравствуйте, VladD2, Вы писали:
ВВ>>В покере не силен, как и в Немерле, но на функциональный манер получается что-то типа:... VD>В императивной версии разбираться просто в лом, но если они соотвествуют, то это хорошая демонстрация того насколько программа, будучи переписанная в функциональном стиле (даже без излишних вывертов), становится понятнее и короче.
Мне, честно говоря, тоже в лом было в императивной разбираться
VD>Ну, и однобуквенные имена полей, на мой взгляд, не плохое решение.
В первоначальном варианте вообще все было в строчку написано. F# в этом плане очень хороший язык, неплохо дисциплинирует.
К слову, вариант на F#:
#light
type CardSuit =
| V = 13
| Q = 14
| K = 15
| T = 16
type Card =
| Plain of int
| High of CardSuit
with member c.GetRank() =
match c with
| Plain(v) -> v
| High(s) -> (int)s
type CardCombination =
| Single of Card
| Pair of Card
| TwoPair of CardCombination*CardCombination
| Three of Card
| Street of Card
| Flush of Card
| Full of Card
| Four of Card
| StreetFlush of Card
with member c.GetRank() =
match c with
| Single(c) -> c.GetRank()
| TwoPair(p1, p2) -> p1.GetRank() + p2.GetRank()
| Pair(c) -> c.GetRank() + 0x20
| Three(c) -> c.GetRank() + 0x80
| Street(c) -> c.GetRank() + 0x100
| Flush(c) -> c.GetRank() + 0x200
| Full(c) -> c.GetRank() + 0x300
| Four(c) -> c.GetRank() + 0x400
| StreetFlush(c) -> c.GetRank() + 0x500
let rec getRank (c:list<CardCombination>) =
match c with
| [] -> 0
| x::xs -> x.GetRank() + (xs |> getRank)
let cards = Pair(High(CardSuit.V)) :: Single(High(CardSuit.Q)) :: Single(Plain(6)) :: Single(High(CardSuit.T)) :: []
let res = getRank cards
По-моему не такие уж большие отличия по синтаксису. Хотя вот почему-то он меня заставил аннотацию типа для функции написать
А вот если писать на F# в стиле class based OOP это будет, конечно, кошмар
ВВ>В первоначальном варианте вообще все было в строчку написано. F# в этом плане очень хороший язык, неплохо дисциплинирует.
В F# табличное форматирование тоже было бы очень полезно.
ВВ>...По-моему не такие уж большие отличия по синтаксису.
Дык ты в основном пользовался алгебраическими типами которые у обоих языков позаимствованы из ML-я. Если в Немерле еще указать "#pragma indent", то вообще очень похоже будет.
ВВ>Хотя вот почему-то он меня заставил аннотацию типа для функции написать
Кто? F#?
ВВ>А вот если писать на F# в стиле class based OOP это будет, конечно, кошмар
Ага. С ФП у него намного лучше чес с ООП и МП. Это следствие того, что язык не проектировался с нуля, а является адаптацией OCaml-а. У создателей OCaml-а был свой, весьма своеобразный взгляд на ООП (функциональный).
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, AngeL B., Вы писали:
AB>Здравствуйте, VladD2, Вы писали:
H>>>Нашел: Type Inference with Deferral VD>>Ага. Но человеческим это можно назвать только если ты из научной среды .
AB>А вот, кстати, совсем не праздный вопрос. AB>Учитывая куда (на майкрософт) ведет ссылка, описывающая алгоритм вывода типов в языке, не является ли это бомбой под будущем языка? Ведь они там могут и запатентовать его (тьфу-тьфу-тьфу и по дереву постучал).
Они не смогут запатентовать то, что было реализовано и опубликовано не ими до подачи их гипотетической заявки на патент. А если смогут, то такой патент без проблем оспаривается.
Здравствуйте, VladD2, Вы писали:
ВВ>>...По-моему не такие уж большие отличия по синтаксису. VD>Дык ты в основном пользовался алгебраическими типами которые у обоих языков позаимствованы из ML-я. Если в Немерле еще указать "#pragma indent", то вообще очень похоже будет.
Вот тут есть интересный момент. Как только на Немерле начинаешь писать в функциональном стиле, то он плавным движением руки превращается в ML.
А вот у той же Скалы совсем другая философия — она вообще выглядит так, как будто в ней функциональные конструкции имитируются через ООП. Даже не знаю, как сказать точно. Может быть, некоторых пугает такая двойственность Немерле
ВВ>>Хотя вот почему-то он меня заставил аннотацию типа для функции написать VD>Кто? F#?
Ну да.
ВВ>>А вот если писать на F# в стиле class based OOP это будет, конечно, кошмар VD>Ага. С ФП у него намного лучше чес с ООП и МП. Это следствие того, что язык не проектировался с нуля, а является адаптацией OCaml-а. У создателей OCaml-а был свой, весьма своеобразный взгляд на ООП (функциональный).
Да вообще с их явным порядком файлов и плоской структурой проекта что-то большое на F# писать запаришься.
ЗЫ. Кстати, вот как выглядит вышепоказанный пример на моем интерпретаторе:
let (V, Q, K, T) = (13, 14, 15, 16);
type Card = Plain(v) | High(v);
let GetCardRank = c ->
match (c)
| Plain(v) -> v
| High(v) -> v;
type Comb =
Single(c) | Pair(c) | TwoPair(p1, p2) | Three(c) | Street(c)
| Flush(c) | Full(c) | Four(c) | StreetFlush(c);
let GetRank = cc ->
match (cc)
| Single(c) -> GetCardRank(c)
| TwoPair(p1, p2) -> GetRank(p1) + GetRank(p2)
| Pair(c) with r = 0x20
| Three(c) with r = 0x80
| Street(c) with r = 0x100
| Flush(c) with r = 0x200
| Full(c) with r = 0x300
| Four(c) with r = 0x400
| StreetFlush(c) with r = 0x500 -> GetCardRank(c) + r;
let CalcRank = l -> match(l)
| [] -> 0 | x::xs -> GetRank(x) + CalcRank(xs);
let cards = Comb.Pair(Card.High(V)) ::
Comb.Single(Card.High(Q)) ::
Comb.Single(Card.Plain(6)) ::
Comb.Single(Card.High(T)) :: [];
CalcRank(cards);
Здравствуйте, Воронков Василий, Вы писали:
ВВ>А вот у той же Скалы совсем другая философия — она вообще выглядит так, как будто в ней функциональные конструкции имитируются через ООП. Даже не знаю, как сказать точно. Может быть, некоторых пугает такая двойственность Немерле
На самом деле Скала и Немерл идеологически очень похожи. В немерле тоже ФП выражается через ОО-конструкции. У скалы есть свои преимущество, но у нее нет одной мелочи — макросов. А эта мелочь дорогого стоит.
ВВ>>>Хотя вот почему-то он меня заставил аннотацию типа для функции написать VD>>Кто? F#?
ВВ>Ну да.
А что говорит?
ВВ>Да вообще с их явным порядком файлов и плоской структурой проекта что-то большое на F# писать запаришься.
Ну, на ОКамле ведь писали? Это конечно неудобно и непривычно но не смертельно. И вообще, главный козырь это не фичи языка, а декларированная поддержка МС.
ВВ>ЗЫ. Кстати, вот как выглядит вышепоказанный пример на моем интерпретаторе:
А зачем ты его создавал?
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
ВВ>>>>Хотя вот почему-то он меня заставил аннотацию типа для функции написать VD>>>Кто? F#? ВВ>>Ну да. VD>А что говорит?
Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
ВВ>>ЗЫ. Кстати, вот как выглядит вышепоказанный пример на моем интерпретаторе: VD>А зачем ты его создавал?
Кризис среднего возраста видимо Хочется написать свой язык программирования. Да и 100% managed embeddable script штука вообще полезная.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.
ВВ>Кризис среднего возраста видимо Хочется написать свой язык программирования.
Лучше помог бы нам в работе над Nemerle 2.
ВВ>Да и 100% managed embeddable script штука вообще полезная.
Дык есть железные Питон и Руби же. Плюс джава скрип никто не отменял.
К тому же в качестве такового можно и немерл использовать. Как видишь по количеству кода он очень то уступает скриптам, а по скорости и надежности сильно их превосходит. Макросы позволяют интегрировать в язык нужные DSL-и, что резко повышает уровень скрипта.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, VladD2, Вы писали:
VD>Я напрочь испорчен интеллисенсм. Моя продуктивность без него на порядки ниже.
Я ещё много пишу в С++, где интеллисенс реже работает, чем нет.
VD>А в Виме есть фичи облегчающие табличное форматирование? VD>Как они работают?
Для Вима есть скрипт Align с широким набором форматов табличного выравнивания. С ним можно выделить блок текста, набрать \tsp и текст будет выравнен в таблицу с колонками разделёнными пробелами; \t= выравнивнивает по знакам =, а \t: по двоеточиям. Есть специальные шаблоны для выравнивания комментариев, объявлений функций, HTML таблиц и многого другого.
ВВ>Поощряет или нет, но в императивном стиле на Немерле писать практически так же удобно, как и на Шарпе — особенно по сравнению с тем же F#, который, к слову, тоже позиционируется как гибридный язык.
А какие проблемы у F# с императивным кодом?
Я вот сейчас на OCaml, гоню сплошной императивный код (оптимизация) никаких неудобств не вижу.
Здравствуйте, VladD2, Вы писали:
ВВ>>Да вообще с их явным порядком файлов и плоской структурой проекта что-то большое на F# писать запаришься.
VD>Ну, на ОКамле ведь писали? Это конечно неудобно и непривычно но не смертельно. И вообще, главный козырь это не фичи языка, а декларированная поддержка МС.
Так я опять что-то пропустил?
На OСaml никакой плоской структуры не наблюдается, вложенные модули без проблем. Есть небольшие проблем с линкером при циклических ссылках и все, на F# что опять все испортили?
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, Mystic, Вы писали:
ВВ>Посмотрел еще раз твой первоначальный код. Все же до конца не уверен, что правильно понял задачу. Есть комбинация карт и надо вычислить некий числовой эквивалент, как бы силу комбинации.
Спасибо, буду разбираться. В принципе оценка силы комбинации в функциональном стиле может быть хорошим упражнением. Тут, как я понимаю, просто идет определение силы комбинации, но как это происходит пока не видно Но есть впечатление, что даже не по правилам покера. Плюс изначально карты сгруппированы
что может быть не совсем удобно для семикарточного варианта или для Омахи и вообще при случайной генерации рук. Но как общий пример функционального подхода может быть полезным, постараюсь его взять за основу, перекроить и набить очередные шишки
Но в двух словах про задачу, которую решал я:
Есть такой софт, который называется покерный калькулятор. Задача состоит в том, чтобы подсчитать вероятность победы одного из игроков, если оба дойдут до конца раздачи. Способ решения обычный перебор. Например, у меня есть две карты на руках, у соперника есть две карты на руках. И еще есть пять закрытых карт. Это порядка 1.7M комбинаций. Обычно задача калькулятора состоит в том, чтобы перебрать все эти комбинации и выдать количество побед первого игрока, количество побед второго игрока, количество ничьих и выдать проценты. Естественно, что определение достоинства комбинации должно быть реализовано максимально быстро (в частности PokerStove выполняет указанный перебор за доли секунды).
В данном случае я немного упростил реальную жизнь, и рассматривал определение силу не семикарточной комбинации, а пятикарточной. Но общее требование остается таким же: необходимо быстро выполнить достаточно много оценок. Один из алгоритмов быстрого вычисления силы руки по пяти картам описан тут. В этом алгоритмы используются вычисленные заранее таблицы. Вот вычисление этих таблиц я и хотел получить Nemerle.
Изначально задача стояла в том, чтобы перечислить все возможные покерные комбинации в порядке от самой сильной к самой слабой, и для каждой из них вычислить уникальный хэш. Список должен быть таким: AKQJTs, KQJT9s, ..., 65432s, A5432s, AAAAK, AAAAQ, ..., AAAA2, KKKKA, KKKKQ, ... (всего 7462 комбинаций, s в конце означает, что все карты одной масти — suited). Это и делает мой код на C#.
Здравствуйте, VladD2, Вы писали:
VD>В императивной версии разбираться просто в лом, но если они соотвествуют, то это хорошая демонстрация того насколько программа, будучи переписанная в функциональном стиле (даже без излишних вывертов), становится понятнее и короче.
Что-то мне кажется, что это совсем разные программы
Здравствуйте, FR, Вы писали:
ВВ>>Поощряет или нет, но в императивном стиле на Немерле писать практически так же удобно, как и на Шарпе — особенно по сравнению с тем же F#, который, к слову, тоже позиционируется как гибридный язык.
FR>А какие проблемы у F# с императивным кодом? FR>Я вот сейчас на OCaml, гоню сплошной императивный код (оптимизация) никаких неудобств не вижу.
Думаю, что он имел в виду ОО-стиль.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте, FR, Вы писали:
FR>На OСaml никакой плоской структуры не наблюдается, вложенные модули без проблем. Есть небольшие проблем с линкером при циклических ссылках и все, на F# что опять все испортили?
Разве необходимость объявлять типы перед тем как они используются — это придумка F#-а? Я в ОКамле не силен, но что-то мне казалось, что это из него пошло.
В прочем, может быть это проблемы расширения алгоритма вывода типов сделанного в F#.
Что до модулей, то в F# модуль — это сборка. А сборки в дотнете сильно боше чем модули (юниты) в других языках. И вот в их рамках F# обязывает располагать типы последовательно. А так как он позволяет их разносить по отдельным файлам, то требуют располагать файлы в определенной последовательности.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
VD>Разве необходимость объявлять типы перед тем как они используются — это придумка F#-а? Я в ОКамле не силен, но что-то мне казалось, что это из него пошло.
Необходимость объявлять есть, но также есть возможность предварительного (неконкретизированного) объявления типов и сигнатур функций. Для этого есть .mli файлы во многом аналог сишных заголовочных файлов.
Например в .mli такое объявление:
type command
val command: ?doc:string -> string -> Arg.spec -> command
в .ml конкретизация:
type command =
{ doc : string(**The documentation associated to the keyword, possibly empty.*);
kwd : string(**The keyword. Should start with "-"*);
spec : Arg.spec (**The behavior associated to the keyword*);
}
let command ?(doc="") kwd spec =
{ doc = doc;
kwd = kwd;
spec= spec }
VD>В прочем, может быть это проблемы расширения алгоритма вывода типов сделанного в F#.
VD>Что до модулей, то в F# модуль — это сборка. А сборки в дотнете сильно боше чем модули (юниты) в других языках. И вот в их рамках F# обязывает располагать типы последовательно. А так как он позволяет их разносить по отдельным файлам, то требуют располагать файлы в определенной последовательности.
В OCaml подобная заморочка есть только у линкера, в исходном же коде можно произвольно располагать.
Здравствуйте, FR, Вы писали:
FR>Необходимость объявлять есть,
Ну, вот отсюда ноги и растут. Будучи помноженным на объем дотнетных сборок получается форменная проблема.
FR>но также есть возможность предварительного (неконкретизированного) объявления типов и сигнатур функций. Для этого есть .mli файлы во многом аналог сишных заголовочных файлов.
Да какая разница? Все равно важно файлы в определенной последовательности держать или держать все в одном файле и уже в нем последовательность отслеживать.
В ОКамле, возможно, остроту проблемы снимало тот факт, что модули ОКамла значительно меньше модулей дотнета (сборок).
Зато в ОКамле дургих проблем хватает. Невозможность создать перегрузку и т.п.
FR>Например в .mli такое объявление:
FR>
Здравствуйте, VladD2, Вы писали:
VD>Здравствуйте, Mystic, Вы писали:
M>>Что-то мне кажется, что это совсем разные программы
VD>Возможно. Но из твоей понять суть алгоритма очень сложно. А из его элементарно.
Без нужного опыта совсем неэлементарно. Но после некоторого вникания в код у меня возникла мысль, что данный исходник просто считает взвешенную сумму элементов списка.