Честно говоря, не совсем вижу. Функции обязаны быть чистыми, static переменные нельзя, циклы с изменяемым счётчиком нельзя. Там от императивности ничего и не останется. Поправьте, если я не прав.
На всякий случай уточню, чтобы небыло недопонимания. Класс здесь не связан с таковым в ООП. Это скорее в математическом смысле. Т.е. все числа принадлежат к классу Num, а все упорядочиваемые — к классу Ord (сокр. от ordering)
Достаточно потребовать, чтобы функция вызывала себя только с редуцированными аргументами. В таком случае fact завершается, так как вызывает себя с аргументом на 1 меньше, а при 0 (или 1) значение определено.
Можно даже так: один аргумент может оставаться тем же, если при этом уменьшается другой, но если второй даже увеличивается, то первый должен уменьшиться, тогда второй обязательно дойдёт до некоторого минимума, после чего уменьшится первый и в итоге всё завершится.
Всё зависит от способностей total checker'а.
Насчёт того, насколько мощным будет это подмножество — не знаю, но сходу очевидны такие примитивы как map/fold/filter и прочие списочные функции, а значит и все их комбинации.
Понятно, что вся программа не будет таковой, но если так удастся написать хотя бы часть функций, это уже хорошо.
Данная запись означает:
«Для любого типа t такого, что он принадлежит к классу Ord и Num, функция max2 принимает один аргумент типа t и возвращает результат типа t»
Про классы я ещё расскажу. Вкратце, суть в том, что если тип принадлежит к некоему классу, то над ним определены некоторые функции, и если max2 можно выразить только через эти функции, то сам тип уже не важен. Это может быть и Int, и Double, и даже Ratio (целочисленная дробь)
Я привёл пример, чтобы показать, что многие достаточно сложные задачи решаемы и на Total FP. Т.е. имеет смысл выделить это в языке особенным образом (как выделены «грязные» функции).
Хотите — используете всю мощь, но теряете уверенность в том, что алгоритм завершится.
В общем-то да, язык для описания доказательств, но чем это не язык программирования? Разве что тулзу на нём не написать, но речь была не об этом, а о возможностях total fp.
«Проблема всех языков программирования в том, что они делают то, что он написал, а не то, что имел в виду»
От ошибки алгоритма никуда не деться. Но если в Хаскеле ещё можно написать head [] и получить ошибку во время исполнения, то dependent types это пресекут.
По поводу проблемы остановки. Есть Total FP. Например Coq, он не Тьюринг-полный, однако на нём верифицировали (доказали корректность) урезанного компилятора из C в PowerPC. Возможности таких языков велики. Из этого следует, что гарантированно завершнимое подмножество языка может быть как-то выделено, на системе типов или ещё как-то.
Тогда если используешь потенциально незавершимый алгоритм, это будет отражено так же, как сейчас отражаются операции ввода-вывода в Хаскеле.
Я ответил чуть выше.
В общем-то мне самому интересно в этом разбираться, так как на практике я Haskell не использовал (а хочу), так что если есть интересные задачи, я готов попробовать.
Но выделить задачу, в которой ФЯ был бы удобнее, — сложно. Он везде удобнее, правда, за это приходится платить.
То, что это чат, — не принципиально. Там есть и многопоточность (Chan, MVar, forkIO), и GUI, и бесконечные списки. В принципе это же самое можно показать на примере любой другой программы.
Он призван сократить количество кода, а это работает практически на любых задачах. Я, честно говоря, не знаю, есть ли какая-то конкретная задача, где можно оценить функциональный язык во всей красе. Ну, т.е. по-моему любая задача подходит :)
Обработка деревьев и списков, конечно, хорошо, но это обычно составная какой-то более сложной задачи, а не сама программа.
Вот это я и хочу показать на примере реализации чата. Можно будет оценить, что стало проще, что сложнее.
В целом всё это даёт более короткую запись, а строгая типизация позволяет практически избежать ошибок.
Это уже большой плюс. Конечно, те же бесконечные списки можно запрограммировать итераторами, но Haskell потому и стоит учить, что он позволяет по-другому решать задачу, хотя потом её можно будет записать хоть на Си++.
Можно даже так: один аргумент может оставаться тем же, если при этом уменьшается другой, но если второй даже увеличивается, то первый должен уменьшиться, тогда второй обязательно дойдёт до некоторого минимума, после чего уменьшится первый и в итоге всё завершится.
Всё зависит от способностей total checker'а.
Насчёт того, насколько мощным будет это подмножество — не знаю, но сходу очевидны такие примитивы как map/fold/filter и прочие списочные функции, а значит и все их комбинации.
Понятно, что вся программа не будет таковой, но если так удастся написать хотя бы часть функций, это уже хорошо.
«Для любого типа t такого, что он принадлежит к классу Ord и Num, функция max2 принимает один аргумент типа t и возвращает результат типа t»
Про классы я ещё расскажу. Вкратце, суть в том, что если тип принадлежит к некоему классу, то над ним определены некоторые функции, и если max2 можно выразить только через эти функции, то сам тип уже не важен. Это может быть и Int, и Double, и даже Ratio (целочисленная дробь)
Хотите — используете всю мощь, но теряете уверенность в том, что алгоритм завершится.
compcert.inria.fr/doc/index.html
В общем-то да, язык для описания доказательств, но чем это не язык программирования? Разве что тулзу на нём не написать, но речь была не об этом, а о возможностях total fp.
От ошибки алгоритма никуда не деться. Но если в Хаскеле ещё можно написать
head []и получить ошибку во время исполнения, то dependent types это пресекут.По поводу проблемы остановки. Есть Total FP. Например Coq, он не Тьюринг-полный, однако на нём верифицировали (доказали корректность) урезанного компилятора из C в PowerPC. Возможности таких языков велики. Из этого следует, что гарантированно завершнимое подмножество языка может быть как-то выделено, на системе типов или ещё как-то.
Тогда если используешь потенциально незавершимый алгоритм, это будет отражено так же, как сейчас отражаются операции ввода-вывода в Хаскеле.
-fwarn-incomplete-patternsИли это не оно?
Нас спасут dependent types, когда выйдут из подполья :)
В общем-то мне самому интересно в этом разбираться, так как на практике я Haskell не использовал (а хочу), так что если есть интересные задачи, я готов попробовать.
Но выделить задачу, в которой ФЯ был бы удобнее, — сложно. Он везде удобнее, правда, за это приходится платить.
То, что это чат, — не принципиально. Там есть и многопоточность (Chan, MVar, forkIO), и GUI, и бесконечные списки. В принципе это же самое можно показать на примере любой другой программы.
Обработка деревьев и списков, конечно, хорошо, но это обычно составная какой-то более сложной задачи, а не сама программа.
REPL'а вполне достаточно. Можно любую функцию определить и тут же её прогнать.
То, что бесконечный список не вычисляется до его вывода на экран, я показал.
Или вы о нюансах?
В целом всё это даёт более короткую запись, а строгая типизация позволяет практически избежать ошибок.
Это уже большой плюс. Конечно, те же бесконечные списки можно запрограммировать итераторами, но Haskell потому и стоит учить, что он позволяет по-другому решать задачу, хотя потом её можно будет записать хоть на Си++.