Re[31]: Мифический Haskell
От: Klapaucius  
Дата: 09.03.12 14:22
Оценка:
Здравствуйте, samius, Вы писали:

S>Если на практике происходит специализация, то это не ПП, а ad-hoc.


Мы, вроде бы, сговорились на том, что особенности реализации не учитываются. Уже передумали?

S>(Потенциальная) — это значит что мне не потребуется специализировать для работы с еще одним любым типом.


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

S>А если мне в программе нужно всего 10 типов и не нужно бесконечность, то это не мои проблемы.


Правильно. А можно написать программу которой нужно не 10, а потенциально бесконечное число типов, как в обсуждаемых примерах — и привет, не компилируется!

S>А вы умудряетесь игнорировать то что определение ПП не требует бесконечности.


Я вообще не утверждал, что требует. Я утверждал, что бесконечность следует из определения ПП.

S>Но не в C#.


И в C#. Нет там никакого применения в рантайме. Вот применение параметрического типа в рантайме на C#:
typeof(Foo<>).MakeGenericType(new[]{typeof(Bar)})

А вот в комайл-тайм:
Foo<Bar>


K>>Но почему?

S>Потому что кайндов в дотнете нет.

Спрашиваю: почему нет? Ответ — "потому что потому". Потрясающе просто!

S>Про бесконечное кол-во типов мы уже обсудили что оно не требуется определением.


Да, я вам несколько раз написал, что это следствие определения, но вы это просто проигнорировали. "Обсудили", конечно.

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


Т.е. предмет обсуждения значения не имеет. Отлично!

S>Тем более, что она не требуется и не следует.


Т.е. вы в состоянии дать верхнюю оценку числа "любых типов"? И верхнюю оценку числа типов в описываемых программах?
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[32]: Мифический Haskell
От: samius Япония http://sams-tricks.blogspot.com
Дата: 09.03.12 16:16
Оценка:
Здравствуйте, Klapaucius, Вы писали:

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


S>>Если на практике происходит специализация, то это не ПП, а ad-hoc.


K>Мы, вроде бы, сговорились на том, что особенности реализации не учитываются. Уже передумали?

Я лишь указал на то, что специализация (или выбор реализации в зависимости от типа) называется ad-hoc.

S>>(Потенциальная) — это значит что мне не потребуется специализировать для работы с еще одним любым типом.


K>Нет, не значит. "мне не потребуется специализировать для работы с еще одним любым типом" — это означает "конечное число".

Не означает, иначе вы его должны суметь оценить.

S>>А если мне в программе нужно всего 10 типов и не нужно бесконечность, то это не мои проблемы.


K>Правильно. А можно написать программу которой нужно не 10, а потенциально бесконечное число типов, как в обсуждаемых примерах — и привет, не компилируется!

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

S>>А вы умудряетесь игнорировать то что определение ПП не требует бесконечности.


K>Я вообще не утверждал, что требует. Я утверждал, что бесконечность следует из определения ПП.

А я утверждал что не следует. Как быть?

S>>Но не в C#.


K>И в C#. Нет там никакого применения в рантайме. Вот применение параметрического типа в рантайме на C#:

K>
K>typeof(Foo<>).MakeGenericType(new[]{typeof(Bar)})
K>

И ? Это действительно применение параметрического типа в рантайме. Противоречит тому что нет никакого применения в рантайме.
K>А вот в комайл-тайм:
K>
K>Foo<Bar>
K>

А вот это в какой тайм?
    class X<T>
    {
        readonly X<Tuple<T>> _next;

        public X(T v1, int count)
        {
            if (count > 0)
                _next = new X<Tuple<T>>(Tuple.Create(v1), count - 1);
        }
        public Type GetTailType()
        {
            return _next == null
               ? GetType()
               : _next.GetTailType();
        }
    }

    class Program
    {
        static void Main()
        {
            int count = int.Parse(Console.ReadLine());

            var x = new X<int>(1, count);
            Console.WriteLine(x.GetTailType());
        }
    }


K>>>Но почему?

S>>Потому что кайндов в дотнете нет.

K>Спрашиваю: почему нет? Ответ — "потому что потому". Потрясающе просто!

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

S>>Про бесконечное кол-во типов мы уже обсудили что оно не требуется определением.


K>Да, я вам несколько раз написал, что это следствие определения, но вы это просто проигнорировали. "Обсудили", конечно.

А я вам несколько раз написал что 1) не следствие, что 2) бесконечность можно наблюдать на множестве программ.

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


K>Т.е. предмет обсуждения значения не имеет. Отлично!

Вы обсуждаете полиморфизм или что? Если полиморфизм, то это фича языка, а не программы. Смотрим в определение. Если вы обсуждаете что-то другое, то я пойду.

S>>Тем более, что она не требуется и не следует.

K>Т.е. вы в состоянии дать верхнюю оценку числа "любых типов"? И верхнюю оценку числа типов в описываемых программах?
К чему оценка? Доступное мне определение говорит лишь о возможности идентичной обработки значений вне зависимости от типа. Определение в TAPL не сильно от него отличается.
Re[58]: Мифический Haskell
От: samius Япония http://sams-tricks.blogspot.com
Дата: 09.03.12 17:02
Оценка:
Здравствуйте, VoidEx, Вы писали:

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


S>>Выделение памяти у нас превартилось в семантически обозримый side effect? С каких пор?


VE>Ты спрашиваешь, как программе определить, выделяется ли память?

Я спрашиваю не об этом. Если угодно, я спрашиваю о том, какой смысл говорить о чистоте чего-либо в рамках системы, где выделение памяти считается обозримым сайд-эффектом?
Можно, конечно, считать что вся доступная память передается неявным параметром в функцию, и неявным результатом возвращается, но такой подход оправдывает любые деструктивные изменения, а не только выделение. Так что, я считаю, что семантически-обозримое выделение памяти — это выход за рамки беседы.

VE>Математики не потому составляют чёткие определения, что они глупые, а как раз наоборот, потому что понимают, что дьявол в деталях.

VE>Может, в определение напишем "side-effect — то, что неглупый человек считает side-effect'ом"?
Судя по всему, сейчас там так и написано. Во всяком случае каждый второй норовит его подправить своим определением.

S>>Ты путаешь referential transparency с детерминированностью. Если есть гарантия что результат будет тот же и не будет зависеть от ввода через I/O или скрытых состояний, то это есть детерминированность, а не ссылочная прозрачность. Детерминированной функции портить мир можно. Ссылочно прозрачному выражению — нельзя.


VE>Не путаю. Она и не портит, мир живёт себе как жил. Ничем не хуже, чем с выделенной памятью.

По поводу выделения памяти ответил выше.

VE>>>Что мешает использовать файл как оперативную память?

S>>Ничего. Только детерминированности не будет, т.к. общаешься с файлом через I/O. А нет детерминированности — нет и прозрачности.

VE>Почему это не будет? На n! при сотне вызовов возвращает верное значение? Да. Так что ж тогда?

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

VE>>>Нет, ты со мной не согласен. Я задал кучу вопросов, на которые такое определение ответить не в состоянии.

S>>Мне казалось, что я на все ответил, опираясь на определение.

VE>Это тебе казалось, а я ответов не получил. Видимо потому, что ты тоже опираешься на "интуицию умных людей", а у меня такое понятие отсутствует, мне нужно чёткое определение, чтоб определение было полезным даже для дурака вроде меня. Эдак можно начать опираться на клятвы матерью и своим здоровьем.

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

VE>А что если работает рантайм, но программа имеет возможность косвенно следить за её работой? Ну, как с памятью.

