Re[4]: Функциональное программирование в Nemerle
От: IT Россия linq2db.com
Дата: 30.05.07 15:58
Оценка: +1
Здравствуйте, anonym469, Вы писали:

IT>>получалось примерно такое же г.

A>Компактное г, смею заметить. А не пятикратное г.

Г. оно хоть компактное, хоть не очень, всё равно г.

ЗЫ. Я то этой фигнёй занимался от безнадёги, т.к. меня с C++ на C обратно на какое-то время пересадили. А зачем тебе это надо совсем непонятно.
... << RSDN@Home 1.2.0 alpha rev. 0>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[3]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 30.05.07 16:01
Оценка: 35 (1) +1
Здравствуйте, Кэр, Вы писали:

Кэр>konsoletyper, смелее, можно словами


OK.

Про new тебе уже сказали. Кроме того, хочу добавить, что и в C# можно банально объявить конструктор как protected и заставлять создавать объекты через статический метод, так что создание объекта — это не прерогатива одного лишь конструктора. Да и понятие "создание объекта" — вещь весьма условная и работающая только при ортодоксальном ООП. Вот здесь
Автор: konsoletyper
Дата: 17.05.07
я немного пофлеймил по этому поводу. В частности, в "функциональных" вещах типа Compiler-compiler
Автор: konsoletyper
Дата: 31.03.07
удобнее рассматривать множество объектов как нечто метофизическое, а конструктор — как функцию, дающую доступ к одному из объектов множества. Можно, в принципе, и в чём-то вроде GUI так же относиться ко всему (тогда конструктор кроме этого добавляет к объекту некий неопределяемый "identity"), но, ИМХО, это неудобно. Вообще, использовать new или нет — дело привычки, и, поверь, когда привыкнешь не писать new, обратно отвыкнуть будет труднее.

По поводу : bool. Nemerle тем и славен, что у него есть вывод типов. Однако, это не сказывается на читабельности, т.к. вывод типов на уровне методов отключён. А узнать тип возвращаемого значения достаточно просто — надо глянуть на возвращаемое значение. Кстати, как человек, имеющий опыт программирования на питоне и пхп, могу сказать, что быстро оценил эту полезную фичу Nemerle.

По поводу return. Важно понимать, что в Nemerle ты не можешь что-то сделать и вернуть. Ты можешь просто описать функцию, которая что-то возвращает. Всякие match и if — это не операторы, а выражения, т.е. любая из ветвей этих конструкция должна содержать некоторое выражение. Это выражение вычисляется. В частности выражение { a; b; ...; c } означает, что перед вычислением данного выражения исполняются (вычисляются) a, b и ..., а потом вычисляется c, которое и есть результат вычисления всего выражения. Это похоже на begin в scheme.
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[4]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 01:12
Оценка: 1 (1) +1
Здравствуйте, konsoletyper, Вы писали:

K>Кроме того, хочу добавить, что и в C# можно банально объявить конструктор как protected и заставлять создавать объекты через статический метод, так что создание объекта — это не прерогатива одного лишь конструктора.

А я между прочим этого и не утверждал.

K>Да и понятие "создание объекта" — вещь весьма условная и работающая только при ортодоксальном ООП. Вот здесь
Автор: konsoletyper
Дата: 17.05.07
я немного пофлеймил по этому поводу. В частности, в "функциональных" вещах типа Compiler-compiler
Автор: konsoletyper
Дата: 31.03.07
удобнее рассматривать множество объектов как нечто метофизическое, а конструктор — как функцию, дающую доступ к одному из объектов множества. Можно, в принципе, и в чём-то вроде GUI так же относиться ко всему (тогда конструктор кроме этого добавляет к объекту некий неопределяемый "identity"), но, ИМХО, это неудобно. Вообще, использовать new или нет — дело привычки, и, поверь, когда привыкнешь не писать new, обратно отвыкнуть будет труднее.

Повторюсь — я не осозновал, что в Nemerle конструктор не обязательно возвращает новый объект. С учетом специфики работы конструктора в .Net (в частности в силу отсутвия его собрата — деструктора) это может быть и вполне оправдано. Но опять же — это радикальное отличие от остальных .Net языков. Так что этому пожалуй стоит уделить особое внимание для "начинающих на Nemerle".

