Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 24.03.14 18:18
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Хм, если так, то это очень плохо.

ARK>По-хорошему, для таких фокусов параметры должны передаваться по значению или быть иммутабельными. Тут у Брайта какой-то адский косяк.

Как раз всё правильно. По всем принципам это как раз классические чистые функции, т.к. все данные передаются в виде параметра (а не ссылками на что-то внешнее изнутри функции). Просто если мы будем передавать в такую чистую функцию неконстантные данные, то никакие подобные оптимизации невозможны. Но это не отменяет чистоту функции. )
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.03.14 18:38
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, gandjustas, Вы писали:


G>>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой? интересует с точки зрения компилятора и потенциальных оптимизаций.


_>Что значит будет чистой или нет? ) Это решает программист, с помощью модификатора pure. А компилятор соответственно или позволяет собрать такой код или нет.


_>Далее, если мы говорим про такой объект, то это собственно по сути ничем не отличается от двух глобальных функций, которым передают в качестве параметра одну и ту же структуру. Ключевое тут "в качестве параметра", так что без проблем можно считать такую функцию чистой.

Это как? Даже если одна из функций потенциально меняет эту структуру? Тогда на какие оптимизации можно рассчитывать?

_>Только вот если передавать этой нашей чистой функции неконстантную функцию (или в случае ООП, вызывая метод неконстантного объекта), то очевидно, что никакие оптимизации типа кэширования или перемещения точки вызова невозможны, т.к. это будут вызовы с потенциально разными аргументами.


G>>Это в принципе в любом языке.


_>Ну ну) А ничего что например в C++ константные данные располагаются вообще в другой памяти? ) Это конечно же если компилятор вообще будет выделять память под них — в большинстве случаев оно может просто в ассемблерном коде оказаться зашиты. )))

Речь идет о константных параметрах и константных функциях.


G>>Не силен в D, покажи пример.


_>В ответ на такой код

_>
_>int data;
_>pure int f(){return data;}
_>
компилятор скажет: "Error: pure nested function 'f' cannot access mutable data 'data'".


А если это написано внутри класса? data является полем (потенциально изменяемым), а f — функцией-членом.

G>>В общем случае получение такой гарантии приводит к решению проблемы останова. Так что в принципе ввести подобное в языки нельзя.

_>И откуда тут взялась проблема остановки? )
См вопрос выше.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.03.14 18:51
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, AlexRK, Вы писали:


ARK>>Хм, если так, то это очень плохо.

ARK>>По-хорошему, для таких фокусов параметры должны передаваться по значению или быть иммутабельными. Тут у Брайта какой-то адский косяк.

_>Как раз всё правильно. По всем принципам это как раз классические чистые функции, т.к. все данные передаются в виде параметра (а не ссылками на что-то внешнее изнутри функции). Просто если мы будем передавать в такую чистую функцию неконстантные данные, то никакие подобные оптимизации невозможны. Но это не отменяет чистоту функции. )


Константность — слабо формализованный термин. Неизменяемость (immutability) — более, стоит употреблять него.

Чистая функция, это функция которая:
1) Детерминирована — то есть при одинаковых входных значениях всегда дает одинаковые входные значения.
2) Не имеет наблюдаемых сайд-эффектов.

Если функция при вычислениях использует изменяемые данные, то она не может быть чистой (даже несмотря на модификаторы типа pure).
Re[57]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 24.03.14 18:57
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Это как? Даже если одна из функций потенциально меняет эту структуру? Тогда на какие оптимизации можно рассчитывать?


Если мы передаём в чистую функцию неконстантную структуру, то ни на какие. Но от этого функция не перестаёт быть чистой. )

G>А если это написано внутри класса? data является полем (потенциально изменяемым), а f — функцией-членом.


Тогда без проблем, т.к. это аналогично чему-то типа "int f(const ref S s){return s.data;}", что очевидно является чистой функцией.

_>>И откуда тут взялась проблема остановки? )

G>См вопрос выше.

И?
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 24.03.14 19:04
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, gandjustas, Вы писали:


G>>Это как? Даже если одна из функций потенциально меняет эту структуру? Тогда на какие оптимизации можно рассчитывать?


_>Если мы передаём в чистую функцию неконстантную структуру, то ни на какие. Но от этого функция не перестаёт быть чистой. )


По факту перестает. Теряется свойство детерминированности.

G>>А если это написано внутри класса? data является полем (потенциально изменяемым), а f — функцией-членом.