По поводу памяти ответил выше. Только я не понимаю, к чему тебе слежение за памятью или голубями? Начинай следить сразу за регистрами CPU. Так проще. Чистота сразу превращается в миф и теряет практическую актуальность.

VE>Или обратный эффект. Что, если я могу рантайм расширять? Ну вот например ввёл доставки голубем, и с т.з. языка это считается runtime extension и даёт те же гарантии, что и работа с памятью. А дальше компилятор на основе метаданных выбирает реализацию сам — то ли память, то ли голуби.

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

VE>Я не думаю, что это такой уж надуманный пример, вон взять Nemerle 2, который будет как бы инструмент для создания языков. Там может понадобиться нечто подобное. В базовом языке (который ещё и грязный) у нас будет всё превращаться в голубиную почту, но в исходном чистом ДСЛ это будет обычное вычисление.

Так обычно и бывает с чистыми языками, N2 тут ничего не открыл.

S>>Посылка данных в сеть — это output через I/O девайс. А выделение памяти не является семантически обозримым сайд эффектом.


VE>В чём разница? Увидеть можно и то, и другое. Изнутри программы.

Разница в том, что одно считается вводом/выводом, а другое — нет.

S>>Что по поводу insignificant сайд эффекта — так это представь вычисление факториала со внешним мутабельным аккумулятором. Такая функция будет формально impure, но включенная в выражение таким образом, что бы изменения не распространялись за пределы выражения, ее побочный эффект будет незначителен для того, кто ожидает результат выражения.


VE>Можно ещё представить себе вычисление огроменного списка. Формально он pure, но запусти их 3 сразу и памяти не хватит. И это оказывается очень так значительно для того, кто ожидает результат вычисления. Но это лирика.

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

VE>А можно опять вернуться к голубиной почте, а лучше к temporary файл. Можно создать temporary file (имя которому генерирует ОСь, и имя которого неизвестно никому, только handle открывшему процессу), поиспользовать для вычислений и закрыть (после чего он может удалиться, а может и нет, зависит от флагов открытия). Такая функция чиста? Вроде ввод-вывод есть, но побочный эффект необнаруживаем.

Определение требует считать такую функцию грязной, ибо ввод/вывод. Но ты можешь считать ее достаточно чистой для каких-то своих соображений. Можешь даже убедить в этом haskell через unsafePerformIO. Только не жалуйся, что для выполнения чистой функции потребовались права.
Re[33]: Мифический Haskell
От: Klapaucius  
Дата: 09.03.12 19:45
Оценка:
Здравствуйте, samius, Вы писали:

K>>Нет, не значит. "мне не потребуется специализировать для работы с еще одним любым типом" — это означает "конечное число".

S>Не означает, иначе вы его должны суметь оценить.

Я тут уже указывал способ определить не верхнюю границу, а точное число типов для тизируемого кода на C++

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


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

S>А я утверждал что не следует. Как быть?


Из определения парам. полиморфизма следует, что у нас есть, по крайней мере, один мономорфный тип () и один полиморфный forall a. Succ a с этим вы согласны? Тогда из любого заданного типа a мы можем сконструировать еще один применением Succ. Таким образом, число типов сверху не ограничено. Q.E.D
Ровно это следствие в приведенных тут программах на языках с ПП и используется.

S>>>Но не в C#.


S>Это действительно применение параметрического типа в рантайме. Противоречит тому что нет никакого применения в рантайме.


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

S>А вот это в какой тайм?

S>
S>    class X<T>
S>    {
S>        readonly X<Tuple<T>> _next;

S>        public X(T v1, int count)
S>        {
S>            if (count > 0)
S>                _next = new X<Tuple<T>>(Tuple.Create(v1), count - 1);
S>        }
S>        public Type GetTailType()
S>        {
S>            return _next == null
S>               ? GetType()
S>               : _next.GetTailType();
S>        }
S>    }

S>    class Program
S>    {
S>        static void Main()
S>        {
S>            int count = int.Parse(Console.ReadLine());

S>            var x = new X<int>(1, count);
S>            Console.WriteLine(x.GetTailType());
S>        }
S>    }
S>


Компайл-тайм, разумеется.

S>Так вы мне так же и отвечаете. Не хотелось бы начинать еще одну тему.

S>"потому что потому" получается после заглядывания в определение кайнда. Может вы под кайндом понимаете что-то другое, но тогда следовало дать свое определение.

Мое определение, разумеется, не отличается от википедийного. Не понял, как вы из него вывели, что в .net нет кайндов? В примерах из статьи, правда, есть фактические ошибки. Например, кайнд (->) в хаскеле не * -> * -> *, а ?? -> ? -> *. Прямые аналоги хаскельных кайндов # * в .net это struct и class, и полиморфизм в .net работает, в отличие от хаскеля, для кайнда, который в хаскеле называется ??. Домашнее задание — к типам каких кайндов можно применять оператор typeof в C#?

S>А я вам несколько раз написал что 1) не следствие, что 2) бесконечность можно наблюдать на множестве программ.


См. доказательство выше.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[59]: Мифический Haskell
От: VoidEx  
Дата: 11.03.12 11:35
Оценка:
Здравствуйте, samius, Вы писали:

S>Можно, конечно, считать что вся доступная память передается неявным параметром в функцию, и неявным результатом возвращается, но такой подход оправдывает любые деструктивные изменения, а не только выделение. Так что, я считаю, что семантически-обозримое выделение памяти — это выход за рамки беседы.


Неявным нельзя, явным — пожалуйста.
foo :: Ptr Int -> Ptr Int
очень явно отличается от
foo :: Memory -> Ptr Int -> (Ptr Int, Memory)
Вторая — чистая. Вы не можете вычислить две foo, кроме как последовательно их соединив, и в этом смысле они referential transparent.
Для иллюстрации вы можете имплементировать Ptr как Int, а Memory как [Byte].

S>Определение детерминированности гласит что результат кроме гарантированного повтора на тех же арргументах, не должен зависеть от ввода. Чтение файла — это ввод. Надеюсь, что этим самым мы закрываем тему о детерминированности чтения из файла.


Не закроем. Фукнция создаёт файл с уникальным доступом, пишет, читает, в конце возвращает результат. Результат будет неизменен, хоть 100 раз вызови.
По поводу памяти, видел программу artmoney? Находишь адрес памяти, отвечающий за кол-во жизней в игре, ставишь 100. Ну и кто же более детерминирован тут, файл или память?

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


Именно. Поэтому это определение смысла не имеет.

S>По поводу памяти ответил выше. Только я не понимаю, к чему тебе слежение за памятью или голубями? Начинай следить сразу за регистрами CPU. Так проще. Чистота сразу превращается в миф и теряет практическую актуальность.


Как раз referential transparency от этого никуда не девается, а про чистоту я уже не раз сказал, что она не имеет смысла.

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


Ну если в самой программе написано "позови Софокла, пусть он второй пергамент порешает", то очень даже имеет. Но результат всё равно детерминирован.

VE>>В чём разница? Увидеть можно и то, и другое. Изнутри программы.

S>Разница в том, что одно считается вводом/выводом, а другое — нет.

Одно является I/O потому, что оно считается I/O, а другое нет — потому что нет. Весьма полезное определение.

S>Определение требует считать такую функцию грязной, ибо ввод/вывод. Но ты можешь считать ее достаточно чистой для каких-то своих соображений. Можешь даже убедить в этом haskell через unsafePerformIO. Только не жалуйся, что для выполнения чистой функции потребовались права (_|_).