K>По поводу : bool. Nemerle тем и славен, что у него есть вывод типов. Однако, это не сказывается на читабельности, т.к. вывод типов на уровне методов отключён. А узнать тип возвращаемого значения достаточно просто — надо глянуть на возвращаемое значение.

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

K>По поводу return. Важно понимать, что в Nemerle ты не можешь что-то сделать и вернуть. Ты можешь просто описать функцию, которая что-то возвращает. Всякие match и if — это не операторы, а выражения, т.е. любая из ветвей этих конструкция должна содержать некоторое выражение. Это выражение вычисляется. В частности выражение { a; b; ...; c } означает, что перед вычислением данного выражения исполняются (вычисляются) a, b и ..., а потом вычисляется c, которое и есть результат вычисления всего выражения. Это похоже на begin в scheme.

Ну и что? Это никак не противоречит тому, что выставления return в том месте, где возращается уже конечное значение (некоторое value-значение или объект) — повышает читабельность кода.
Re[2]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка: +1
Здравствуйте, Кэр, Вы писали:

Кэр>здесь в коде выделены жирным элементы, которые призваны улучшить читаемость


От догм и предрассудков лучше избавляться.

Кстати, есть один вопрос:
    | EndOfFile           => return stack.Count == 1
        ...
    | EndRound            => check(_ is Token.BeginRound)  // )

А почему в первой строчке return понадобился, а во второй нет?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>В том-то и дело, что не равно. Метод может вернуть существующую копию объекта, конструктор всегда даст новый объект. Это уже дает совершенно разное отношение к этому коду.


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

К тому же, если это так уж актуально, то всегда можно подвести мышку в IDE и посмореть, что это такое...

Кэр>Кроме того — лучше когда сразу понятно, куда надо если что обратить свой взор — где могут быть потенциальные проблемы.


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

Кэр> В одношаговых логических цепочках — это все равно, если что внимательно посмотрели на контекст, спохватились, начали думать в другом направлении. В более длинных цепочках подобные умолчания будут только тормозить решение проблемы.


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

Кэр>И вообще если уж говорить про принципиальные отличия: внутри обычного метода можно использовать вызовы виртуальных методов, внутри конструктора нельзя — так что думать о них как о близнецах-братьях очень не рекомендуется.


1. Ты глубого заблуждаешся. В дотнете без проблем можно вызвать виртуальные методы из констроторов и финалайзеров.
2. А это уже никого не трогает. Точнее трогает того кто создает этот метод/конструктор. Ты работаешь с черным ящиком. Собственно это и есть инкапсуляция.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, nikov, Вы писали:

N>В Nemerle вызов конструктора не всегда возвращает новый объект.


Можно с этого места по подробнее? О чем речь?
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, konsoletyper, Вы писали:

K>Вообще, использовать new или нет — дело привычки, и, поверь, когда привыкнешь не писать new, обратно отвыкнуть будет труднее.


Хочу подчеркнуть эту мысль. Порой мы просто привыкаем к некоторому подходу и начинаем думать, что это "единственно верный путь". Привыкать к другому подходу всегда трудно. Это всегда вызвать некоторое неприятие.

Однако есть четкий способ понять какой из путей лучше. Если при обратном переходе неприятие (ломка) становится больше, то однозначо первый путь был хуже.

Так вот, подобные вещи в Немерле случаются очень часто. По началу кажется, что в нем использованы весьма спорыные решения, но поработав на Немеле и возвращаясь к C# начинашь испытвать такую ломку, что понимашь — решения выбранные в нем не случайны. Они имеют под собой основания. Просто эти основания не сразу становятся очевидными.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Повторюсь — я не осозновал, что в Nemerle конструктор не обязательно возвращает новый объект.


Откровенно говоря я и по сей момент не осознаю. Семантика конструктора в Немерле вроде кака 1 в 1 C#-ная. Наверно, стоит дождаться пояснений от nikov-а.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, anonym469, Вы писали:

A>Компактное г, смею заметить. А не пятикратное г.


Не очень. Просто автор "забыл" привести две тонны кода эмулируюих паттерн матчинг. Уверю тнебя, там будет не только не мало кода, но он будет еще и тормозным и не универсальным.

Дело в том, что паттерн-матчинг — это не очень тривиальная вещь. Разбирая match-и компилятор проводит весьма интеллектуальную работу. Он выстраивает дерево решения и уже на его основании генерирует ординарный код. Получаемый в результате код получается весьма эффективным. Достичь того же самого эмуляцией невозможно. Любое усложнение образцов будет усложнять задачу на порядки.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[5]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 11:06
Оценка:
Здравствуйте, IT, Вы писали:

