В определённом смысле в любом языке рантайм-среда находится вне языка, но, поскольку язык без неё не может использоваться, это суждение не особо полезно. Давай всё же перейдём к конкретным свойствам программ. Хочу услышать твой ответ про мемоизацию.
Сразу держи для сравнения мой пример про SQL с одной функцией
select :: database -> query -> dataset
В этом API из одной функции действительно нельзя сделать ничего императивного. Нет прямого доступа к stdout. Т.е. действительно есть непреодолимая граница между самим языком и нечистым миром. На моём sql даже невозможно описать никакое императивное действие. В Хаскеле есть writeFile.
Возможно ли на Хаскеле написать программу, которая пишет в файл?
Напрямую нет. Только программу, которая формирует байткод для записи в файл. Вообще любая программа на Хаскеле сводится к вычислению байткода в константе main.
Ты полностью игнорируешь суть деления языков на функциональные и остальные.
Верное и понятное в общем-то замечаиние про функции как объекты первого класса у тебя свелось к «нипанятна», «API ниапридилили».
На пример про композицию ты в ответ буровишь что то невнятное про чистоту. Хотя чистота в общем-то отдельное свойство (языка, хотя и неотъемлемое св-ство теории лямбда-исчисления). Например, в окамле нет монады IO как в хаскеле, но кажется никто не скажет что окамль - не функциональный. Окамль при этом поддерживает объектно-ориентированную парадигму и императивную. Собственно они так и говорят в туториале - три парадигмы.
Т.е. я не говорю, что категоризировать так как ты делаешь - нельзя. Более того, в теории, как ты верно заметил, чистота одно из важнейших свойств (лямбда исчисления), которое позволяет рассуждать о свойствах программы.
Но на практике языки делят так как делят. И это оправдано, потому что когда ты начинаешь плясать с бубном ради композиции, это смешно. А чистота потихоньку в некотором смысле была везде. Ну везде можно написать ф-цию которая зависит только от входных данных. Но такой полной чистоты как в хаскеле, кажется, не было до хаскеля. Но языки фукнциональные были.
Вообще наверное наиболее правильно сказать что функциональный язык это тот у которого модель вычислений в некотором смысле соотвествует лямбда-исчислению. Т.е. вместо , гм, некоторого абстрактного «исполнителя» который выполняет алгоритм, как у обычных языков, в функциональном языке есть понятие «редукция терма». А «исполнителя» нет как такового.
Но опять , будет ли в этом делении смысл? Пока что как мне кажется наиболее удачное деление проходит по «функциям как объектам первого порядка», что в общем то тоже свойство лямбда-исчисления. И это позволяет языку «отображать и отображаться» в лямбда-термы без плясок с бубном (в том смысле что программу на языке можно выразить в виде какого то лямбда-терма и любой лямбда-терм можно лекго выразить в языке).
Пока что как мне кажется наиболее удачное деление проходит по «функциям как объектам первого порядка», что в общем то тоже свойство лямбда-исчисления. И это позволяет языку лямбда-исчисления то лямбда-терма и любой лямбда-терм можно лекго выразить в языке)
Вот ты простое «деление» обвесил «свойством лямбда-исчисления», возможностью «отображать и отображаться» в лямбда-термы без плясок с бубном...
И вот я сижу и думаю, то-ли «функциями как объектами первого порядка» нельзя пользоваться без изучения лямбда-исчисления, то-ли без «лямбда-термов» программы работать не будут, то-ли таки простого «деления» недостаточно...
гм, ну что ж я сделаю если лямбда-исчисление это та самая причина по которой важно иметь функции первого класса?
пользоваться то можно, но вед Денис выше плакался что «апи неопределено» и ему «непонятно» когда функция - объект первого класса, а когда нет. Вот я и говорю - можно без бубнов записывать лямбда термы и темры языка выражать в лямбда термах - значит функциональный. Куда ж мне деваться если он меня гонит в теорию?
как ему упростить, если он «а я наговняю из палок и знаит си - функциональый», а когда ему говоришь «говнять нельзя».. хм, хотя кажется я так не говорил ещё... спасибо за мысль, сейчас попробую.
den73, говнять - нельзя! Этот приём при категоризации языков не рассматривают как важный. Поэтому у тебя и не сходятся концы с концами.
Ты полностью игнорируешь суть деления языков на функциональные и остальные.
Хорошо, что ты сузил своё высказывание, а то я хотел уже сказать, куда тебе идти.
Но такой полной чистоты как в хаскеле, кажется, не было до хаскеля
Вот то-то и оно, что кажется. Нет в хаскеле полной чистоты. Есть чёткая граница. Но такая граница есть и в PL/SQL из Oracle. Т.е. Хаскель в этом отношении мало ушёл вперёд от Oracle.
Причём, Oracle - это гигант рынка, который никто не наделяет лимбом, а никому на практике не нужный Хаскель почему-то превозносят.
Пока что как мне кажется наиболее удачное деление проходит по «функциям как объектам первого порядка»,
Я не плакался, смотри сам не заплачь. Что такое «функция - объект первого порядка»? Где определение того, что значит эта фраза? В каком учебнике и на какой странице? Рискну сказать: я искал ответ на этот вопрос и пришёл к выводу, что такое понятие не определено, т.е. те, кто это говорит, не знают, о чём они говорят.
Ты сначала обоснуй, что композиция входит в понятие «функция является объектом первого класса». И я тебе сразу скажу, что лямбда-исчисление не гарантирует чистоты. В CL вполне возможны лямбды с мутабельным состоянием.
Ну везде можно написать ф-цию которая зависит только от входных данных.
Ты же говоришь «говнять нельзя», а твой ответ как раз в стиле «говнять». Правильная реализация чистоты, это когда ты пишешь в коде «эта функция должна быть чистой». Дальше ты пишешь определение функции. И если она не чистая, то она не компилируется. Это минимум, который компилятор языка должен предоставлять, если он хочет называться функциональным. И минимум, который должен быть в спецификации языка. Иначе да, получается, что вообще нет смысла в слове «функциональный язык».
В Хаскеле, допустим, это звучит примерно так: «если модуль прямо или косвенно не импортирует IO, то он чистый». Не уверен, что это так уж круто, но более-менее сойдёт.
В CL это никак не звучит. Нет никакого инструмента, чтобы нечистая функция не скомпилировалась, кроме рук.
Не хочу встревать в вашу высоко-конструктивную и познавательную беседу, но просто замечу, что в haskell используется два совершенно разных понятия о «чистой» функции (О! Cколько раз я об этом я уже пишу!). Одно - формальное, и по нему практически все функции чисты, даже те, что возвращают результат в рамках монады IO. Да, это факт. А другое понятие «чистоты» неформальное, которое обычно и используют хаскелисты в общении между собой.
Очень многие попадаются на этом, потому что не понимают и не видят разницы.
Типичный пример: «Был у меня чистый монадный трансформер. Я его параметризовал монадой IO, и получилось внезапно грязное вычисление. Как это может быть?» Вот из этой самой серии
Это определение недостаточно для сортировки языков. Что значит «можно создать объект в рантайме»? Вот, например, 3 варианта:
динамическое создание новых функций, как в программах с REPL.
композиция, частичное применение
копирование указателя на функцию, которое есть и в Си.
Что из этого является необходимым для признания функций объектом первого класса?
С внутренней самопозноваемостью тоже не всё ясно. Во-первых, в Си есть void*, который может сделать из мухи слона, но сказать, что муха - это муха, после прохода через void* уже невозможно. Далее, если речь идёт о познаваемости, какого рода информация должна быть известна о функции?
Спасибо за здравое мнение! То, о чём ты говоришь - это классическое «двоемыслие». И то, что пользуясь изначально лживой терминологией, человек попадает во вполне конкретную засаду, как раз и есть единственный путь раззомбирования. Впрочем, религиозные идеологии всегда замкнуты и дают свои объяснения для любых грабель.
Ты же говоришь «говнять нельзя», а твой ответ как раз в стиле «говнять».
не говнять так не говнять - 1) отменяем атд из говна и палок и пишем по русски - в си нет поддержки атд, согласен? 2) отменяем композицию из говна и палок и пишем по русски - в си нет способа композировать функции в общем случае 3) в си нет способа передавать функции так же как мы передаём другие типы (уточню что имею ввиду: когда я передаю инт - я вижу в параметрах функции инт, когда передаю структуру - компилятор проверит что я передал структуру того типа что я описал, а когда передаю функцию - я её кастую в void * и никто не может проветь что функция должна возвращать и что принимать, в отличие)
пункты 2 и 3 означают что функции в си - не объекты первого класса. значит си - не фукнциональный язык.
Это подстановочная модель вычислений.
Используется только в теоретических исследованиях по CS, практического применения в чистом виде не имеет, в силу ограниченных возможностей.
И я тебе сразу скажу, что лямбда-исчисление не гарантирует чистоты. В CL вполне возможны лямбды с мутабельным состоянием.
мне кажется что ты сам не понимаешь что говоришь, пэтому таки поясню
лямбда-исчисление - это такая алгебраическая теория. я тебе могу сказать что в чистом (нетипизированном) лямбда-исчислении мутабельности нет как таковой. Правда из немутабельных примитивов можно сконструировать объекты, которые будут вести себя как мутабельные. Но это ничего не меняет, лямбда-исчисление гарантирует чистоту, как теория. Там просто нет ни слова о побочных эффектах, только редукция термов, вот и всё. а то что «в лиспе можно написать», так это дело десятое. Странный аргумент честно говоря.
Хорошо, что ты сузил своё высказывание, а то я хотел уже сказать, куда тебе идти.
И да, я его не сужал. Я об этом так сразу и сказал - ты игнорируешь суть при категоризации. То что ты не умеешь читать - проблемы исключительно твоего обучения. А сказать куда тебе идти и я могу, дело не хитрое.
ну просто сконструируй свой терм-вычисление так чтобы в параметрах передавались все термы описывающие состояние. И вызывай его рекурсивно каждый раз когда состояние изменилось.
ВОобще странное понимание у тебя, анонимус: чистое лямбда-исчисление тьюринг-полно, соотвественно всё что можно в обычном писюке - можно и там.
факториал считается без состояния с точки зрения ФП. То что вычислитель там создает стек вызовов, передает параметры, схлопывает его — это к семантике не относится.
чистое лямбда-исчисление тьюринг-полно
Да
, соотвественно всё что можно в обычном писюке - можно и там
Нет. Ни там ни там нет интерактивности и индетерминизма. Уже давно доказано, что существуют алгоритмы, нереализуемые на МТ.
Эта гипотеза Черча-Тюринга — не более чем замшелый штамп, который зачем-то вбивают в голову студентам.
ну просто сконструируй свой терм вычисление так чтобы в параметрах передавались все термы описывающие состояние. И вызывай его рекурсивно каждый раз когда состояние изменилось.
Это какая-то демагогия. Состояние либо есть либо нет. То что кто-то там будет *считать* что-то состоянием, это не сделает его таковым.
Для пользователя лямбда-вычислителя нет вообще никакой пеердачи чего-то куда то, там есть аппликация и абстракция, запись же описывает отображение.
Очевидно, чтобы появился новый объект (неравный существующим).
Соответственно, «динамическое создание новых функций, как в программах с REPL» и «композиция, частичное применение» подходят, а
«копирование указателя на функцию» нет, так как это та же функция.
Я об этом так сразу и сказал - ты игнорируешь суть при категоризации
Это неправда и ты сам это признал. Но если ты на таком уровне хочешь разговаривать, кидать вот такие вот общие оценки моей деятельности, то это уже троллинг, а мне это неинтересно. Мне интересен содержательный разговор. До новых встреч!
Ну так тут записью в файл занимается bash, а не sql. В моём SQL нет команды для записи в файл. А в Хаскеле - есть. Как ни прячь ты её за байткодами и компиляторами, от ответственности не уйти.
Очевидно, чтобы появился новый объект (неравный существующим).
На мой взгляд, в такой формулировке слабовато. Я ожидал конкретного набора операций. Хотя в Си и это возможно - можно подлинковать динамическую библиотеку и будет действительно новая функция.
Оригинальный англоязычный термин более точен: «function as first-class object». Первоклассный объект как объект языка, а не как сущность из ООП. Отсюда растут ноги ФВП, святой троицы map-filter-reduce прежде всего.
Поэтому в haskell обычно используют понятие о ссылочной прозрачности, которая является достаточным условием для формальной чистоты, а также является обоснованием для ленивости. Революционность языка состоит в том, что практически все функции (за редким исключением тех функций, что используются в отладке, и пары единиц корявых функций) являются ссылочном-прозрачными, даже те, что создают побочные эффекты, например, оперируя с вводом-выводом в файлы, а также меняя содержимое ссылок.
Поэтому нет особой необходимости использовать термин формальной чистоты, поскольку он уже замещен более сильным понятием. И тогда ничего плохого нет в том, чтобы вольно трактовать чистоту.
Короче говоря, читайте книги, друзья, и практикуйтесь, чтобы не делать ляпов, изобретая собственную «терминологию» из-за непонимания существующей!