Здравствуйте, Курилка, Вы писали:
К>Дума, стоит упомянуть сабжевую статью Конала Эллиота, тем более описываемые там утверждения уже проскакивали тут на форуме.
попытался прочитать но там много.
можно в двух словах что он хотел сказать?
Здравствуйте, cvetkov, Вы писали:
C>Здравствуйте, Курилка, Вы писали:
К>>Дума, стоит упомянуть сабжевую статью Конала Эллиота, тем более описываемые там утверждения уже проскакивали тут на форуме.
C>попытался прочитать но там много. C>можно в двух словах что он хотел сказать?
Идея, видимо пришла из ООПшного "всё есть объект", но это скорее рационализация, чем истинное утверждение ("контрпример" — если 3, число, — константная функция, то что же возвращает эта функция)
Здравствуйте, Курилка, Вы писали:
К>Здравствуйте, cvetkov, Вы писали:
C>>Здравствуйте, Курилка, Вы писали:
К>>>Дума, стоит упомянуть сабжевую статью Конала Эллиота, тем более описываемые там утверждения уже проскакивали тут на форуме.
C>>попытался прочитать но там много. C>>можно в двух словах что он хотел сказать?
К>Идея, видимо пришла из ООПшного "всё есть объект", но это скорее рационализация, чем истинное утверждение ("контрпример" — если 3, число, — константная функция, то что же возвращает эта функция)
Она возвращает константную функцию — число 3. Те возвращает сама себя. Какие проблемы?
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Курилка, Вы писали:
К>>Идея, видимо пришла из ООПшного "всё есть объект", но это скорее рационализация, чем истинное утверждение ("контрпример" — если 3, число, — константная функция, то что же возвращает эта функция)
G>Она возвращает константную функцию — число 3. Те возвращает сама себя. Какие проблемы?
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Курилка, Вы писали:
К>>Здравствуйте, cvetkov, Вы писали:
C>>>Здравствуйте, Курилка, Вы писали:
К>>>>Дума, стоит упомянуть сабжевую статью Конала Эллиота, тем более описываемые там утверждения уже проскакивали тут на форуме.
C>>>попытался прочитать но там много. C>>>можно в двух словах что он хотел сказать?
К>>Идея, видимо пришла из ООПшного "всё есть объект", но это скорее рационализация, чем истинное утверждение ("контрпример" — если 3, число, — константная функция, то что же возвращает эта функция)
G>Она возвращает константную функцию — число 3. Те возвращает сама себя. Какие проблемы?
с точки зрения хаскеля так думать можно. это конечно не обязательно, но если не хочется отказыватся от "все есть функция" то придется.
но если бы в хаскеле использовались бы числа черча, то это было бы не так.
Здравствуйте, Курилка, Вы писали:
К>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, Курилка, Вы писали:
К>>>Идея, видимо пришла из ООПшного "всё есть объект", но это скорее рационализация, чем истинное утверждение ("контрпример" — если 3, число, — константная функция, то что же возвращает эта функция)
G>>Она возвращает константную функцию — число 3. Те возвращает сама себя. Какие проблемы?
К>Тип покажи
У тройки тип Int, можно считать что это функция с нулем аргументов, которая возвращает себя, а может и ниче не возвращает, так как в типизированной лямбде для функций с нулем аргументов аппликация неприменима.
Здравствуйте, gandjustas, Вы писали:
G>Она возвращает константную функцию — число 3. Те возвращает сама себя. Какие проблемы?
Функция — это отображение чего-то на что-то.
"на что-то" у нас есть: на себя.
Осталось позаботиться об "отображении" и "чего-то".
В роли "чего-то" пусть выступает любое пустое значение.
3 = 3() = 3()() = 3()()() и т.д.
"Отображение" — вызов функции. Есть ли язык, в котором вызов не был бы встроенным действием?
Последнее, что нам нужно — конструктор, превращающий обычное значение в функцию-самограйку.
На нетипизированных языках это провернуть несложно
def constfunc(x) :
def f() :
return f
# или, для пущей уникальности - свяжем xreturn constfunc(x)
return f
Этюд для любителей писанины: выразить оба решения через лямбда-исчисление, с помощью операции Ы (Y).
На типизированных, кстати, тоже. Если у нас есть возможность ad-hoc перегрузить вызов.
Не скажу за хаскелл, насколько там можно наколдовать с $ напрямую.
В С++ же это элементарно
template<class T>
struct constfunc
{
T original; // вдруг кому-то захочется таки посмотреть
constfunc() {}
constfunc(const T& src) : original(src) {}
typedef constfunc result_type; // для совместимости с механизмом вывода boost::bind
result_type operator() () const { return *this; }
};
Единственный вопрос: А НАФИГА?
У объектов есть всякие полезные свойства. Мы можем использовать их идентичность (сравнивать адреса); обращаться к их данным и методам.
Что мы можем сделать с функцией, кроме как применить её к какому-то значению? Но, поскольку константа (по нашему определению) возвращает себя же...
Выход один: эта функция должна реагировать на пароль
def constfunc(x) :
def f(p = None) :
if p is True :
return x
else :
return f
return f
three = constfunc(3)
print three # function<.....>print three(1)(2)(3) # function<.....>print three(1)(2)(3)(False)(True) # 3
В этом прослеживается аналогия с числами Чёрча — когда число является комбинатором. Но аналогия очень зыбкая.
Здравствуйте, gandjustas, Вы писали:
G>У тройки тип Int, можно считать что это функция с нулем аргументов, которая возвращает себя, а может и ниче не возвращает, так как в типизированной лямбде для функций с нулем аргументов аппликация неприменима.
G>Это только вопрос идеологии.
Что такое функция с нулём аргументов? Она применяется к юниту (нуль-арному кортежу) или вообще не применяется?
Если не применяется — какая же это функция?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, gandjustas, Вы писали:
G>>У тройки тип Int, можно считать что это функция с нулем аргументов, которая возвращает себя, а может и ниче не возвращает, так как в типизированной лямбде для функций с нулем аргументов аппликация неприменима.
G>>Это только вопрос идеологии.
К>Что такое функция с нулём аргументов? Она применяется к юниту (нуль-арному кортежу) или вообще не применяется? К>Если не применяется — какая же это функция?
Но ведь
f :: Int
f = 1 + (3 + 3)
является функцией (не в математическом смысле, конечно)
Она даже выполняется (правда, только один раз; и оптимизатор вполне может её вычислить статически)
Prelude> :m + Debug.Trace
Prelude Debug.Trace> let f = 1 + (trace "called!" (3 + 3))
Prelude Debug.Trace> f
called!
7
Prelude Debug.Trace> f
7
Prelude Debug.Trace>
Мне кажется, утверждение "всё является функцией" основано на том, что такого рода сущности никак не выделены в языке. Хотя полезность такого обобщения, конечно, сомнительна (но и вреда особо не видно ).
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, gandjustas, Вы писали:
G>>Она возвращает константную функцию — число 3. Те возвращает сама себя.
DM>Вчера как раз подумал: кот — это устройство по превращению еды в кота, т.е. кот :: еда -> кот.
Здравствуйте, SolVolkov, Вы писали:
К>>Что такое функция с нулём аргументов? Она применяется к юниту (нуль-арному кортежу) или вообще не применяется? К>>Если не применяется — какая же это функция?
SV>Но ведь SV>f = 1 + (3 + 3) SV>является функцией (не в математическом смысле, конечно) SV>Она даже выполняется (правда, только один раз; и оптимизатор вполне может её вычислить статически)
Нуу, батенька!
int hello() { printf("hello!"); return 1+3+3; }
static int const x = hello();
void suddenly()
{
static int const y = hello();
}
Ни x, ни y не являются функциями, хотя, без сомнения, они требуют вычислений — вызова функций hello, printf и operator+.
Причём y — ленивое значение, оно будет вычислено только при первом вызове использующей её функции.
(А если убрать printf, то оптимизатор вполне может и проинлайнить, и вычислить статически).
SV>Мне кажется, утверждение "всё является функцией" основано на том, что такого рода сущности никак не выделены в языке. Хотя полезность такого обобщения, конечно, сомнительна (но и вреда особо не видно ).
Как это не выделены? Функции есть, значения есть, ленивость тоже есть.
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, SolVolkov, Вы писали:
К>>>Что такое функция с нулём аргументов? Она применяется к юниту (нуль-арному кортежу) или вообще не применяется? К>>>Если не применяется — какая же это функция?
SV>>Но ведь SV>>f = 1 + (3 + 3) SV>>является функцией (не в математическом смысле, конечно) SV>>Она даже выполняется (правда, только один раз; и оптимизатор вполне может её вычислить статически)
К>Нуу, батенька!
Я и не утверждал, что "она даже выполняется" -- это определение
К>
К>int hello() { printf("hello!"); return 1+3+3; }
К>static int const x = hello();
К>void suddenly()
К>{
К> static int const y = hello();
К>}
К>
К>Ни x, ни y не являются функциями, хотя, без сомнения, они требуют вычислений — вызова функций hello, printf и operator+. К>Причём y — ленивое значение, оно будет вычислено только при первом вызове использующей её функции. К>(А если убрать printf, то оптимизатор вполне может и проинлайнить, и вычислить статически).
int hello1() {return 1+3+3}
int hello2 = 7
hello1 -- функция с нулём аргументов. Или нет? Она ведь ни к чему не применяется.
f в моём примере -- аналог функции hello1.
SV>>Мне кажется, утверждение "всё является функцией" основано на том, что такого рода сущности никак не выделены в языке. Хотя полезность такого обобщения, конечно, сомнительна (но и вреда особо не видно ).
К>Как это не выделены? Функции есть, значения есть, ленивость тоже есть.
Где есть? И при чём тут ленивость?
Function binding семантически эквивалентно pattern binding. Вот и всё.
Т.е. следующие определения абсолютно идентичны
f2 a = a + 1 -- function binding
f2 = \a -> a + 1 -- pattern binding
f2 = (+1) -- pattern binding
В первом случае f2 биндится на function value, а в двух других -- просто на value. В чём разница между value и function value? Хз, в определении языка никакой разницы я не нашёл (вполне допускаю, впрочем, что плохо искал ).
Haskell Report не даёт определения понятию "функция", да и использует его непоследовательно. Поэтому вопрос, является ли "7" функцией или нет не имеет ответа. Это лишь вопрос предпочтений.
Можно пойти дальше и сказать, что в хаскеле всё является значением. И это тоже будет правдой.
И я так и не понял, в чем, собственно, причина столь большого резонанса по повожу сабжа? Что в этом утверждении плохого и неправильного?
SV>Function binding семантически эквивалентно pattern binding. Вот и всё. SV>Т.е. следующие определения абсолютно идентичны SV>
SV>f2 a = a + 1 -- function binding
SV>f2 = \a -> a + 1 -- pattern binding
SV>f2 = (+1) -- pattern binding
SV>
SV>В первом случае f2 биндится на function value, а в двух других -- просто на value. В чём разница между value и function value? Хз, в определении языка никакой разницы я не нашёл (вполне допускаю, впрочем, что плохо искал ).
Разница в том, что по умолчанию значения мономорфны, а функции полиморфны
f x = x+1 -- Num a => a->a
g = (+1) -- Integer->Integer
-- хотя можно и объявить явно
h :: (Fractional a) => a->a -- подойдёт любой субкласс Num :)
h = (+1)
i :: Int->Int-- подойдёт любой инстанс Num
i x = x+1
А в остальном — это сахар
SV>Haskell Report не даёт определения понятию "функция", да и использует его непоследовательно. Поэтому вопрос, является ли "7" функцией или нет не имеет ответа. Это лишь вопрос предпочтений.
Ну, если термин используется абы как, то предпочтительно было бы не вносить дополнительную сумятицу и не использовать его там, где в обычной жизни его бы не стали использовать.
SV>Можно пойти дальше и сказать, что в хаскеле всё является значением. И это тоже будет правдой.
Ну не всё, конечно. Классы и типы не являются первоклассными объектами. Но то, что является первоклассными — суть значения, по определению
SV>И я так и не понял, в чем, собственно, причина столь большого резонанса по повожу сабжа? Что в этом утверждении плохого и неправильного?
Дык, попытка сделать нечто неестественное. То, что не ложится ни в математическую семантику, ни в программистскую.
Вызывает естественный протест, во-первых, и всякие изыски, во-вторых.
Вот если бы мы разнесли понятия "хранилище" и "значение", причём значения не обязаны быть первоклассными объектами, а возникают постольку-поскольку внутри вычислений, как содержимое регистров...
А чтение хранилища сделать нуль-арной функцией.
Это привело бы к непротиворечивому, но жутко избыточному синтаксису
x = 3
y() = trace"y" `seq` 4()
f() = x() + 1() -- (+) здесь неполноценная встроенная функция, принимающая разбоксированные значения
g(z) = f() + z() -- раз мы пользуемся (+), то вынуждены разбоксировать аргумент
h() = g(y) -- а здесь боксированный аргумент и разбоксированный результат
Кажется, получается комонада... функции вида (box a -> a)
Свят-свят-свят...
SV>>hello1 -- функция с нулём аргументов. Или нет? Она ведь ни к чему не применяется. SV>>f в моём примере -- аналог функции hello1.
К>Нет. В твоём примере f — это static int hello2 = hello1(); К>Точнее, с учётом ленивости, там будет что-то наподобие К>
А если это определение локально (в where)? Ты сейчас пол рантайма HUGS напишешь?
Хаскель -- это не си и не с++. Полного соответствия нет.
Я влез в дискуссию в ответ на конкретный вопрос: можно ли назвать функцией то, что не принимает аргументов. В С/С++ -- можно. А почему нельзя в Haskell?
SV>>Function binding семантически эквивалентно pattern binding. Вот и всё. SV>>Т.е. следующие определения абсолютно идентичны SV>>
SV>>f2 a = a + 1 -- function binding
SV>>f2 = \a -> a + 1 -- pattern binding
SV>>f2 = (+1) -- pattern binding
SV>>
SV>>В первом случае f2 биндится на function value, а в двух других -- просто на value. В чём разница между value и function value? Хз, в определении языка никакой разницы я не нашёл (вполне допускаю, впрочем, что плохо искал ).
К>Разница в том, что по умолчанию значения мономорфны, а функции полиморфны К>А в остальном — это сахар
Разница зарыта где-то в реализации. А число "7" дано мне в ощущениях Хз как оно там реализованно. Может, это функция какая-то.
SV>>Haskell Report не даёт определения понятию "функция", да и использует его непоследовательно. Поэтому вопрос, является ли "7" функцией или нет не имеет ответа. Это лишь вопрос предпочтений.
К>Ну, если термин используется абы как, то предпочтительно было бы не вносить дополнительную сумятицу и не использовать его там, где в обычной жизни его бы не стали использовать.
Не абы как, а непоследовательно. Читай, не ясно, какое мнение о сабже было у автора.
SV>>Можно пойти дальше и сказать, что в хаскеле всё является значением. И это тоже будет правдой.
К>Ну не всё, конечно. Классы и типы не являются первоклассными объектами. Но то, что является первоклассными — суть значения, по определению
SV>>И я так и не понял, в чем, собственно, причина столь большого резонанса по повожу сабжа? Что в этом утверждении плохого и неправильного?
К>Дык, попытка сделать нечто неестественное. То, что не ложится ни в математическую семантику, ни в программистскую. К>Вызывает естественный протест, во-первых, и всякие изыски, во-вторых.
Но у меня же не вызывает протест (И что за изыски, кстати?)
Ну не поворачивается у меня язык функцию main назвать значением (даже с учетом того, что функция тоже есть значение ).
Хотя у авторов Haskell Report поворачивается
HR>>A Haskell program is a collection of modules, one of which, by convention, must be called Main and must export the value main.
Хотя в другом месте аналогичные сущиности называются функциями HR>>Input Functions These functions read input from the standard input device (normally the user’s terminal). HR>> getChar :: IO Char HR>> getLine :: IO String HR>> getContents :: IO String HR>> interact :: (String -> String) -> IO () HR>> readIO :: Read a => String -> IO a HR>> readLn :: Read a => IO a
Здравствуйте, BulatZiganshin, Вы писали:
BZ>правильно: BZ>котоморфизм :: кот -> еда -> кот BZ>имей в виду что кот на входе и кот на выходе различны — второй заметно толще
Так не годится, нужен uniqueness typing хотя бы. Иначе каждый раз число котов будет удваиваться. А он один мутабельный на самом деле.
Здравствуйте, D. Mon, Вы писали:
BZ>>котоморфизм :: кот -> еда -> кот
DM>Так не годится, нужен uniqueness typing хотя бы. Иначе каждый раз число котов будет удваиваться. А он один мутабельный на самом деле.
Здравствуйте, deniok, Вы писали:
DM>> А он один мутабельный на самом деле.
D>Что такое "на самом деле"? Фиксация конкретной операционной семантики ограничивает число способов рассуждать о коте.
На самом деле = консистентная модель, валидируемая экспериментом.
Если я применю котоморфизм Булата, то получу нового кота рядом со старым. А на практике этого не происходит, вместо этого один кот меняет свои свойства (размер). Он вообще работает в ОО парадигме: ему можно послать сообщение, а он может на него среагировать (изменить координаты), а может не среагировать. Т.е. обладает состоянием к тому же.
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, deniok, Вы писали:
DM>>> А он один мутабельный на самом деле.
D>>Что такое "на самом деле"? Фиксация конкретной операционной семантики ограничивает число способов рассуждать о коте.
DM>На самом деле = консистентная модель, валидируемая экспериментом. DM>Если я применю котоморфизм Булата, то получу нового кота рядом со старым.
Это зависит от реализации. Оптимизатор может использовать того же самого кота, выставив в санке еды указатель на желудок этого кота.
Здравствуйте, D. Mon, Вы писали:
DM>На самом деле = консистентная модель, валидируемая экспериментом. DM>Если я применю котоморфизм Булата, то получу нового кота рядом со старым.
да. только это рядом будет не в пространстве а во времени.
Здравствуйте, BulatZiganshin, Вы писали:
BZ>>>котоморфизм :: кот -> еда -> кот
DM>>Так не годится, нужен uniqueness typing хотя бы. Иначе каждый раз число котов будет удваиваться. А он один мутабельный на самом деле.
BZ>ты ещё не постиг дао чистоты
Кот там иммутабельный и чистый. Просто он использует замыкание языка — лижет себе всё, до чего дотягивается.
SV>Я влез в дискуссию в ответ на конкретный вопрос: можно ли назвать функцией то, что не принимает аргументов. В С/С++ -- можно. А почему нельзя в Haskell?
Тут проблема не в том, что она принимает, а что она возвращает.
Если все есть функция, а 3 — константная функция, то что возвращает эта константная функция? Функция — есть однозначное отображение элементов множества A во множество B. Область определения для константной функции пуста, но что представляет собой множество значений?
Говорить, что она возвращает сама себя — бессмысленно, так как это бесконечное рекурсивное определение, тавтология неопределенного понятия.
Здравствуйте, SpaceConscience, Вы писали:
SC>>Область определения для константной функции пуста, но что представляет собой множество значений?
Если область определения пуста, то область значений тоже пуста. Вроде это очевидно.
Функция по определению что-то куда-то отображает. Числа ничего не отображают, но несут в себе значение.
Заметим, что и числа и функции можно представить в виде функций, путем добавления фиктивного параметра
1 -> f(x) = 1 + 0*x; (1)
s(x) -> g(x, y) = s(x) + 0*y;
но функция f отображает числа в числа
если же делать автоматически преобразование (1), чтобы числа называть функциями (и от понятия числа отказаться), то неясно будет какова область определения функции, так как уйдем в бесконечную рекурсию
иногда, числа неявно преобразуют в функции, когда их пытаются дифференцировать:
1'_z = 0 (здесь 1 была преобразована в функцию одного переменного z), однако от понятия числа не смогли бы отказаться, т.к. определение производной опирается на числа =)
зы: короче, я не разделяю попытку отказаться от чисел в пользу функций
Здравствуйте, uzhas, Вы писали:
SC>>>Область определения для константной функции пуста, но что представляет собой множество значений?
Для константной функции — область определения не пуста, а универсальна. Отображаем что угодно в точку.
alwaysThree = const 3
three = alwaysThree undefined-- на входе _|_ как типичный представитель универсума, на выходе - всё равно 3
main = putStrLn $ show three
U>Заметим, что и числа и функции можно представить в виде функций, путем добавления фиктивного параметра
В ФП более популярно представление чисел как комбинаторов — показателей степени повторения функции-аргумента (числа Чёрча)
0(f,x) = x
1(f,x) = f(x)
2(f,x) = f(f(x))
etc.
Поскольку комбинаторный базис SKI содержит тернарный комбинатор S, мы можем договориться, что и все остальные сущности — тоже тернарные (лишние аргументы можно забивать мусорными значениями).
Т.е.
0(f,x,_) = x
1(f,x,_) = f(x,_,_)
2(f,x,_) = f(f(x,_,_),_,_)
А чтобы передавать более трёх аргументов — надо реализовать списки на комбинаторах, и передать список.
U>зы: короче, я не разделяю попытку отказаться от чисел в пользу функций
Здравствуйте, Кодт, Вы писали:
К>В ФП более популярно представление чисел как комбинаторов — показателей степени повторения функции-аргумента (числа Чёрча)
спасибо, погуглил (но там не нашел) и пояндексил
набрел на http://msimuni.wikidot.com/fp-hw11
помогите улучшить\упростить (а может, исправить) решения на задачки 6, 7, 8:
cToInt a = a (+1) 0
cInc c = (\f -> f . (c f))
snd3 (_, b, _) = b
cDec c = (\f -> snd3 $ (c g) (f, id, False))
where g (f, x, True) = (f, f . x, True)
g (f, x, False) = (f, x, True)
К>Поскольку комбинаторный базис SKI содержит тернарный комбинатор S
где можно почитать про SKI и S ?
Здравствуйте, uzhas, Вы писали:
К>>В ФП более популярно представление чисел как комбинаторов — показателей степени повторения функции-аргумента (числа Чёрча) U>спасибо, погуглил (но там не нашел) и пояндексил
Правильно. Но, с учётом того, что f^n · f^m = f^(n+m) = f^m · f^n, можно написать и наоборот
cInc c = \f -> (c f) . f
U>snd3 (_, b, _) = b
U>cDec c = (\f -> snd3 $ (c g) (f, id, False))
U> where g (f, x, True) = (f, f . x, True)
U> g (f, x, False) = (f, x, True)
U>
В принципе, верно. Но я бы сделал попроще:
cDec c = \f x -> finish $ c (step f) (start x) where
start x = (error"вычитание из нуля!!!", x)
step f (decx, x) = (x, f x)
finish (decx, x) = decx
Этюд: придумать числа Чёрча с поддержкой отрицательных значений
К>>Поскольку комбинаторный базис SKI содержит тернарный комбинатор S U>где можно почитать про SKI и S ?
U>>snd3 (_, b, _) = b
U>>cDec c = (\f -> snd3 $ (c g) (f, id, False))
U>> where g (f, x, True) = (f, f . x, True)
U>> g (f, x, False) = (f, x, True)
U>>
К>В принципе, верно. Но я бы сделал попроще: К>
К>cDec c = \f x -> finish $ c (step f) (start x) where
К> start x = (error"вычитание из нуля!!!", x)
К> step f (decx, x) = (x, f x)
К> finish (decx, x) = decx
К>
Надо заметить, что здесь мы неявно пользуемся двумя встроенными функциями: конструктором и парсером кортежа.
Это не совсем честно, в чистом лямбда-исчисление нет иных структур, кроме функций.
Поэтому немножко рукодельничаем ещё:
-- нам нужно:
pair x y = \selector -> .....
fst xy = xy fst' where fst' = .....
snd xy = xy snd' where snd' = .....
-- чёрчева логика
CBool :: {-then-} a -> {-else-} a -> {-result-} a
true_ t e = t
false_ t e = e
if_ c t e = c t e
and_ a b = a b false_
or_ a b = a true_ b
not_ a = a false_ true_
-- и т.д.
-- реализуем
pair x y = \selector -> selector x y
fst xy = xy true_
snd xy = xy false_
-- подставляем
cDec c f x = finish $ c step f $ start where
start = pair (error"-1") x
step xy = pair (snd xy) (f $ snd xy)
finish xy = fst xy
Здравствуйте, SpaceConscience, Вы писали:
SV>>Я влез в дискуссию в ответ на конкретный вопрос: можно ли назвать функцией то, что не принимает аргументов. В С/С++ -- можно. А почему нельзя в Haskell?
SC>Тут проблема не в том, что она принимает, а что она возвращает.
SC>Если все есть функция, а 3 — константная функция, то что возвращает эта константная функция? Функция — есть однозначное отображение элементов множества A во множество B. Область определения для константной функции пуста, но что представляет собой множество значений?
SC>Говорить, что она возвращает сама себя — бессмысленно, так как это бесконечное рекурсивное определение, тавтология неопределенного понятия.
Число 3 не является функцией в математике. С этим никто не спорит. Она ничего не возвращает, поскольку ни к чему не применяется.
Но в субже нет слова "математика". Зато есть слово "хаскел". А определение языка хаскел явно называет сущности, подобные числу 3, функциями. Т.е. число 3 является функцией в языке хаскел. Точка.
Здравствуйте, SolVolkov, Вы писали:
SV> А определение языка хаскел явно называет сущности, подобные числу 3, функциями. Т.е. число 3 является функцией в языке хаскел. Точка.
Здравствуйте, D. Mon, Вы писали:
DM>Здравствуйте, SolVolkov, Вы писали:
SV>> А определение языка хаскел явно называет сущности, подобные числу 3, функциями. Т.е. число 3 является функцией в языке хаскел. Точка.
DM>А ссылку не дашь на такую глупость?
SV>Input Functions These functions read input from the standard input device (normally the user’s terminal).
SV> getChar :: IO Char
SV> getLine :: IO String
SV> getContents :: IO String
SV> interact :: (String -> String) -> IO ()
SV> readIO :: Read a => String -> IO a
SV> readLn :: Read a => IO a
SV>
У IO t ручка вызова недоступна для посторонних, то есть, нельзя просто так написать let x = getChar ().
Только через let x = unsafePerformIO getChar, которое сделает что-то наподобие (unboxIO getChar) ().
Или в недрах оператора >>, который для монады IO сделает то же самое.
Короче говоря, тщательно забоксированная честная функция.
Любое значение можно превратить в IO-функцию
constIO :: x -> IO x
constIO x = return x
Как, впрочем, и в обычную функцию
type Call x = () -> x
constCall :: x -> Call x
constCall x = const x
Но не наоборот же! Не получится применить ($()) или unsafePerformIO к произвольному значению, — только к соответствующей функции.
Здравствуйте, Кодт, Вы писали:
К>У IO t ручка вызова недоступна для посторонних, то есть, нельзя просто так написать let x = getChar (). К>Только через let x = unsafePerformIO getChar, которое сделает что-то наподобие (unboxIO getChar) (). К>Или в недрах оператора >>, который для монады IO сделает то же самое. К>Короче говоря, тщательно забоксированная честная функция.
IO t -- абстрактный тип данных. Как он там устроен внутри -- детали реализации.
Точно так же можно сказать, что у 3 ручка вызова недоступна для посторонних. Причём, совершенно не важно, существует ли такая реализация на самом деле.
К>Любое значение можно превратить в IO-функцию К>
К>constIO :: x -> IO x
К>constIO x = return x
К>
К>Как, впрочем, и в обычную функцию К>
К>type Call x = () -> x
К>constCall :: x -> Call x
К>constCall x = const x
К>
К>Но не наоборот же! Не получится применить ($()) или unsafePerformIO к произвольному значению, — только к соответствующей функции.
Не понимаю, к чему это всё. Что лично ты понимаешь под функцией в haskell? getChar :: IO Char -- это функция или нет? Если да, то почему f :: Int -- нет?
Здравствуйте, SolVolkov, Вы писали:
SV>IO t -- абстрактный тип данных. Как он там устроен внутри -- детали реализации. SV>Точно так же можно сказать, что у 3 ручка вызова недоступна для посторонних. Причём, совершенно не важно, существует ли такая реализация на самом деле.
Сказать-то можно всё, что угодно. Но зачем запутывать самих себя?
SV>Не понимаю, к чему это всё. Что лично ты понимаешь под функцией в haskell? getChar :: IO Char -- это функция или нет? Если да, то почему f :: Int -- нет?
У слова "функция" есть два смысла.
1) Нечто, превращающее одни значения в другие. Есть аргумент — функция. Нет аргумента — не функция.
2) Нечто, имеющее поведение.
Чтобы избежать этой путаницы, — лично я предпочитаю называть функциями отображения.
Дальше есть три пути, чтобы ввести действия в язык
— отказ от чистоты; неявное время, энергичные вычисления; => изменение дизайна языка
— явное время, т.е. getChar :: Timestamp -> (Char,Timestamp) (или уникальные типы — это то же самое, только в профиль)
— работа через адаптер, который снаружи чист — например, монада State и монада IO, но можно было и не упихивать в формализм монад (ценой синтаксического оверхеда или нового сахара)
Заметим, что
getChar — это действие, возвращающее Char
putStrLn — это не действие, а функция (sic!), отображающая String на действие, возвращающее юнит.
К>Сказать-то можно всё, что угодно. Но зачем запутывать самих себя?
Я пока не услышал, к каким проблемам это приводит
SV>>Не понимаю, к чему это всё. Что лично ты понимаешь под функцией в haskell? getChar :: IO Char -- это функция или нет? Если да, то почему f :: Int -- нет?
К>У слова "функция" есть два смысла. К>1) Нечто, превращающее одни значения в другие. Есть аргумент — функция. Нет аргумента — не функция. К>2) Нечто, имеющее поведение. К>Чтобы избежать этой путаницы, — лично я предпочитаю называть функциями отображения.
А Haskell Report и то и другое называет "функция". Т.е., если я правильно понял твой поинт, ты предлагаешь изменить определение языка. Но это уже совершенно другой вопрос Если твоё предложение пройдёт, то ответ на вопрос в субже станет "нет". А пока...
К>Можно ввести понятие "действие" (action). К>Собственно говоря, его и используют в учебнике К>http://www.haskell.org/haskellwiki/Introduction_to_Haskell_IO/Actions
К>Дальше есть три пути, чтобы ввести действия в язык К>- отказ от чистоты; неявное время, энергичные вычисления; => изменение дизайна языка К>- явное время, т.е. getChar :: Timestamp -> (Char,Timestamp) (или уникальные типы — это то же самое, только в профиль) К>- работа через адаптер, который снаружи чист — например, монада State и монада IO, но можно было и не упихивать в формализм монад (ценой синтаксического оверхеда или нового сахара)
К>Заметим, что К>getChar — это действие, возвращающее Char К>putStrLn — это не действие, а функция (sic!), отображающая String на действие, возвращающее юнит.
Интерестно. Ну, т.е., такая интерпретация мне знакома, но я никогда не думал над тем, что это можно закрепить в определении языка. Просто потому, что это требует более формального рассмотрения (иначе повториться та же ошибка, что и с функциями -- интуитивное введение понятия в язык приводит в разногласиям при толковании).
Определить действие через монады, очевидно, не получится. Более того, за десять минут я не придумал ни одного вменяемого способа определить понятие "действие". Если ты знаешь такой способ -- делись
Здравствуйте, SolVolkov, Вы писали:
К>>У слова "функция" есть два смысла. К>>1) Нечто, превращающее одни значения в другие. Есть аргумент — функция. Нет аргумента — не функция. К>>2) Нечто, имеющее поведение. К>>Чтобы избежать этой путаницы, — лично я предпочитаю называть функциями отображения.
SV>А Haskell Report и то и другое называет "функция". Т.е., если я правильно понял твой поинт, ты предлагаешь изменить определение языка. Но это уже совершенно другой вопрос Если твоё предложение пройдёт, то ответ на вопрос в субже станет "нет". А пока...
Ну, тогда пускай переписывают Introduction у себя на сайте. Или Report переписывают. А то развели барррдак!
К>>Можно ввести понятие "действие" (action).
.....
SV>Интерестно. Ну, т.е., такая интерпретация мне знакома, но я никогда не думал над тем, что это можно закрепить в определении языка. Просто потому, что это требует более формального рассмотрения (иначе повториться та же ошибка, что и с функциями -- интуитивное введение понятия в язык приводит в разногласиям при толковании). SV>Определить действие через монады, очевидно, не получится. Более того, за десять минут я не придумал ни одного вменяемого способа определить понятие "действие". Если ты знаешь такой способ -- делись
Почему не получится?
Во-первых, можно post factum: "Действие — это значение типа IO t. Совершение действия производится оператором >>=".
Или, расширенно, — значения из семейства монад со схожими свойствами: одиночный результат и спрятанные побочные эффекты.
Это State, Reader, Writer, Cont.
В пользу такой трактовки — и слово, используемое в сахаре: do.
К>>>Можно ввести понятие "действие" (action). К>.....
SV>>Интерестно. Ну, т.е., такая интерпретация мне знакома, но я никогда не думал над тем, что это можно закрепить в определении языка. Просто потому, что это требует более формального рассмотрения (иначе повториться та же ошибка, что и с функциями -- интуитивное введение понятия в язык приводит в разногласиям при толковании). SV>>Определить действие через монады, очевидно, не получится. Более того, за десять минут я не придумал ни одного вменяемого способа определить понятие "действие". Если ты знаешь такой способ -- делись
К>Почему не получится? К>Во-первых, можно post factum: "Действие — это значение типа IO t. Совершение действия производится оператором >>=". К>Или, расширенно, — значения из семейства монад со схожими свойствами: одиночный результат и спрятанные побочные эффекты. К>Это State, Reader, Writer, Cont.
К>В пользу такой трактовки — и слово, используемое в сахаре: do.
f :: Monad m => m Int
f = return 1
g1 :: IO Int
g1 = do
a <- f
return $ a + 1
g2 :: [Int]
g2 = do
a <- f
return $ a + 1
f -- это действие или нет? Исходя из твоего определения -- нет (поскольку тип не IO t, а Monad m => m t). Но по месту применения выглядит то как действие (в g1), то как значение (в g2). Получается слишком запутано и бессмысленно.
SV>f -- это действие или нет? Исходя из твоего определения -- нет (поскольку тип не IO t, а Monad m => m t). Но по месту применения выглядит то как действие (в g1), то как значение (в g2). Получается слишком запутано и бессмысленно.
Но ведь и функцией это не назовёшь... Где у списка потайная ручка для вызова?
Причём, в одних случаях (когда мы рассматриваем его просто как значение списочного вида) он должен "возвращать" одно: самого себя, аналогично "функции" 3. А в других (в трактовке монады) — другое: элементы поштучно.
Здравствуйте, Кодт, Вы писали:
SV>>f -- это действие или нет? Исходя из твоего определения -- нет (поскольку тип не IO t, а Monad m => m t). Но по месту применения выглядит то как действие (в g1), то как значение (в g2). Получается слишком запутано и бессмысленно.
К>Но ведь и функцией это не назовёшь... Где у списка потайная ручка для вызова?
В том-то и проблема -- мы не знаем, есть ли эта "ручка для вызова" в общем случае. Это становится ясно только по месту вызова (и то не обязательно). Что, ИМХО, не позволит достаточно ясно определить понятие "действие".
К>Причём, в одних случаях (когда мы рассматриваем его просто как значение списочного вида) он должен "возвращать" одно: самого себя, аналогично "функции" 3. А в других (в трактовке монады) — другое: элементы поштучно.
SV>f :: Monad m => m Int
SV>f = return 1
SV>g1 :: IO Int
SV>g1 = do
SV> a <- f
SV> return $ a + 1
SV>g2 :: [Int]
SV>g2 = do
SV> a <- f
SV> return $ a + 1
SV>
SV>f -- это действие или нет? Исходя из твоего определения -- нет (поскольку тип не IO t, а Monad m => m t). Но по месту применения выглядит то как действие (в g1), то как значение (в g2). Получается слишком запутано и бессмысленно.
Хм... Продолжая в том же духе
import Control.Applicative
f :: Applicative f => f Int
f = pure 1
g1 :: Maybe Int
g1 = f
g2 :: Int -> Int
g2 = f
Похоже, что понятия "функция" и "значение" в haskell вообще невозможно формально разделить. Этот haskell -- такой haskell
Здравствуйте, SolVolkov, Вы писали:
SV>Похоже, что понятия "функция" и "значение" в haskell вообще невозможно формально разделить. Этот haskell -- такой haskell
Читаю я вас, читаю.. Вот разделите вы эти понятия или, наоборот, не разделите. Вам же это, наверное, зачем то нужно? Зачем?
Здравствуйте, lomeo, Вы писали:
L>Здравствуйте, SolVolkov, Вы писали:
SV>>Похоже, что понятия "функция" и "значение" в haskell вообще невозможно формально разделить. Этот haskell -- такой haskell
L>Читаю я вас, читаю.. Вот разделите вы эти понятия или, наоборот, не разделите. Вам же это, наверное, зачем то нужно? Зачем?
Здравствуйте, lomeo, Вы писали:
L>Вам же это, наверное, зачем то нужно? Зачем?
это нужно для определения словаря
к примеру, хвала Моисею Исаевичу Шейнфинкелю:
"Его работа также показала, что функции двух или более аргументов может быть заменена функцией принимающий лишь один аргумент. Механизм такой замены упрощает работу как в терминах комбинаторной логики, так и лямбда-исчисления и позднее назван каррированием, в честь Хаскелла Карри."