Ты можешь считать достаточно чистой функцию вычисления суммы списка чисел. Можешь даже убедить в этом меня. Только не жалуйся, что для выполнения чистой функции не хватило памяти (_|_).
Re[34]: Мифический Haskell
От: samius Япония http://sams-tricks.blogspot.com
Дата: 12.03.12 07:24
Оценка:
Здравствуйте, Klapaucius, Вы писали:

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


K>>>Нет, не значит. "мне не потребуется специализировать для работы с еще одним любым типом" — это означает "конечное число".

S>>Не означает, иначе вы его должны суметь оценить.

K>Я тут уже указывал способ определить не верхнюю границу, а точное число типов для тизируемого кода на C++

Остается выяснить, что же мешает превзойти заранее заданное точное число типов.

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


K>Но типизируется-то конкретная программа, а не "множество программ".

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

K>И потенциальная бесконечность следует для одной программы.

Нет.

S>>А я утверждал что не следует. Как быть?


K>Из определения парам. полиморфизма следует, что у нас есть, по крайней мере, один мономорфный тип () и один полиморфный forall a. Succ a с этим вы согласны?

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

K>Тогда из любого заданного типа a мы можем сконструировать еще один применением Succ. Таким образом, число типов сверху не ограничено. Q.E.D

что мешает сконструитьвать еще один тип в программе на C++? Разумеется, явно в коде, или в компайл-тайме.

K>Ровно это следствие в приведенных тут программах на языках с ПП и используется.

Нету такого следствия.

S>>Это действительно применение параметрического типа в рантайме. Противоречит тому что нет никакого применения в рантайме.


K>Речь шла о том, что применение в рантайме для написания обсуждаемого кода не требуется.

Если обсуждаются примеры из http://migmit.livejournal.com/32688.html, то С# там их применяет в рантайме.

S>>А вот это в какой тайм?

S>>
S>>            int count = int.Parse(Console.ReadLine());

S>>            var x = new X<int>(1, count);
S>>


K>Компайл-тайм, разумеется.

Тогда вопрос. Откуда C# в компайл тайм знает что надо применить как минимум 1000 типов? Для 1000 код работает, мог бы работать и для большего числа, если бы не StackOverflow.

S>>"потому что потому" получается после заглядывания в определение кайнда. Может вы под кайндом понимаете что-то другое, но тогда следовало дать свое определение.


K>Мое определение, разумеется, не отличается от википедийного. Не понял, как вы из него вывели, что в .net нет кайндов? В примерах из статьи, правда, есть фактические ошибки. Например, кайнд (->) в хаскеле не * -> * -> *, а ?? -> ? -> *. Прямые аналоги хаскельных кайндов # * в .net это struct и class, и полиморфизм в .net работает, в отличие от хаскеля, для кайнда, который в хаскеле называется ??. Домашнее задание — к типам каких кайндов можно применять оператор typeof в C#?

В случае с кайндами — виноват, признаю свою ошибку.
Д.З. Если я правильно все понял, то typeof разрешен для
#
*
(?,...)->? -- unbounded type name

В последнем случае — подразумевается то, что typeof(Dictionary<,>) можно, а typeof(Dictionary<int, >) нельзя, т.е. никаких частичных применений.
А так же можно для указателей (но не ссылок 'out/ref'), которые я не знаю как обозначить в нотации кайндов хаскеля;
и, конечно, Void.

Может быть еще для чего-то можно.

S>>А я вам несколько раз написал что 1) не следствие, что 2) бесконечность можно наблюдать на множестве программ.


K>См. доказательство выше.

Re[60]: Мифический Haskell
От: samius Япония http://sams-tricks.blogspot.com
Дата: 12.03.12 10:16
Оценка:
Здравствуйте, VoidEx, Вы писали:

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


S>>Можно, конечно, считать что вся доступная память передается неявным параметром в функцию, и неявным результатом возвращается, но такой подход оправдывает любые деструктивные изменения, а не только выделение. Так что, я считаю, что семантически-обозримое выделение памяти — это выход за рамки беседы.


VE>foo :: Memory -> Ptr Int -> (Ptr Int, Memory)

VE>Вторая — чистая. Вы не можете вычислить две foo, кроме как последовательно их соединив, и в этом смысле они referential transparent.
VE>Для иллюстрации вы можете имплементировать Ptr как Int, а Memory как [Byte].

Вот что в этом аспекте интересно, а почему в хаскеле любую функцию (например, конкретно map) не оформили в виде монады Memory a?

S>>Определение детерминированности гласит что результат кроме гарантированного повтора на тех же арргументах, не должен зависеть от ввода. Чтение файла — это ввод. Надеюсь, что этим самым мы закрываем тему о детерминированности чтения из файла.


VE>Не закроем. Фукнция создаёт файл с уникальным доступом, пишет, читает, в конце возвращает результат. Результат будет неизменен, хоть 100 раз вызови.

А ввод? Детерминированность это не только гарантия повторения результата. Уже устал повторять.
VE>По поводу памяти, видел программу artmoney? Находишь адрес памяти, отвечающий за кол-во жизней в игре, ставишь 100. Ну и кто же более детерминирован тут, файл или память?
Мне непонятно что значит "более детерминирован". Результат, завязанный на работу с файлом недетерминирован по определению. С памятью — зависит от остального.

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


VE>Именно. Поэтому это определение смысла не имеет.

А какой смысл в хаскеле делать вид что его функции чисты? Или он как-то с памятью по-особому работает?

S>>По поводу памяти ответил выше. Только я не понимаю, к чему тебе слежение за памятью или голубями? Начинай следить сразу за регистрами CPU. Так проще. Чистота сразу превращается в миф и теряет практическую актуальность.


VE>Как раз referential transparency от этого никуда не девается, а про чистоту я уже не раз сказал, что она не имеет смысла.

referential transparency определяется через те же эффекты, что и чистота. Непонятно, что вдруг чистота куда-то девается, а referential transparency, определенная на той же детерминированности — нет.

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


VE>Ну если в самой программе написано "позови Софокла, пусть он второй пергамент порешает", то очень даже имеет. Но результат всё равно детерминирован.

"позови Софокла, пусть он порешает" — не ввод вывод. А вот "спроси Софокла, чему будет равен результат" — ввод вывод.

VE>>>В чём разница? Увидеть можно и то, и другое. Изнутри программы.

S>>Разница в том, что одно считается вводом/выводом, а другое — нет.

VE>Одно является I/O потому, что оно считается I/O, а другое нет — потому что нет. Весьма полезное определение.

Оно по крайней мере допускает наличие чистых функций в хаскеле (кроме действий). Твои же определения — наоборот, говорят что лишь действия IO a чисты (ну и может быть еще что-то, что не оперирует санками).

VE>Ты можешь считать достаточно чистой функцию вычисления суммы списка чисел. Можешь даже убедить в этом меня. Только не жалуйся, что для выполнения чистой функции не хватило памяти (_|_).

Дык это нормально. Чистой функции никто не запрещает жрать память. Портить левую — нельзя. А жрать — сколько влезет.
Re[61]: Мифический Haskell
От: VoidEx  
Дата: 12.03.12 11:45
Оценка:
Здравствуйте, samius, Вы писали:

VE>>foo :: Memory -> Ptr Int -> (Ptr Int, Memory)

VE>>Вторая — чистая. Вы не можете вычислить две foo, кроме как последовательно их соединив, и в этом смысле они referential transparent.
VE>>Для иллюстрации вы можете имплементировать Ptr как Int, а Memory как [Byte].

S>Вот что в этом аспекте интересно, а почему в хаскеле любую функцию (например, конкретно map) не оформили в виде монады Memory a?