_>Тогда без проблем, т.к. это аналогично чему-то типа "int f(const ref S s){return s.data;}", что очевидно является чистой функцией.
Не является, ибо нет гарантии то s никто не поменяет вне функции. Это значит что все оптимизации для чистых фукнций нельзя выполнить. Даже переупорядочить вычисления нельзя.

_>>>И откуда тут взялась проблема остановки? )

G>>См вопрос выше.
_>И?
См ответ выше. Если бы компилятор мог проанализировать что делается в коде вокруг "чистых" функций, то мог бы выполнить оптимизации, а это сводится к проблеме останова.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 24.03.14 21:21
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>Константность — слабо формализованный термин. Неизменяемость (immutability) — более, стоит употреблять него.


Это привычка из плюсов, где только const) А в D действительно есть отдельно const и immutable.

G>Чистая функция, это функция которая:

G>1) Детерминирована — то есть при одинаковых входных значениях всегда дает одинаковые входные значения.
G>2) Не имеет наблюдаемых сайд-эффектов.

Ну да.

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


Это если ссылка на эти данные откуда-то изнутри функции. А если речь идёт о передаваемых в качестве параметров, то никаких проблем.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 24.03.14 21:46
Оценка: :)
Здравствуйте, gandjustas, Вы писали:

G>По факту перестает. Теряется свойство детерминированности.


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

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


Оптимизации можно проводить только в пределах неизменности сущностей, передаваемых в качестве параметров в нашу функцию. И кстати для компилятора не проблема отслеживать эти вещи. Но это всё происходит вне нашей функции и никак не влияет на факт её чистоты. Чистая же она потому, что её результат зависит исключительно от параметров функции.

G>См ответ выше. Если бы компилятор мог проанализировать что делается в коде вокруг "чистых" функций, то мог бы выполнить оптимизации, а это сводится к проблеме останова.


Ничего подобного. Достаточно чтобы в языке можно было задать иммутабельные данные — тогда никаких анализов исполнения алгоритма не требуется и при этом всё получается точно. Хотя теоретически в неком минимальном виде (например для локальных переменных, на которые никто не ссылается) можно пробовать применять подобную оптимизацию и для не иммутабельных данных. Не знаю реализовано ли где-то подобное...
Re[58]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.03.14 01:21
Оценка:
Здравствуйте, alex_public, Вы писали:


_>Если мы передаём в чистую функцию неконстантную структуру, то ни на какие. Но от этого функция не перестаёт быть чистой. )

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

Если у меня чистая функция вызывается дважды на мутабельных данных, я обязан выполнить оба вызова — а ну как состояние поменялось? Причём это не зависит от того, является ли функция чистой.
А вот если мне (компилятору) удастся доказать, что данные между вызовами не изменились, то я могу выполнять агрессивные оптимизации.
Начиная с выноса вызова за цикл.

Компиляторы С++ решают эту проблему при помощи агрессивного инлайнинга — там уже неважно, кто помечен const, а кто нет. После SSA — анализа станет понятно, кто и когда меняется, и каким минимальным кодом можно реализовать заданное наблюдаемое поведение.
К сожалению, этот подход не работает в глобальном масштабе.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 25.03.14 03:42
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Напомню: задача была как раз в оптимизациях, а не в том, чтобы сделать функцию чистой.


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

S>Если у меня чистая функция вызывается дважды на мутабельных данных, я обязан выполнить оба вызова — а ну как состояние поменялось? Причём это не зависит от того, является ли функция чистой.


Конечно. Хотя в определённых простых случая (типа локальных переменных без ссылок) компилятор теоретически без проблем способен отслеживать изменения мутабельных данных. Но я не в курсе реализовано ли что-то подобное в D.

S>А вот если мне (компилятору) удастся доказать, что данные между вызовами не изменились, то я могу выполнять агрессивные оптимизации.

S>Начиная с выноса вызова за цикл.

Ага. И как раз чистые функции вызванные на иммутабельных данных и дают такие гарантии. Причём для этого совсем не требуется вводить обязательную чистоту на весь язык (как в Haskell) — достаточно всего лишь пары модификаторов, как в D.

S>Компиляторы С++ решают эту проблему при помощи агрессивного инлайнинга — там уже неважно, кто помечен const, а кто нет. После SSA — анализа станет понятно, кто и когда меняется, и каким минимальным кодом можно реализовать заданное наблюдаемое поведение.