IT>ЗЫ. Я то этой фигнёй занимался от безнадёги, т.к. меня с C++ на C обратно на какое-то время пересадили. А зачем тебе это надо совсем непонятно.


Это как раз вроде ясно. Вудя по айпишникам — это тот самый троль, что развил всю тему.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[3]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 11:54
Оценка: -1 :))
Здравствуйте, VladD2, Вы писали:

VD>От догм и предрассудков лучше избавляться.


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

VD>Кстати, есть один вопрос:

VD>
VD>    | EndOfFile           => return stack.Count == 1
VD>        ...
VD>    | EndRound            => check(_ is Token.BeginRound)  // )
VD>

VD>А почему в первой строчке return понадобился, а во второй нет?

Как раз по тем причинам, что я указывал выше — return обозначает то место, где начнет разворачиваться стэк вызовов функций.
Такой return
VD>
VD>    | EndRound            => return check(_ is Token.BeginRound)  // )
VD>

лишний. Здесь просто вычисления идут вглубь по стэку вызова.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 11:54
Оценка:
Здравствуйте, VladD2, Вы писали:

Кэр>>В том-то и дело, что не равно. Метод может вернуть существующую копию объекта, конструктор всегда даст новый объект. Это уже дает совершенно разное отношение к этому коду.


VD>И в чем разница?

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

Дело в другом: когда мне объект падает от конструктора — я знаю, что это brand new объект. У меня не будет проблем с синхронизацией при его использовании. Мне не нужно будет думать — а вдруг его свойства уже как-то криво проинициализированны и мне нужно сначала исполнить шаманский танец перед его использованием.
Чаще всего Если это не так — значит это бага класса.
Поясню на примере — если мне приходит SqlCommand из какого-то метода, значит лезем в метод и смотрим, что за объект, что с ним уже сделали и пр. Если объект получен из конструктора — сразу работаем дальше.

VD>К тому же, если это так уж актуально, то всегда можно подвести мышку в IDE и посмореть, что это такое...


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

Кэр>>Кроме того — лучше когда сразу понятно, куда надо если что обратить свой взор — где могут быть потенциальные проблемы.


VD>Лучше сосредоточить свое внимание на логике программы. Тогда, если что просто не случится. Или если вдруг случится, то ты все равно будешь иметь больший контроль над программой, так как не возишся с мелочевкой, а владеешь сутью программы.


Когда сам пишешь код — ага. Когда читаешь чужой код — все намного хуже. Суть программы еще не схвачена. До нее как раз надо докопаться. В своем исходном посте я как раз привел ключевые слова, которые на мой взгляд к этому подталкивают.

Кэр>> В одношаговых логических цепочках — это все равно, если что внимательно посмотрели на контекст, спохватились, начали думать в другом направлении. В более длинных цепочках подобные умолчания будут только тормозить решение проблемы.

VD>Это в тебе говорят привычки и догмы. Точнее ты пыташся выдумать проблемы там где их нет, чтобы обосновать привычный тебе внешний вид кода.
Отнюдь. Вот это ни разу не привычный мне внешний вид кода.
def calc() : bool
{}

Просто этот код гораздо более информативный, чем этот:
def calc()
{}

Причем данная инфмормативность для автора кода чаще всего ничего не стоит.

Кэр>>И вообще если уж говорить про принципиальные отличия: внутри обычного метода можно использовать вызовы виртуальных методов, внутри конструктора нельзя — так что думать о них как о близнецах-братьях очень не рекомендуется.


VD>1. Ты глубого заблуждаешся. В дотнете без проблем можно вызвать виртуальные методы из констроторов и финалайзеров.


Как ты думаешь, что произойдет, если создать экземпляр Derived класса?
public abstract class Base
    {
        public Base()
        {
            Log("Instance created");
        }

        public abstract void Log(string message);
    }

    public class Derived : Base
    {
        public Derived()
        {
             _logMessages = new StringBuilder();
        }

        private StringBuilder _logMessages;

        public override void Log(string message)
        {
            _logMessages.Append(message);
            Console.WriteLine(message);
        }
    }



VD>2. А это уже никого не трогает. Точнее трогает того кто создает этот метод/конструктор. Ты работаешь с черным ящиком. Собственно это и есть инкапсуляция.