Потому же, почему и runST не надо оформлять в виде монады IO — referential transparency.
Потому же, почему и withTemporaryFile не нужно оформлять в виде монады IO — referential transparency.

Приведённая же функция foo с деструктивным присваиванием — в общем случае грязная.

Если от withTemporaryFile вам нужен именно её "побочный эффект" в виде ввода-вывода, язык должен позволять это указать, тогда это будет IO функция с вводом-выводом и выполняться будет каждый раз.

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

Ситуация чем-то напоминает мне вопрос о том, "исключительная ли ситуация, если openFile не смог открыть файл?"
Файл-то чёрт с ним, но вот parse и tryParse существуют прямо здесь и прямо сейчас. А ещё всякие foo и fooAsync.
Вакханалия какая-то.

VE>>Не закроем. Фукнция создаёт файл с уникальным доступом, пишет, читает, в конце возвращает результат. Результат будет неизменен, хоть 100 раз вызови.

S>А ввод? Детерминированность это не только гарантия повторения результата. Уже устал повторять.

А я устал повторять, что чтение памяти ничем не отличается от чтения файла, кроме того, что одно IO, потому что считается IO, а другое не IO, потому что таковым не считается.

S>Мне непонятно что значит "более детерминирован". Результат, завязанный на работу с файлом недетерминирован по определению. С памятью — зависит от остального.


По определению "недетерминирован, потому что считается таковым". Это не определение, а чушь какая-то.

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


VE>>Именно. Поэтому это определение смысла не имеет.

S>А какой смысл в хаскеле делать вид что его функции чисты? Или он как-то с памятью по-особому работает?

Они referential trasparent. unsafePerformIO видел? Так вот она unsafe (как и unsafeCoerce) потому, что ответственность лежит на программисте.

S>referential transparency определяется через те же эффекты, что и чистота. Непонятно, что вдруг чистота куда-то девается, а referential transparency, определенная на той же детерминированности — нет.


Не через те же.

An expression is said to be referentially transparent if it can be replaced with its value without changing the behavior of a program (in other words, yielding a program that has the same effects and output on the same input).

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

Кстати говоря, вы что, никогда не видели ситуации, как мемоизуют функции с побочными эффектами (в вашем определении)? Получается то же самое. Ну да, ну да, там же этого программист захотел. А в отношении withTemporaryFile мне запрещает этого хотеть википедия?

S>Оно по крайней мере допускает наличие чистых функций в хаскеле (кроме действий). Твои же определения — наоборот, говорят что лишь действия IO a чисты (ну и может быть еще что-то, что не оперирует санками).


Мои определения ничего такого не говорят.

VE>>Ты можешь считать достаточно чистой функцию вычисления суммы списка чисел. Можешь даже убедить в этом меня. Только не жалуйся, что для выполнения чистой функции не хватило памяти (_|_).

S>Дык это нормально. Чистой функции никто не запрещает жрать память. Портить левую — нельзя. А жрать — сколько влезет.

И какую такую левую функцию портит withTemporaryFile, которой не хватило прав?
Re[62]: Мифический Haskell
От: samius Япония http://sams-tricks.blogspot.com
Дата: 13.03.12 03:52
Оценка:
Здравствуйте, VoidEx, Вы писали:

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


VE>>>foo :: Memory -> Ptr Int -> (Ptr Int, Memory)

VE>>>Вторая — чистая. Вы не можете вычислить две foo, кроме как последовательно их соединив, и в этом смысле они referential transparent.
VE>>>Для иллюстрации вы можете имплементировать Ptr как Int, а Memory как [Byte].

S>>Вот что в этом аспекте интересно, а почему в хаскеле любую функцию (например, конкретно map) не оформили в виде монады Memory a?


VE>Потому же, почему и runST не надо оформлять в виде монады IO — referential transparency.

VE>Потому же, почему и withTemporaryFile не нужно оформлять в виде монады IO — referential transparency.
А разве referential transparency не чушь? Она не сохраняет нагрев процессора

VE>Приведённая же функция foo с деструктивным присваиванием — в общем случае грязная.

А что по поводу грязной функции map без деструктивного присваивания?

VE>Если от withTemporaryFile вам нужен именно её "побочный эффект" в виде ввода-вывода, язык должен позволять это указать, тогда это будет IO функция с вводом-выводом и выполняться будет каждый раз.

не знаю, что это

VE>Что именно важно: результат функции (полученный как угодно) или её эффект — определять должен программист.

велкам в С++

VE>Ситуация чем-то напоминает мне вопрос о том, "исключительная ли ситуация, если openFile не смог открыть файл?"

VE>Файл-то чёрт с ним, но вот parse и tryParse существуют прямо здесь и прямо сейчас. А ещё всякие foo и fooAsync.
VE>Вакханалия какая-то.
что за parse и tryParse?

VE>>>Не закроем. Фукнция создаёт файл с уникальным доступом, пишет, читает, в конце возвращает результат. Результат будет неизменен, хоть 100 раз вызови.

S>>А ввод? Детерминированность это не только гарантия повторения результата. Уже устал повторять.

VE>А я устал повторять, что чтение памяти ничем не отличается от чтения файла, кроме того, что одно IO, потому что считается IO, а другое не IO, потому что таковым не считается.

от того что ты устал считаться по-другому не станет.

S>>Мне непонятно что значит "более детерминирован". Результат, завязанный на работу с файлом недетерминирован по определению. С памятью — зависит от остального.


VE>По определению "недетерминирован, потому что считается таковым". Это не определение, а чушь какая-то.

От того что ты называешь определения чушью, других определений не появляется. Предлагаю все-таки ссылаться на какие-то источники, а не на "я так считаю".

S>>А какой смысл в хаскеле делать вид что его функции чисты? Или он как-то с памятью по-особому работает?


VE>Они referential trasparent. unsafePerformIO видел? Так вот она unsafe (как и unsafeCoerce) потому, что ответственность лежит на программисте.

То есть все, кто пишут что хаскель чист — пишут чушь?

S>>referential transparency определяется через те же эффекты, что и чистота. Непонятно, что вдруг чистота куда-то девается, а referential transparency, определенная на той же детерминированности — нет.


VE>Не через те же.


VE>An expression is said to be referentially transparent if it can be replaced with its value without changing the behavior of a program (in other words, yielding a program that has the same effects and output on the same input).


VE>Я настаиваю на том, что если вы считаете идентичными программы, одна из которых выделяет памяти до гигабайта, а другая до мегабайта (потому что в ней что-то там замемоизовали благодаря referential trasparent), то можно считать идентичными и те, одна из которых 3 раза создаёт использует с нуля временный файл, а другая лишь один (потому что можно работу с файлом мемоизовали).

идентичными? Нигде такого не писал. А как же нагрев процессора? Он делает RT чушью

VE>Более того, я считаю, что важность эффекта определяется не википедией, а программистом.

даёшь всё IO без монады IO!

VE>Т.е. конкретно в данном примере я считаю, что первые две программы по эффектам отличаются сильнее, чем вторые две.

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

VE>Кстати говоря, вы что, никогда не видели ситуации, как мемоизуют функции с побочными эффектами (в вашем определении)? Получается то же самое. Ну да, ну да, там же этого программист захотел. А в отношении withTemporaryFile мне запрещает этого хотеть википедия?

хотеть не запрещает

S>>Оно по крайней мере допускает наличие чистых функций в хаскеле (кроме действий). Твои же определения — наоборот, говорят что лишь действия IO a чисты (ну и может быть еще что-то, что не оперирует санками).


VE>Мои определения ничего такого не говорят.

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

S>>Дык это нормально. Чистой функции никто не запрещает жрать память. Портить левую — нельзя. А жрать — сколько влезет.