S>К сожалению, этот подход не работает в глобальном масштабе.

Ну это вообще другая тема, которая в любом случае полезна.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 25.03.14 05:44
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Здравствуйте, gandjustas, Вы писали:


G>>По факту перестает. Теряется свойство детерминированности.


_>Ничего подобного. Вызов нашей чистой функции, потом модифицирующей и потом снова чистой по смыслу является просто двумя вызовами чистой функции с двумя разными аргументами.


И че? Компилятор то все равно ничего оптимизировать не может. Ленивость тоже ввести не получится.

Напомню разговор начался с того, что умеет Хаскель.

G>>См ответ выше. Если бы компилятор мог проанализировать что делается в коде вокруг "чистых" функций, то мог бы выполнить оптимизации, а это сводится к проблеме останова.


_>Ничего подобного. Достаточно чтобы в языке можно было задать иммутабельные данные — тогда никаких анализов исполнения алгоритма не требуется и при этом всё получается точно. Хотя теоретически в неком минимальном виде (например для локальных переменных, на которые никто не ссылается) можно пробовать применять подобную оптимизацию и для не иммутабельных данных. Не знаю реализовано ли где-то подобное...

Имеено об этом я и говорю. На самом деле для оптимизаций достаточно single-owned объектов. То есть внтури функции точно известно что никто другой не поменяет объект (на него ссылки больше нигде нет), в вызывающей функции такая же картина. Это дает широкий простор компилятору.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 25.03.14 05:56
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>>>Но ведь никто не мешает вызвать в другом потоке mutable функцию объекта, так?

DM>>Система типов мешает. Если он в одном потоке immutable, он и в любом другом будет immutable, если не идти на сознательное нарушение и использовать касты.

G>А в какой момент объект становится immutable? Как const в C++? Или на уровне типа задается? Или есть что-то типа механизма "заморозки" ?


При рождении. Фактически, если у нас есть класс А, то А и immutable A — это два разных типа. Создав объект как просто А, его нельзя передать туда, где ждут immutable, и наоборот: можно создать immutable A, он для всех будет immutable, меняющей функции его не передать, мутабельный метод не вызвать.

G>Если ссылку на объект можно скопировать до того как он стал immutable, то гарантий по сути никаких нет.


Нельзя, как следует из вышесказанного.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
От: AlexRK  
Дата: 25.03.14 16:50
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Как раз всё правильно. По всем принципам это как раз классические чистые функции, т.к. все данные передаются в виде параметра (а не ссылками на что-то внешнее изнутри функции). Просто если мы будем передавать в такую чистую функцию неконстантные данные, то никакие подобные оптимизации невозможны. Но это не отменяет чистоту функции. )


Не могу согласиться. Такие псевдо-чистые функции не являются прозрачными по ссылкам — заменить их значениями от своих аргументов нельзя.
Re[59]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.14 06:22
Оценка:
Здравствуйте, alex_public, Вы писали:

_>Как раз всё правильно. По всем принципам это как раз классические чистые функции, т.к. все данные передаются в виде параметра (а не ссылками на что-то внешнее изнутри функции).



Классические чистые функции это вобщем не про данные в виде параметров
Классические чистые функции это

1. детерминизм
2. отсутствие побочных эффектов

При чем оба признака обязательны для чистоты.
(A a) => return a.y;


Отсутствие сторонних эффектов есть, а если А это изменяемое состояние, то детерминизма нет. Следовательно, функция не является чистой.

>Просто если мы будем передавать в такую чистую функцию неконстантные данные, то никакие подобные оптимизации невозможны. Но это не отменяет чистоту функции. )


Итого — у тебя снова своя собственная теория.
Re[56]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.14 06:26
Оценка:
Здравствуйте, alex_public, Вы писали:

G>>Есть объект, одна функция чистая, то есть не меняет состояние объекта, но читает его. Вторая функция меняет. Первая функция не будет чистой? интересует с точки зрения компилятора и потенциальных оптимизаций.


_>Что значит будет чистой или нет? ) Это решает программист, с помощью модификатора pure. А компилятор соответственно или позволяет собрать такой код или нет.


Похоже, понятно, почему топик тянется так долго
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 26.03.14 14:28
Оценка:
Здравствуйте, gandjustas, Вы писали:

G>И че? Компилятор то все равно ничего оптимизировать не может. Ленивость тоже ввести не получится.


G>Напомню разговор начался с того, что умеет Хаскель.


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

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

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

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