С этим не спорю. Я говорил о том, что в целом нельзя относится к конструктору и к методу, как к одному и тому же.
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[5]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 31.05.07 12:16
Оценка: 2 (1)
Здравствуйте, Кэр, Вы писали:

K>>Да и понятие "создание объекта" — вещь весьма условная и работающая только при ортодоксальном ООП. Вот здесь
Автор: konsoletyper
Дата: 17.05.07
я немного пофлеймил по этому поводу. В частности, в "функциональных" вещах типа Compiler-compiler
Автор: konsoletyper
Дата: 31.03.07
удобнее рассматривать множество объектов как нечто метофизическое, а конструктор — как функцию, дающую доступ к одному из объектов множества. Можно, в принципе, и в чём-то вроде GUI так же относиться ко всему (тогда конструктор кроме этого добавляет к объекту некий неопределяемый "identity"), но, ИМХО, это неудобно. Вообще, использовать new или нет — дело привычки, и, поверь, когда привыкнешь не писать new, обратно отвыкнуть будет труднее.

Кэр>Повторюсь — я не осозновал, что в Nemerle конструктор не обязательно возвращает новый объект. С учетом специфики работы конструктора в .Net (в частности в силу отсутвия его собрата — деструктора) это может быть и вполне оправдано. Но опять же — это радикальное отличие от остальных .Net языков. Так что этому пожалуй стоит уделить особое внимание для "начинающих на Nemerle".

Ну, я сам не особо разбираюсь в нюансах работы компилятора Nemerle. Но дело не в том, что реально возвращается конструктором, а как это значение интерпретируется человеком. Если просто читать программу в "фнукциональном" режиме, то использование new начинает казаться неоправданным.

K>>По поводу : bool. Nemerle тем и славен, что у него есть вывод типов. Однако, это не сказывается на читабельности, т.к. вывод типов на уровне методов отключён. А узнать тип возвращаемого значения достаточно просто — надо глянуть на возвращаемое значение.

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

Да нет, никаких проблем с этим не возникает. Обычно, если грамотно называть функции и переменные, производить декомпозицию, то всё становится более менее очевидным. В худшем случае никто не мешает навиести курсор на функцию и получить хинт. Советую заодно присмотреться к динмически-типизированным языкам вроде PHP и Python, где при правильном проектировании и документировании таких проблем не возникает. Пролемы в них возникают при отладке, а вот в ML-образных языках мы получаем такую же лаконичность и не теряем в удобстве отладки (потенциально).

K>>По поводу return. Важно понимать, что в Nemerle ты не можешь что-то сделать и вернуть. Ты можешь просто описать функцию, которая что-то возвращает. Всякие match и if — это не операторы, а выражения, т.е. любая из ветвей этих конструкция должна содержать некоторое выражение. Это выражение вычисляется. В частности выражение { a; b; ...; c } означает, что перед вычислением данного выражения исполняются (вычисляются) a, b и ..., а потом вычисляется c, которое и есть результат вычисления всего выражения. Это похоже на begin в scheme.

Кэр>Ну и что? Это никак не противоречит тому, что выставления return в том месте, где возращается уже конечное значение (некоторое value-значение или объект) — повышает читабельность кода.

Опять же, значение не возвращается, а вычисляется. И это совершенно разные вещи. Вообще, если ты ещё не сомтрел на Scheme, то советую почитать SICP, там все эти вещи хорошо описаны (ой, сейчас Влад на меня зарычит, но я всё же твёрдо останусь при мнении, что SICP — отличное руководство по ФП для начинающих).

А так попытаюсь сам объяснить. В ИП программа состоит из набора инструкций, которые последовательно друг за другом исполняются. Иногда последовательноть может несколько нарушится (if, break, return, etc), чтобы опять потом продолжиться. Процедура тоже выполняется последовательно, пока не встретится return.

В ФЯ никакой последовательности нет. Например, результат вычисления if или match не обяззательно возвращать из функции, можно присвоить его какой-нибудь переменной. Советую посмотреть в рефлекторе на код, в который разворачиваются if'ы, в которых используются "переменные", объявленные при помощи def, и тоже вычисляющиеся при помощи if. Гарантирую, тебя ожидает много интересного.

Вот как вообще можно прийти к ФЯ. Пусть у нас имеется простейший калькулятор, считающий мат. выражения вроде:

2 * 3 + 5 / 7;


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

d = b ^ 2 — 4 * a * c;
((-b — sqr(d)) / (2 * a), (-b + sqr(d)) / (2 * a))

далее, для расчёта формулы могут понадобитья более сложные вещи, которые часто встречаются в различных задачах. Так что мы вводим возможность записывать собственные функции. Например, если какой-то фокрмуле используется тангенс, который отсутствует в стандартном наборе функций, чтобы не писать всюду sin(x) / cos(x) мы записываем

tg(x) = sin(x) / cos(x)


и далее используем в нашей формуле более краткую и очевидную форму.

Наконец, некоторые вещи не выразишь в виде всяких sin, cos, +, -, etc. Пусть, например, нужно записать функцию, вычисляющую модуль числа. Для этого нужно расширить наш язык:

abs(x) = if (x > 0) x else -x


abs(x) =
    when x > 0 => x
    when x < 0 => -x


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

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

factorial(x) =
    when x = 0 => 1
    when x > 0 => x * factorial(x - 1)


Ну а дельше мы можем понапихать в наш калькулятор всяких других вкусностей типа паттерн-матчинга, вложенных функций, лямбд и т.п. И получим полноценный чистый ФЯ. Но в нём будет проблема — нельзя в нём сделать что-то императивное. Потому уместно будет сделать доп. инструкцию imperative { }, где в фигурных скобках располагается код, выполняющий что-то императивное, а значением конструкции будет последнее выражение в ней. Правда, всё это оверхед, и потому разработчики Nemerle решили, что блок, залючённый в фигурные скобки, будет содержать как сложенные переменные, нигде больше не использующиеся (типа let x = ... in ... в OCaml), и императивный код. Причём нет особой разницы между императивными и чистыми функциями, просто вводится доп. тип данных void, которому принадлежит одно значение (). Собственно, () является знгачением функций вроде присваивания (=) или Console.WriteLine().
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[6]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 31.05.07 12:29
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Дело в другом: когда мне объект падает от конструктора — я знаю, что это brand new объект. У меня не будет проблем с синхронизацией при его использовании. Мне не нужно будет думать — а вдруг его свойства уже как-то криво проинициализированны и мне нужно сначала исполнить шаманский танец перед его использованием.


Неужели? А вдруг вновь созданный объект содержит внутри себя ссылку на уже давно созданный объект? От кривого изайна никакой компилятор не спасёт...

Кэр>Отнюдь. Вот это ни разу не привычный мне внешний вид кода.

Кэр>
Кэр>def calc() : bool
Кэр>{}
Кэр>

Кэр>Просто этот код гораздо более информативный, чем этот:
Кэр>
Кэр>def calc()
Кэр>{}
Кэр>

Кэр>Причем данная инфмормативность для автора кода чаще всего ничего не стоит.

Наивный...

А если из этой функции что-то невразумительное возвращается, вроде Map[string * bool, list[int * bool * string * string]]? Это, конечно, перегиб, и не стоит использовать такие вот конструкции в чём-то большом. Но бывает и так, что подобные выкрутасы являются более оправданными. Что же, мне всё это расписывать?

Кэр>С этим не спорю. Я говорил о том, что в целом нельзя относится к конструктору и к методу, как к одному и тому же.


Кто тебе это сказал?
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[4]: Функциональное программирование в Nemerle
От: konsoletyper Россия https://github.com/konsoletyper
Дата: 31.05.07 12:29
Оценка: :)
Здравствуйте, Кэр, Вы писали:

VD>>Кстати, есть один вопрос:

VD>>
VD>>    | EndOfFile           => return stack.Count == 1
VD>>        ...
VD>>    | EndRound            => check(_ is Token.BeginRound)  // )
VD>>

VD>>А почему в первой строчке return понадобился, а во второй нет?

Кэр>Как раз по тем причинам, что я указывал выше — return обозначает то место, где начнет разворачиваться стэк вызовов функций.

Кэр>Такой return
VD>>
VD>>    | EndRound            => return check(_ is Token.BeginRound)  // )
VD>>

Кэр>лишний. Здесь просто вычисления идут вглубь по стэку вызова.

Непоследовательно...
... << RSDN@Home 1.2.0 alpha rev. 672>>
Re[6]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 13:01
Оценка:
Здравствуйте, konsoletyper, Вы писали:

Кэр>>Повторюсь — я не осозновал, что в Nemerle конструктор не обязательно возвращает новый объект. С учетом специфики работы конструктора в .Net (в частности в силу отсутвия его собрата — деструктора) это может быть и вполне оправдано. Но опять же — это радикальное отличие от остальных .Net языков. Так что этому пожалуй стоит уделить особое внимание для "начинающих на Nemerle".


K>Ну, я сам не особо разбираюсь в нюансах работы компилятора Nemerle. Но дело не в том, что реально возвращается конструктором, а как это значение интерпретируется человеком. Если просто читать программу в "фнукциональном" режиме, то использование new начинает казаться неоправданным.


Здесь
Автор: Кэр
Дата: 31.05.07
я расписал, почему стоит различать вызов конструктора и метода.

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


K>Да нет, никаких проблем с этим не возникает. Обычно, если грамотно называть функции и переменные, производить декомпозицию, то всё становится более менее очевидным. В худшем случае никто не мешает навиести курсор на функцию и получить хинт. Советую заодно присмотреться к динмически-типизированным языкам вроде PHP и Python, где при правильном проектировании и документировании таких проблем не возникает. Пролемы в них возникают при отладке, а вот в ML-образных языках мы получаем такую же лаконичность и не теряем в удобстве отладки (потенциально).


Спор ради спора? Ты даже готов следить за правильным именованием методов и переменных — лишь бы не указывать небольшую дополнительную информацию. Чем тебе так мешает этот : bool?

Кэр>>Ну и что? Это никак не противоречит тому, что выставления return в том месте, где возращается уже конечное значение (некоторое value-значение или объект) — повышает читабельность кода.


K>Опять же, значение не возвращается, а вычисляется. И это совершенно разные вещи. Вообще, если ты ещё не сомтрел на Scheme, то советую почитать SICP, там все эти вещи хорошо описаны (ой, сейчас Влад на меня зарычит, но я всё же твёрдо останусь при мнении, что SICP — отличное руководство по ФП для начинающих).


Под возращением я имел ввиду то место, где начинает разворачиваться стэк вызовов. Я понимаю отличие императивного и функционального кода
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 13:04
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Дело в другом: когда мне объект падает от конструктора — я знаю, что это brand new объект. У меня не будет проблем с синхронизацией при его использовании.


Это в корне не верное предположение. Объект может быть устроен как угодно. В том числе он может запоминать создаваемые экземлпяры в неком глобальном массиве. Стало быть, любые предположения могут быть невреными.

Именно по этому объекты рассматривают как черные ящики имеющие только публичный интерфейс и некое оговариваемое поведение. Последнее и обуславливает то как можно использовать объект.

Кэр> Мне не нужно будет думать — а вдруг его свойства уже как-то криво проинициализированны и мне нужно сначала исполнить шаманский танец перед его использованием.


Если тебе нужно думать о таких вещах, то это уже признак того, что класс спроектирован из рук плохо.

Кэр>Поясню на примере — если мне приходит SqlCommand из какого-то метода, значит лезем в метод и смотрим, что за объект, что с ним уже сделали и пр. Если объект получен из конструктора — сразу работаем дальше.


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

Кэр>Да поддержка IDE — великая вещь. Но если из самого кода можно понять, что тут написано и быстро сделать вывода, причем стоимость создания такого кода невелика — то нужно писать как можно более понятный код. Ведь за мышкой покаааа потянееешься...


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

Когда мне нужно знать тип фукнции я просто подвожу мышку к нужному вызову. Точно так же если я не уверен в том, что за вызов находится у меня в коде, я могу подвести мышку и увидеть надпись "constructor..." где будет кроме всего прочего еще описание типов его параметров и возомжно подсказка.

Когда же я читаю код мне важны более абстракные факты. Я и так додумаюсь, что это создание новго объекта.

К тому же функцианальный стиль подталкивает к тому, что бы воспринималь, по возможности, все как вызовы фукнций. И то что конструктор тоже выглядит как фукнция — это часть этого стиля.

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

Кэр>Когда сам пишешь код — ага. Когда читаешь чужой код — все намного хуже. Суть программы еще не схвачена.


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

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


Просто ты привык читать запутанный код и тебе кажется, что лишние (не влияющие на логику) являются очень важными. На самом деле это не так. Точнее если бы это было так, то прграммы написанные на скриптовых языках вроде Питона или Руби вообще невозможно было читать. Однако многие находят, что как раз все с точностью до наоборот и программы на хороших скриптовых языках читать проще чем, скажем, на C#.

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