VE>И какую такую левую функцию портит withTemporaryFile, которой не хватило прав?

я ничего не утверждал о порче функций. Я написал что выделять память чистой функции не запрещено.
Re[63]: Мифический Haskell
От: VoidEx  
Дата: 13.03.12 15:50
Оценка:
Здравствуйте, samius, Вы писали:

VE>>Потому же, почему и runST не надо оформлять в виде монады IO — referential transparency.

VE>>Потому же, почему и withTemporaryFile не нужно оформлять в виде монады IO — referential transparency.
S>А разве referential transparency не чушь? Она не сохраняет нагрев процессора

И не должна. RT позволяет заменить вычисление значением без смены поведения программы. Поведение программы определяет программист.
Т.е. если должна была греть процессор и перестала — то вызов функции, греющую процессор, заменить на значение нельзя. Если пофиг, греет или нет, то можно менять, и функция RT. Это относительное понятие, а не абсолютное.

S>А что по поводу грязной функции map без деструктивного присваивания?

Какой такой грязной map?

VE>>Если от withTemporaryFile вам нужен именно её "побочный эффект" в виде ввода-вывода, язык должен позволять это указать, тогда это будет IO функция с вводом-выводом и выполняться будет каждый раз.

S>не знаю, что это

withTemporaryFile :: (Handle -> IO r) -> r


Если вы используете её так же, как runST, она вполне себе RT. Если вам необходимо именно создание временного файла, то необходим аналог stToIO.
Что такое runST знаете?

VE>>Что именно важно: результат функции (полученный как угодно) или её эффект — определять должен программист.

S>велкам в С++

Это такой язык, где гипотетически можно сделать всё (и некоторые даже воротят монстров), но на деле никто ничего такого не использует, потому что без слёз не взглянешь? Спасибо, знаком.

VE>>Ситуация чем-то напоминает мне вопрос о том, "исключительная ли ситуация, если openFile не смог открыть файл?"

VE>>Файл-то чёрт с ним, но вот parse и tryParse существуют прямо здесь и прямо сейчас. А ещё всякие foo и fooAsync.
VE>>Вакханалия какая-то.
S>что за parse и tryParse?

System.Int.parse и System.Int.tryParse (.Net)

VE>>По определению "недетерминирован, потому что считается таковым". Это не определение, а чушь какая-то.

S>От того что ты называешь определения чушью, других определений не появляется. Предлагаю все-таки ссылаться на какие-то источники, а не на "я так считаю".

Можно конечно за абсолют принять википедию и годами всех убеждать, что она верна, а думать на эту тему — время терять, а можно таки самому думать над вопросом. Глядишь, и определение в вики исправят.

S>>>А какой смысл в хаскеле делать вид что его функции чисты? Или он как-то с памятью по-особому работает?


VE>>Они referential trasparent. unsafePerformIO видел? Так вот она unsafe (как и unsafeCoerce) потому, что ответственность лежит на программисте.

S>То есть все, кто пишут что хаскель чист — пишут чушь?

Я тут раз десять сказал, что понятие "чистый" бесполезное, а ты меня спрашиваешь, чистый ли Хаскель. Ну, с т.з. википедии чистый, но меня это не волнует.

VE>>Я настаиваю на том, что если вы считаете идентичными программы, одна из которых выделяет памяти до гигабайта, а другая до мегабайта (потому что в ней что-то там замемоизовали благодаря referential trasparent), то можно считать идентичными и те, одна из которых 3 раза создаёт использует с нуля временный файл, а другая лишь один (потому что можно работу с файлом мемоизовали).

S>идентичными? Нигде такого не писал. А как же нагрев процессора? Он делает RT чушью

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

VE>>Более того, я считаю, что важность эффекта определяется не википедией, а программистом.

S>даёшь всё IO без монады IO!

Не всё, а только то, которое является лишь побочным продуктом и не влияет на результат. С putStrLn это, очевидно, не так. putStrLn — ввод-вывод.
withNewIORef (withNewIORef :: a -> (IORef a -> IO b) -> b — не ввод-вывод).

VE>>Кстати говоря, вы что, никогда не видели ситуации, как мемоизуют функции с побочными эффектами (в вашем определении)? Получается то же самое. Ну да, ну да, там же этого программист захотел. А в отношении withTemporaryFile мне запрещает этого хотеть википедия?

S>хотеть не запрещает

Ок, пойдём дальше. Вот пишите вы себе на C++ мемоизатор. И что, поведение программы меняется? Ну т.е. вроде бы что-то меняется, как если одну сортировку на другую поменять, но вот поведение — не меняется. Так как время — не заложено в поведении.

VE>>Мои определения ничего такого не говорят.

S>Мне показалось что они указывают на то что выделение памяти есть семантически обозримый побочный эффект.

А также на то, что является ли это поведением или просто implementation defined (т.е. программе в целом насрать на это), так сказать, определяет программист.

S>>>Дык это нормально. Чистой функции никто не запрещает жрать память. Портить левую — нельзя. А жрать — сколько влезет.


VE>>И какую такую левую функцию портит withTemporaryFile, которой не хватило прав?

S>я ничего не утверждал о порче функций. Я написал что выделять память чистой функции не запрещено.

Не запрещено Абсолютом.

Вот эту фразу поясните:

Дык это нормально. Чистой функции никто не запрещает жрать память. Портить левую — нельзя. А жрать — сколько влезет.

Кто чего портит у withTemporaryFile?
Re[63]: Мифический Haskell
От: VoidEx  
Дата: 13.03.12 16:31
Оценка:
Здравствуйте, samius, Вы писали:

По поводу Haskell вы мне лучше скажите по вашим определениям, почему interact принимает чистую функцию, а newIORef возвращает IO (IORef a)?
Re[64]: Мифический Haskell
От: samius Япония http://sams-tricks.blogspot.com
Дата: 16.03.12 18:51
Оценка:
Здравствуйте, VoidEx, Вы писали:

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


VE>>>Потому же, почему и runST не надо оформлять в виде монады IO — referential transparency.

VE>>>Потому же, почему и withTemporaryFile не нужно оформлять в виде монады IO — referential transparency.
S>>А разве referential transparency не чушь? Она не сохраняет нагрев процессора

VE>И не должна. RT позволяет заменить вычисление значением без смены поведения программы. Поведение программы определяет программист.

"(in other words, yielding a program that has the same effects and output on the same input)"

VE>Т.е. если должна была греть процессор и перестала — то вызов функции, греющую процессор, заменить на значение нельзя. Если пофиг, греет или нет, то можно менять, и функция RT. Это относительное понятие, а не абсолютное.

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

S>>А что по поводу грязной функции map без деструктивного присваивания?

VE>Какой такой грязной map?
Тот самый map, который возвращает результат, выделяя память под него. Ты ведь предложил считать выделение памяти обозримым побочным эффектом, вот потому map стал грязным в тот же час.

VE>>>Если от withTemporaryFile вам нужен именно её "побочный эффект" в виде ввода-вывода, язык должен позволять это указать, тогда это будет IO функция с вводом-выводом и выполняться будет каждый раз.

S>>не знаю, что это

VE>
VE>withTemporaryFile :: (Handle -> IO r) -> r
VE>

Как я понимаю, такая сигнатура не мешает нагадить не только в этот файл, а вообще везде где взбредет.

VE>Если вы используете её так же, как runST, она вполне себе RT. Если вам необходимо именно создание временного файла, то необходим аналог stToIO.

VE>Что такое runST знаете?
Еще нет. Но во всяком случае, об этом есть что почитать. А по поводу withTemporaryFile гугл молчит.