G>Имеено об этом я и говорю. На самом деле для оптимизаций достаточно single-owned объектов. То есть внтури функции точно известно что никто другой не поменяет объект (на него ссылки больше нигде нет), в вызывающей функции такая же картина. Это дает широкий простор компилятору.


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

Хотя в тех же плюсах с их агрессивным инлайном, шаблонами и фишками типа lto подобная оптимизация действительно может творить чудеса и без всяких спец. флагов. )))
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 26.03.14 14:39
Оценка:
Здравствуйте, AlexRK, Вы писали:

ARK>Не могу согласиться. Такие псевдо-чистые функции не являются прозрачными по ссылкам — заменить их значениями от своих аргументов нельзя.


А в чём проблема то? Если они у нас иммутабельные, то система типов всё нормально проконтролирует. А если нет, то просто не выполняем подобную оптимизацию (хотя на самом деле и тут местами можно, но это уже другой вопрос), т.к. потенциально там могут быть разные значения.
Re[60]: Есть ли вещи, которые вы прницпиально не понимаете...
От: alex_public  
Дата: 26.03.14 14:44
Оценка: -1
Здравствуйте, Ikemefula, Вы писали:

I>Классические чистые функции это вобщем не про данные в виде параметров

I>Классические чистые функции это

I>1. детерминизм

I>2. отсутствие побочных эффектов

I>При чем оба признака обязательны для чистоты.

I>
I>(A a) => return a.y;
I>


I>Отсутствие сторонних эффектов есть, а если А это изменяемое состояние, то детерминизма нет. Следовательно, функция не является чистой.


Я правильно понимаю, что с твоей точки зрения такая int f(int x) {return x;} функция тоже не является чистой?
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.14 15:43
Оценка:
Здравствуйте, alex_public, Вы писали:

I>>Отсутствие сторонних эффектов есть, а если А это изменяемое состояние, то детерминизма нет. Следовательно, функция не является чистой.


_>Я правильно понимаю, что с твоей точки зрения такая int f(int x) {return x;} функция тоже не является чистой?


Я выделил, что бы понятнее было. С моей точки зрения int не может быть изменяемым состоянием. А вот int* может

Вобщем кривляйся дальше.
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.03.14 15:56
Оценка:
Здравствуйте, alex_public, Вы писали:

_>А в чём проблема то? Если они у нас иммутабельные, то система типов всё нормально проконтролирует. А если нет, то просто не выполняем подобную оптимизацию (хотя на самом деле и тут местами можно, но это уже другой вопрос), т.к. потенциально там могут быть разные значения.


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

Иммутабельность позволяет реализовать детерминизм. Без иммутабельности его нет и быть не может.

Вот есть у нас обычная функция memoize, возвращает кеширующую функцию для своего параметра.
Теперь фокус
var f = (A a) => return a.x; // по твоей логике это чистая функция
var f1 = memoize(f);
var a = new A();

f1(a); //вычисляем
f1(a); //возвращаем кешированое значение
a.mutate(); // модифицируем
f1(a); // ОПАНЬКИ ! получаем отстой в силу отсутствия детерминизма


Парадокс — чистая функция не может быть мемоизирована.
Отсюда ясно, почему нужен детерминизм.

Как вариант, можешь внести в свою теорию новый термин — абсолютно чистые функции
Re[61]: Есть ли вещи, которые вы прницпиально не понимаете...
От: AlexRK  
Дата: 26.03.14 16:26
Оценка:
Здравствуйте, alex_public, Вы писали:

_>А в чём проблема то? Если они у нас иммутабельные, то система типов всё нормально проконтролирует. А если нет, то просто не выполняем подобную оптимизацию (хотя на самом деле и тут местами можно, но это уже другой вопрос), т.к. потенциально там могут быть разные значения.


Такие функции чистыми называть нельзя, ИМХО. Вопрос терминологии — что понимать под "чистыми функциями". Я всегда считал это эквивалентностью ссылочной прозрачности и для меня стало большой неожиданностью, что Брайт сделал такую кривизну в весьма грамотно спроектированном языке.

Что касается оптимизаций, то это отдельный вопрос. Оптимизируются ведь не только чистые функции. Ну да, модификатор "pure" плюс иммутабельные параметры — и прозрачность по ссылкам гарантирована. Но я просто не понимаю, НАФИГА вообще надо было давать возможность изменять в чистой функции мутабельные параметры?
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.