Кэр>Отнюдь.

Я тоже писал в прошлом на С/С++/C#/Delphi и т.п. и знаю о чем говорю.

Кэр> Вот это ни разу не привычный мне внешний вид кода.

Кэр>
Кэр>def calc() : bool
Кэр>{}
Кэр>

Кэр>Просто этот код гораздо более информативный, чем этот:
Кэр>
Кэр>def calc()
Кэр>{}
Кэр>

Кэр>Причем данная инфмормативность для автора кода чаще всего ничего не стоит.

Да не проблема, если тебе кажется это лучшим ты имешь право вставить тип явно. Более того ты можешь указать тип даже там где в C# это сделать невозможно. Свобода выбора!

Но это очень примитивный случай. Здесь явное указание типа не заграмождает код. А бывает, так что парметров моного и типы начинают занимать слишком много места. Причем из параметров и названия метода ясно, что за типы у параметров и возвращаемого значения. При этом явное указанеие типов будет только мешать.

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

Кэр>Как ты думаешь, что произойдет, если создать экземпляр Derived класса?


Если все спроектировано грамотно, то все будет ОК. А нагородить ошибок можно и без того. К тому же я не понимаю какой смысл обсуждать факт? Это реальность и о ней нужно знать.

Кэр>
Кэр>public abstract class Base
Кэр>    {
Кэр>        public Base()
Кэр>        {
Кэр>            Log("Instance created");
Кэр>        }

Кэр>        public abstract void Log(string message);
Кэр>    }

Кэр>    public class Derived : Base
Кэр>    {
Кэр>        public Derived()
Кэр>        {
Кэр>             _logMessages = new StringBuilder();
Кэр>        }

Кэр>        private StringBuilder _logMessages;

Кэр>        public override void Log(string message)
Кэр>        {
Кэр>            _logMessages.Append(message);
Кэр>            Console.WriteLine(message);
Кэр>        }
Кэр>    }
Кэр>


Будет исключение которое с вероятностью 99% будет выявлено при первом же запуске.

Кэр>С этим не спорю. Я говорил о том, что в целом нельзя относится к конструктору и к методу, как к одному и тому же.


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

Интересно, кстати, что в Немреле с конструктором ожно обращаться точно так же как с функций. Например, следующий пример прекрасно работает:
def strCreator = string;
def someFanction(f)
{
    f(array['H', 'i', '!'])
}

WriteLine(someFanction(strCreator));


И того у нас получается:
1. Функция — это превокласное значение в Немерле. Ею можно гибко манипулировать.
2. Конструктор — это тоже частный вид функции.
Ну, и вывод:
Мы получаем мощнейшие выразительные средства функциональной декомпозиции. И все это благодаря тому, что наш язык более абстрактен нежели закомплексованные императивные предшественники.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[7]: Функциональное программирование в Nemerle
От: Кэр  
Дата: 31.05.07 13:11
Оценка:
Здравствуйте, konsoletyper, Вы писали:

Кэр>>Дело в другом: когда мне объект падает от конструктора — я знаю, что это brand new объект. У меня не будет проблем с синхронизацией при его использовании. Мне не нужно будет думать — а вдруг его свойства уже как-то криво проинициализированны и мне нужно сначала исполнить шаманский танец перед его использованием.


K>Неужели? А вдруг вновь созданный объект содержит внутри себя ссылку на уже давно созданный объект? От кривого изайна никакой компилятор не спасёт...


Ответ содержится в той части, которая выпала из цитаты

Кэр>>Отнюдь. Вот это ни разу не привычный мне внешний вид кода.

Кэр>>
Кэр>>def calc() : bool
Кэр>>{}
Кэр>>

Кэр>>Просто этот код гораздо более информативный, чем этот:
Кэр>>
Кэр>>def calc()
Кэр>>{}
Кэр>>

Кэр>>Причем данная инфмормативность для автора кода чаще всего ничего не стоит.

K>Наивный...


K>А если из этой функции что-то невразумительное возвращается, вроде Map[string * bool, list[int * bool * string * string]]? Это, конечно, перегиб, и не стоит использовать такие вот конструкции в чём-то большом. Но бывает и так, что подобные выкрутасы являются более оправданными. Что же, мне всё это расписывать?