S>>что за parse и tryParse?


VE>System.Int.parse и System.Int.tryParse (.Net)

Не признал. Не тот регистр, да и типов System.Int в дотнете нет. Теперь понял, о чем речь. Согласен, не лучшее решение. Но когда не знаешь, как бывает по-другому, претензий не возникает, хотя чувство дискомфорта присутствует.

VE>Можно конечно за абсолют принять википедию и годами всех убеждать, что она верна, а думать на эту тему — время терять, а можно таки самому думать над вопросом. Глядишь, и определение в вики исправят.

Не вижу повода для его исправления. А, главное, не понятно, какое определение лучше и чем.

S>>То есть все, кто пишут что хаскель чист — пишут чушь?


VE>Я тут раз десять сказал, что понятие "чистый" бесполезное, а ты меня спрашиваешь, чистый ли Хаскель. Ну, с т.з. википедии чистый, но меня это не волнует.

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

VE>>>Я настаиваю на том, что если вы считаете идентичными программы, одна из которых выделяет памяти до гигабайта, а другая до мегабайта (потому что в ней что-то там замемоизовали благодаря referential trasparent), то можно считать идентичными и те, одна из которых 3 раза создаёт использует с нуля временный файл, а другая лишь один (потому что можно работу с файлом мемоизовали).

S>>идентичными? Нигде такого не писал. А как же нагрев процессора? Он делает RT чушью

VE>Поведение программы — это не её проявление на одном каком-то компьютере, а заложенное программистом. То, что на одной системе она греет процессор, на другой моргает лампочками — в поведение не включается.

В побочные эффекты тоже
VE>Если я пишу программу, которая именно что должна греть процессор, то да, вычисление списка не будет RT. Если я пишу калькулятор, то греет он процессор, открывает ли временные файлы, подключается ли к базе — это всё не важно. Если поведение от замены функций на значение (калькуляторное) не меняется, функции — RT.
Вижу, что твоя RT тоже устроена по понятиям. Файлы и БД не считаются единым целым с программой. Чтение из них — это ввод. Если то, что ты прочитаешь из файла/БД будет влиять на результат вычисления, то его нельзя классифицировать как RT.

VE>>>Более того, я считаю, что важность эффекта определяется не википедией, а программистом.

S>>даёшь всё IO без монады IO!

VE>Не всё, а только то, которое является лишь побочным продуктом и не влияет на результат. С putStrLn это, очевидно, не так. putStrLn — ввод-вывод.

Ура, хоть в чем-то согласие. Только поправлю, putStrLn — это не ввод-вывод, ввод-вывод — это будет IO(), который она вернет.
VE>withNewIORef (withNewIORef :: a -> (IORef a -> IO b) -> b — не ввод-вывод).
Нет? А что мне помешает подсунуть в withNewIORef экшн, возвращаемый putStrLn (который ввод-вывод)? Просто я еще не дорос до этого. Потому и спрашиваю, мешает ли что-то заюзать putStrLn в withNewIORef? Соответственно, если не мешает, то withNewIORef будет таким же вводом-выводом, как и экшн от putStrLn.

VE>Ок, пойдём дальше. Вот пишите вы себе на C++ мемоизатор. И что, поведение программы меняется? Ну т.е. вроде бы что-то меняется, как если одну сортировку на другую поменять, но вот поведение — не меняется. Так как время — не заложено в поведении.

Это зависит от прочих вещей. Если в мемоизированном коде был ввод-вывод, то поведение поменяется.

VE>>>Мои определения ничего такого не говорят.

S>>Мне показалось что они указывают на то что выделение памяти есть семантически обозримый побочный эффект.

VE>А также на то, что является ли это поведением или просто implementation defined (т.е. программе в целом насрать на это), так сказать, определяет программист.

Если определяет программист, то это значит что не определяет никто другой. Соответственно, любые изменения порядка/кэширования и т.п. определяются программистом и никем другим.

VE>>>И какую такую левую функцию портит withTemporaryFile, которой не хватило прав?

S>>я ничего не утверждал о порче функций. Я написал что выделять память чистой функции не запрещено.

VE>Не запрещено Абсолютом.


VE>Вот эту фразу поясните:

VE>

VE>Дык это нормально. Чистой функции никто не запрещает жрать память. Портить левую — нельзя. А жрать — сколько влезет.

VE>Кто чего портит у withTemporaryFile?
putStrLn портит. Мне ведь ничего не мешает заюзать его с withTemporaryFile? Если что-то мешает, то там посмотрим.
Re[64]: Мифический Haskell
От: samius Япония http://sams-tricks.blogspot.com
Дата: 16.03.12 18:54
Оценка:
Здравствуйте, VoidEx, Вы писали:

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


VE>По поводу Haskell вы мне лучше скажите по вашим определениям, почему interact принимает чистую функцию, а newIORef возвращает IO (IORef a)?

Я не понимаю сути вопроса. Почему бы interact-у не принимать чистую функцию? И причем тут определения? И почему бы newIORef-у не возвращать IO?
Чему тут конкретно должны мешать определения, которые не мои?
Re[65]: Мифический Haskell
От: VoidEx  
Дата: 16.03.12 20:15
Оценка:
Здравствуйте, samius, Вы писали:

VE>>И не должна. RT позволяет заменить вычисление значением без смены поведения программы. Поведение программы определяет программист.

S>"(in other words, yielding a program that has the same effects and output on the same input)"

Именно. Поведение архиватора, например, какое? Файлы архивировать или память выделять? Вот первое — поведение, второе так, деталь реализации.

VE>>Какой такой грязной map?

S>Тот самый map, который возвращает результат, выделяя память под него. Ты ведь предложил считать выделение памяти обозримым побочным эффектом, вот потому map стал грязным в тот же час.

Я сказал, что оно ничем не отличается от создания временного файла, и потому чисты они или нет (а точнее RT), зависит от ситуации, а не от самого факта. И map — RT.

VE>>
VE>>withTemporaryFile :: (Handle -> IO r) -> r
VE>>

S>Как я понимаю, такая сигнатура не мешает нагадить не только в этот файл, а вообще везде где взбредет.

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

VE>>Если вы используете её так же, как runST, она вполне себе RT. Если вам необходимо именно создание временного файла, то необходим аналог stToIO.

VE>>Что такое runST знаете?
S>Еще нет. Но во всяком случае, об этом есть что почитать. А по поводу withTemporaryFile гугл молчит.

Тогда почитайте, потому что я на это больше всего упор делаю.
Вкратце: у нас есть монада ST, внутри которой (и только внутри) мы можем выделять память, работать с мутабельными переменными.
Однако так как от одних только махинаций с памятью мы гарантированно не сможем получить разные результаты, всю совокупность вычислений мы можем запихнуть в runST и получить чистый результат.
Т.е. почти как unsafePerformIO, но уже не unsafe, потому что у нас подмножество операций, не позволяющих выдать различные результаты.

S>Нет, не это спрашиваю. По этому поводу у меня свое мнение и пока никто меня не разубедил. Я спрашиваю о том, считаешь ли ты что все кто пишет что хаскель чист, пишут чушь?

Нет.

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

S>Вижу, что твоя RT тоже устроена по понятиям. Файлы и БД не считаются единым целым с программой. Чтение из них — это ввод. Если то, что ты прочитаешь из файла/БД будет влиять на результат вычисления, то его нельзя классифицировать как RT.

readIORef тоже тогда можно считать вводом. С т.з. языка ничем не отличается.
Касаемо чтения файла — не влиять, а менять результат от вызова к вызову, тогда не RT.