В таком случае — тем более. Это часть сигнатуры функции. Если функция имеют такую страшную сигнатуру — в большинстве случаев это нужно знать заранее.
Опять же ключевое слово — в большинстве. Подчеркиваю: написать bool — очень просто, а самодокументирование кода сильно возрастает.

Кэр>>С этим не спорю. Я говорил о том, что в целом нельзя относится к конструктору и к методу, как к одному и тому же.

K>Кто тебе это сказал?

Опыт использования технологии .Net. Ты пробовал запустить тот код, что я привел выше по ветке?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[7]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 13:28
Оценка: +1
Здравствуйте, Кэр, Вы писали:

Кэр>Ты даже готов следить за правильным именованием методов и переменных — лишь бы не указывать небольшую дополнительную информацию. Чем тебе так мешает этот : bool?


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

Кажется, что в данном месте понятнее? Ну, поставь тип. Кажется, что и так все понятно — не ставь. Делов то.

Кэр>Под возращением я имел ввиду то место, где начинает разворачиваться стэк вызовов. Я понимаю отличие императивного и функционального кода


Если понимашь, то должен понимать, что на фукнцию без return-ов можно смотреть как на одно большое выражение. А выражение более предсказуемо. Его проще читать, так как знаешь, что логика у него вычислительная, а не императивная.
... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[4]: Функциональное программирование в Nemerle
От: VladD2 Российская Империя www.nemerle.org
Дата: 31.05.07 13:28
Оценка:
Здравствуйте, Кэр, Вы писали:

Кэр>Здравствуйте, VladD2, Вы писали:


VD>>От догм и предрассудков лучше избавляться.


Кэр>Угу, то что ты подписываешь меня на догматическое мышление я уже понял


Почему только тебя? Я сам по началу был немного обескуражен другим стилем записи.

Код типа:
def f(x)
{
  when (x)
    1;
    
    2;
}

я воспринимал как:
int f(bool x)
{
  if (x)
    return 1;
        
  return 2;
}

и первое время входил в ступо когда компилятор выдвавл предупреждение о том, что игнарируется каое-то там значение.

Кэр> В рассуждениях на самом деле не было ни одного отправного пункта — а вот в других языках так поэтому надо делать именно так. Рассуждения начинаются с нуля. Опровергай их тоже с нуля, не вешая на меня ярлыки Вполне допускаю, что могу быть неправ.


В том-то и дело, что не с нуля. Люди которые начинали писать скажем на Лиспе даже не зададут такой вопрос. Просто ты так привык к reurn-ам, что в твоем сознании это единственно правильный выбор и ты уже на подсознательном уровне отвергаешь "странные" варианты.

Со мной была та же фигня. Через неделю практики от этого не остается и следа. А через месяц ты начинаешь задваться вопросом "Зачем я всю жизнь тыкал return-ы там где они на фиг не упали?".

Кстати, в C# 3.0 появятся лямбды — анонимные методы с выводом типов (гы-гы) и тела которых могут быть чистыми выражениями. Так вот в них будут такие же "проблемы". Тоже не будет return-ов и можно будет не указывать типы. Возможно, даже, что тип возвращаемого значения вообще нельзя будет задать явно. Так что привыкать по любому придется. А как привыкнешь, то и вопрос сам собой отпадет.

VD>>Кстати, есть один вопрос:

VD>>
VD>>    | EndOfFile           => return stack.Count == 1
VD>>        ...
VD>>    | EndRound            => check(_ is Token.BeginRound)  // )
VD>>

VD>>А почему в первой строчке return понадобился, а во второй нет?

Кэр>Как раз по тем причинам, что я указывал выше — return обозначает то место, где начнет разворачиваться стэк вызовов функций.


Дык "стек начинает разворачиваться" в обоих случаях. В обоих случаях вычесленное значение будет возвращего из фукнции.

Кстати, скажу по сикрету, что физически никакого стека вызовов и темболее его раскрутки не будет. Дело в том, что эта рекурсия концевая. И компилятор перепишет ее в цикл. Так что не останется ни вызова метода, ни его рекрусивных вызово. В место этого физически будет сгенерирован цикл.

Кэр>Такой return

VD>>
VD>>    | EndRound            => return check(_ is Token.BeginRound)  // )
VD>>

Кэр>лишний. Здесь просто вычисления идут вглубь по стэку вызова.

... << RSDN@Home 1.2.0 alpha rev. 637>>
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.