VE>>withNewIORef (withNewIORef :: a -> (IORef a -> IO b) -> b — не ввод-вывод).

S>Нет? А что мне помешает подсунуть в withNewIORef экшн, возвращаемый putStrLn (который ввод-вывод)? Просто я еще не дорос до этого. Потому и спрашиваю, мешает ли что-то заюзать putStrLn в withNewIORef? Соответственно, если не мешает, то withNewIORef будет таким же вводом-выводом, как и экшн от putStrLn.

Посмотри runST, я в общем и целом про него, но на примере IO, в котором, разумеется, гарантию не дашь.

VE>>Ок, пойдём дальше. Вот пишите вы себе на C++ мемоизатор. И что, поведение программы меняется? Ну т.е. вроде бы что-то меняется, как если одну сортировку на другую поменять, но вот поведение — не меняется. Так как время — не заложено в поведении.

S>Это зависит от прочих вещей. Если в мемоизированном коде был ввод-вывод, то поведение поменяется.

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

VE>>А также на то, что является ли это поведением или просто implementation defined (т.е. программе в целом насрать на это), так сказать, определяет программист.

S>Если определяет программист, то это значит что не определяет никто другой. Соответственно, любые изменения порядка/кэширования и т.п. определяются программистом и никем другим.

Пусть. Зато уже не мешает такую функцию передать в map, например, требующую RT функцию.

VE>>Кто чего портит у withTemporaryFile?

S>putStrLn портит. Мне ведь ничего не мешает заюзать его с withTemporaryFile? Если что-то мешает, то там посмотрим.

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

Само собой, с моей терминологией сделать RT getLine (точнее World -> (String, World)) не получится, но разговор о таком RT вообще бессмысленен. Можно, конечно, считать, что в эту функцию условно передаётся вся Вселенная (в общем-то, именно это и подразумевается), но зачем?
Re[66]: Мифический Haskell
От: samius Япония http://sams-tricks.blogspot.com
Дата: 16.03.12 21:21
Оценка: +1
Здравствуйте, VoidEx, Вы писали:

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


S>>"(in other words, yielding a program that has the same effects and output on the same input)"


VE>Именно. Поведение архиватора, например, какое? Файлы архивировать или память выделять? Вот первое — поведение, второе так, деталь реализации.


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

S>>Тот самый map, который возвращает результат, выделяя память под него. Ты ведь предложил считать выделение памяти обозримым побочным эффектом, вот потому map стал грязным в тот же час.


VE>Я сказал, что оно ничем не отличается от создания временного файла, и потому чисты они или нет (а точнее RT), зависит от ситуации, а не от самого факта. И map — RT.


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

S>>Как я понимаю, такая сигнатура не мешает нагадить не только в этот файл, а вообще везде где взбредет.


VE>Конкретно такая да. Если это принципиально, её можно переписать по аналогии с монадой ST и получить гарантии работы с одним файлом.

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

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

S>>Еще нет. Но во всяком случае, об этом есть что почитать. А по поводу withTemporaryFile гугл молчит.


VE>Тогда почитайте, потому что я на это больше всего упор делаю.


Обязательно в ближайшее время. Инфы с документации мне явно не хватило, что бы перехватить смысл, попытаюсь вкурить Lazy Functional State Threads, упомянутый в статье.

VE>Вкратце: у нас есть монада ST, внутри которой (и только внутри) мы можем выделять память, работать с мутабельными переменными.

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

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

VE>Т.е. почти как unsafePerformIO, но уже не unsafe, потому что у нас подмножество операций, не позволяющих выдать различные результаты.

Интересно, попробую найти ответы в Lazy Functional State Threads.

S>>Нет, не это спрашиваю. По этому поводу у меня свое мнение и пока никто меня не разубедил. Я спрашиваю о том, считаешь ли ты что все кто пишет что хаскель чист, пишут чушь?

VE>Нет.
Рад. Тогда может быть это намек на то, что ты и эти авторы по-разному воспринимают чистоту?

S>>Вижу, что твоя RT тоже устроена по понятиям. Файлы и БД не считаются единым целым с программой. Чтение из них — это ввод. Если то, что ты прочитаешь из файла/БД будет влиять на результат вычисления, то его нельзя классифицировать как RT.


VE>readIORef тоже тогда можно считать вводом. С т.з. языка ничем не отличается.

VE>Касаемо чтения файла — не влиять, а менять результат от вызова к вызову, тогда не RT.

Что-то в этом есть. Т.е. если ты как разработчик даешь зуб что из БД будет прочитано одно и то же при любом стечении обстоятельств, при котором вообще разумно ожидать результатов выполнения программы, тогда, может быть, имеет смысл говорить об RT. Но таки с оговоркой, что такое RT не может быть выкуплено компилятором с умыслом произвести оптимизацию.

VE>Посмотри runST, я в общем и целом про него, но на примере IO, в котором, разумеется, гарантию не дашь.


Ок.

S>>Это зависит от прочих вещей. Если в мемоизированном коде был ввод-вывод, то поведение поменяется.


VE>Открыли файл для чтения в начале программы. Потом пользуемся функцией readFileContents, возвращающую из раза в раз одно и то же по понятным причинам.

VE>Поменяется ли поведение, если в этой функции прочесть один раз во внутренний буфер?

Нет.

S>>Если определяет программист, то это значит что не определяет никто другой. Соответственно, любые изменения порядка/кэширования и т.п. определяются программистом и никем другим.


VE>Пусть. Зато уже не мешает такую функцию передать в map, например, требующую RT функцию.


Не мешает.

S>>putStrLn портит. Мне ведь ничего не мешает заюзать его с withTemporaryFile? Если что-то мешает, то там посмотрим.


VE>Да, забыл упомянуть про это, хотя держал в голове. Имел в виду подмножество IO (статически-гарантируемое), работающее только с этим файлом.

Да, я это предпологал.

VE>Само собой, с моей терминологией сделать RT getLine (точнее World -> (String, World)) не получится, но разговор о таком RT вообще бессмысленен. Можно, конечно, считать, что в эту функцию условно передаётся вся Вселенная (в общем-то, именно это и подразумевается), но зачем?

Вот и я об этом же. Зачем? Особенно, зачем такое считать, если нам не нужна формальная чистота IO String? Мы можем смело называть IO String грязной, не RT, и ничего нам от этого не будет. Хаскель не станет хуже.

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

Но это будет такая, "пользовательская чистота", или чистота в неком контексте, отличающегося от того, что по умолчанию. И все-таки, такая чистота нужна лишь для того, что бы утверждать что совокупность грязных действий имеет локальный и/или незначительный эффект на результат вычислений.
Re[6]: Мифический Haskell
От: vdimas Россия  
Дата: 21.03.12 02:46
Оценка:
Здравствуйте, MigMit, Вы писали:

MM>А, в этом смысле. Понял. Но тут, скорее, играет "двустороннесть" правил пролога, это не относится именно к ПМ.


Относится. Такое же точно программирование в ограничениях, только полноценное. ИМХО, большую часть работы для статически-типизированного языка можно было бы делать в compile-time, и только если данных недостаточно — вызывать поиск в рантайм.
Re[14]: Мифический Haskell
От: vdimas Россия  
Дата: 21.03.12 03:25
Оценка: +1
Здравствуйте, Klapaucius, Вы писали:

K>Нет. MigMit раньше исходил из ошибочного предположения, что в C++ есть параметрический полиморфизм. Но параметрический полиморфизм означает, что forall a. Box a описывает бесконечное кол-во типов.


Почему? ad-hoc — это же не соседний класс, а подкласс чистого полиморфизма, частный случай.
Можно объявить "бесконечное" мн-в типов в С++:
template<unsigned BigN>
struct External {
  struct Internal;
};

template<unsigned BigN>
struct External<BigN>::Internal : External<BigN-1> { 
  typedef External base;
  int value; 
};



K>В C++ же кол-во типов всегда конечно, поэтому полиморфизм там только ad-hoc.


Обычно для показанной техники делают adhoc только для BigN=0, но и это необязательно. Точнее сформулируем так: можно использовать только те типы, которые выводимы во время компиляции, т.е. независимы от данных. И тогда мн-во реально задействованных в программе типов ес-но будет конечным, но это могут быть любые типы из почти бесконечного объвленного мн-ва:
int main(int argc, char * argv[]) {
  External<10>::Internal::base::Internal::base::Internal i;
  i.value = 42;
}
Re[20]: Мифический Haskell
От: vdimas Россия  
Дата: 21.03.12 11:10
Оценка:
Здравствуйте, Klapaucius, Вы писали:

T>>Я не поленился и перепёр haskell в шаблоны один в один:

K>Ох. Лучше бы вы не поленились читать то, что писал МигМит в том треде и что сейчас пишу я.
K>Вот смотрите:

K>Видите, этот код принимает число как аргумент командной строки. Он компилируется. НЕ интерпретируется.




Неправда, он интерпретируется в этом месте:
ScalarProduct a => ScalarProduct (Cons a) where


В отличие от Haskel, подобное преобразование типов (распаковка) для кода Tonal- выполняется в compile-time.


K>И типы проверяет статически.


Тоже неправда. Для АлгТД статически проверяется только м-но допустимых запакованных типов, то бишь статически проверяется лишь некое ограничение на возможный тип, но не сам запакованный тип. Конкретный тип распаковывается исключительно в рантайм, а сама техника распаковки тождественна технике dynamic_cast (с точностью до деталей, то бишь с точностью до способа кодирования/представления токена типа для целей рантайма).


K>Закомментированная строчка вызовет ошибку. Потому, что проверяются не абсолютные размеры списков, а то, что списки одинакового размера. А это известно на этапе компиляции, завит только от написанного кода, а не входных данных.


И опять неправда и непонимание происходящего. Это зависит от реализованной системы типов. Там, где ML-яык работает с боксированными значениями в рантайм, там мы имеем классическую эмуляцию динамики/интерпретации, хоть и со статическими проверками допустимости мн-ва АлгТД в момент компиляции. А там, где ML-язык будет пытаться инстанциировать типы целиком, чтобы избежать лишней динамики в рантайм, без техники зависимых типов не обойтись.

K>И зависимые типы для этого не нужны


Они не нужны только для боксированной реализации рекурсивных типов и прочей динамической типизации.
Re[35]: Мифический Haskell
От: Klapaucius  
Дата: 22.03.12 10:01
Оценка:
Здравствуйте, samius, Вы писали:

K>>Я тут уже указывал способ определить не верхнюю границу, а точное число типов для тизируемого кода на C++

S>Остается выяснить, что же мешает превзойти заранее заданное точное число типов.

Мешает вид полиморфизма в C++

S>Но мы обсуждаем ПП, фичу языка, а не конкретную программу. Причем тут конкретная программа — непонятно.


При том, что фича языка позволяет писать определенный класс конкретных программ. А ее отсутствие — не позволяет.
Рассуждать про n программ, которые в сумме что-то реализуют — это софистика. Ну, как говорить, что (int,+,*) это не кольцо вычетов, а кольцо целых чисел, складывая модули кольца вычетов во всех возможных программах.

K>>И потенциальная бесконечность следует для одной программы.

S>Нет.
Да.

K>>Из определения парам. полиморфизма следует, что у нас есть, по крайней мере, один мономорфный тип () и один полиморфный forall a. Succ a с этим вы согласны?

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

Вы берете удобную для себя половину определения, которое я тут
Автор: Klapaucius
Дата: 09.03.12
привел полностью. Одна только однородность кода не является каким-то характеристическим признаком параметрического полиморфизма. Сабтайпинг, например, тоже позволяет писать однородный код. Собственно, компилятор Java и переписывает однородный код на языке с параметрическим полиморфизмом в однородный код с использованием сабтайпинга на языке, в котором ПП нет вовсе.

S> А то что они должны существовать, да еще и в какой-то конкретной программе, да еще и потенциальной бесконечностью — увы, не следует.


А неудобную для вас вторую часть определения, о том, как однородный код типизируется вовсе отбрасываете. Из второй части определения следует, что они должны существовать.
В C++ они, разумеется, не существуют. Шаблонный код на C++ вообще не может быть типизирован (отсюда и вся мощность шаблонов) и не типизируется. В некоторых реализациях вроде gcc проверяются кайнды (* или Nat), в некоторых, вроде, макрософтовской — даже кайнды не проверяются (ну или не проверялись раньше). Типизируется только инстанциация, результат применения. В языках с ПП типизируется и однородный код и само применение.

S>что мешает сконструитьвать еще один тип в программе на C++? Разумеется, явно в коде, или в компайл-тайме.


Отсутствие в системе типов C++ типа forall a. Succ a.

S>Если обсуждаются примеры из http://migmit.livejournal.com/32688.html, то С# там их применяет в рантайме.


Покажите применение в рантайме из того кода.

S>Тогда вопрос. Откуда C# в компайл тайм знает что надо применить как минимум 1000 типов? Для 1000 код работает, мог бы работать и для большего числа, если бы не StackOverflow.


Еще раз, параметрический код не требует для проверки знания числа типов. Ну, как типизация функции + над int не требует построения и типизации таблицы констант для всего декартова произведения двух множеств значений int.

S>
S>#
S>*
S>(?,...)->? -- unbounded type name
S>


Ну да, это я и имел в виду.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Re[15]: Мифический Haskell
От: Klapaucius  
Дата: 22.03.12 10:01
Оценка:
Здравствуйте, vdimas, Вы писали:

V>Почему? ad-hoc — это же не соседний класс, а подкласс чистого полиморфизма, частный случай.


Нет. Ad-hoc это соседний класс. Никакого "чистого полиморфизма" не бывает. Бывают такие виды порлиморфизма: параметрический полиморфизм (дженерики), ad-hoc (перегрузка/специализация) и сабтайпинг (полиморфизм через наследование) + возможные сочетания.

V>Можно объявить "бесконечное" мн-в типов в С++:

V>
V>template<unsigned BigN>
V>struct External {
V>  struct Internal;
V>};

V>template<unsigned BigN>
V>struct External<BigN>::Internal : External<BigN-1> { 
V>  typedef External base;
V>  int value; 
V>};
V>


Ну и где тут (потенциальная) бесконечность типов? Верхняя граница тут явно задоается.

K>>В C++ же кол-во типов всегда конечно, поэтому полиморфизм там только ad-hoc.


V>Обычно для показанной техники делают adhoc только для BigN=0, но и это необязательно. Точнее сформулируем так: можно использовать только те типы, которые выводимы во время компиляции, т.е. независимы от данных. И тогда мн-во реально задействованных в программе типов ес-но будет конечным, но это могут быть любые типы из почти бесконечного объвленного мн-ва:


Ну, в обсуждаемом примере все типы выводимы во время компиляции (именно это под словом "типы" обычно и понимают). От данных они тоже независисмы. Но шаблоны таким способом использовать нельзя.
... << RSDN@Home 1.2.0 alpha 4 rev. 1476>>
'You may call it "nonsense" if you like, but I'VE heard nonsense, compared with which that would be as sensible as a dictionary!' (c) Lewis Carroll
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.