Самый чистый функциональный язык программирования? [закрыто]

20

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

Мне кажется, что было бы более практично изучать Lisp или Clojure (или Scheme, или Scala и т. Д.), Но, как я недавно слышал, Haskell будет очень трудно победить в обучении принципам функционального программирования кому-то. Я еще не уверен в этом, поэтому я спрашиваю вас: какой самый чистый функциональный язык программирования? Заказ был бы великолепен, если бы несколько человек боролись за великолепное название самого функционального языка программирования.

Joanis
источник
2
Я выучил Миранду в университете, поэтому я предвзят, но я бы предложил Хаскель всем, кто хочет погрузиться в функциональный язык, не отвлекаясь на нечистоту . * 8 ')
Марк Бут
2
После того, как вы закончите изучать функциональное программирование, вы также должны изучить статически типизированное программирование с системой выразительных типов. В комбинированной категории (как функциональной, так и типизированной) я предлагаю: Coq> Haskell> OCaml> Scala> others. Есть несколько менее популярных альтернатив, которые вписываются между Coq и Haskell (как Epigram и Agda). Хаскель скучает по выразительной модульной системе OCaml.
lukstafi

Ответы:

28

Там нет шкалы для оценки степени чистоты функциональных языков. Если язык допускает побочные эффекты, он нечистый, иначе он чистый. По этому определению Haskell, Mercury, Clean и т. Д. Являются чисто функциональными языками; тогда как Scala, Clojure, F #, OCaml и т. д. являются нечистыми.

РЕДАКТИРОВАТЬ: Может быть, я должен был сформулировать это как «если язык не позволяет побочные эффекты, не сообщая системе типов , это чисто. В противном случае это нечисто».

missingfaktor
источник
6
Не совсем: Haskell допускает побочные эффекты ( IOмонада). Просто код, вызывающий побочные эффекты, четко помечен как таковой. Я не думаю, что вообще полезно говорить о чистых / нечистых языках (Haskell позволяет вам обязательно программировать! Ага!), Но все же может быть полезно говорить о кусках кода (функции, модуля, программы и т. Д.) Как о чистых / нечистым.
Фрэнк Шиарар
8
@Frank: Да, Haskell допускает побочные эффекты, но он делает больше, чем просто маркирует код, вызывающий побочные эффекты. Он также поддерживает ссылочную прозрачность даже при использовании кода, вызывающего побочные эффекты, и это то, что он делает чистым - по крайней мере, по определению чистоты многих людей. Конечно, это не соответствует определению отсутствующего фактора «не допускаются побочные эффекты».
2010 в 10:08
4
@Frank Shearar но полезно говорить в таком способе , потому что IOмонада является чистой. Это библиотека времени выполнения, которая не является вашим кодом, так как ваша mainфункция в основном является преобразователем состояния. (Что-то вроде main :: World -> Worldза кадром)
альтернатива
1
Мой язык также имеет ссылочную прозрачность. Вы просто пишете program = "some C code", а затем среда выполнения имеет дело с кодом Си. :-)
Даниэль Любаров
3
Поскольку вывод на экран является побочным эффектом, действительно чисто функциональные программы довольно скучны.
15

Поскольку обучение - ваша цель, а не написание программ как таковых, вы не можете получить ничего более чистого, чем Lambda Calculus .

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

Изучение того, как булевы и числа и как ifих можно изобрести, казалось бы, ничего не добавит больше бензина в ваш бак, но это сделает ваш бак намного больше.

Макнейл
источник
Конечно, нет ничего более чистого, чем это, но мы пересекаем математический барьер немного слишком. Я все еще хочу попрактиковаться в программировании и выучить новый язык, в то же время изучая функциональные принципы Хотя я согласен с тем, что было бы интересно изучить лямбда-исчисление только для лучшего понимания основ функциональной парадигмы (и наличия большего бака).
Джоанис
2
Написание доказательства - это написание программы, а написание программы - написание доказательства. Когда вы узнаете об изоморфизме Карри – Говарда, вы поймете, что преодолели этот математический барьер десять тысяч строк назад.
Макнейл
1
Там нет простого представления -1.
Даниэль Любаров
2
@ Мейсон Уилер: λ-исчисление само по себе не имеет чисел или каких-либо данных, кроме лямбда-абстракций. Если не указано иное, любой, кто говорит о числах в λ-исчислении, вероятно, подразумевает кодирование Черча натуральных чисел , где число n представлено n-кратной композицией функций. Тем не менее, я сомнителен это было , что много борьбы , чтобы выяснить вычитание раз кто - то на самом деле пытались; Я разработал это самостоятельно днем, учитывая только определение сложения и знание того, что вычитание было возможно.
CA McCann
1
Вычитание с использованием церковных чисел легко, если вы получили декомпозицию по кейсам. Построение целого (производного) исчисления для поддержки отрицательных чисел, скорее больше работы.
Донал Феллоуз
6

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

Считаете ли вы Haskell чистым или считаете монаду IO нечистым, стиль Haskell - это крайняя форма этого стиля, которую стоит изучить.

Монада Haskell IO получена из математической теории (конечно) монад. Тем не менее, для императивных программистов, я думаю, обратный способ достижения монад имеет больше смысла.

Первый этап - чистый функциональный язык может легко вернуть большое строковое значение в качестве результата. Эта большая строка может быть исходным кодом императивной программы, полученной чисто функциональным способом из некоторых параметров, определяющих требования. Затем вы можете создать компилятор «более высокого уровня», который запускает ваш генератор кода, а затем автоматически передает этот сгенерированный код в обязательный языковой компилятор.

Фаза вторая - вместо генерации текстового исходного кода вы генерируете строго типизированное абстрактное синтаксическое дерево. Ваш компилятор императивного языка включается в ваш компилятор "более высокого уровня" и принимает AST непосредственно в качестве исходного кода. Это намного ближе к тому, что делает Haskell.

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

Таким образом, для фазы 3, сделайте два одинаковых - одна и та же функция с одинаковым синтаксисом может быть частично оценена во время «генерации кода», или полностью оценена, или вообще не оценена. Далее, отбросьте все циклические узлы конструкции AST в пользу рекурсии. Фактически, полностью отбросьте идею об узлах AST как об особом виде данных - не имейте узлов AST с «буквальным значением», просто имейте значения и т. Д.

Это в значительной степени то, что делает монада IO - оператор связывания - это способ составления «действий» для формирования программ. Ничего особенного - просто функция. Многие выражения и функции могут быть оценены во время «генерации кода», но те, которые зависят от побочных эффектов ввода-вывода, должны иметь задержку оценки до времени выполнения - не по какому-либо специальному правилу, а как естественное следствие зависимостей данных в выражения.

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

Это описание, несомненно, заставит взорваться головы пуристов, но для меня оно объясняет некоторые из реальных причин, почему Хаскель интересен. Он стирает границу между программированием и метапрограммированием и использует инструменты функционального программирования, чтобы заново изобретать императивное программирование без необходимости специального синтаксиса.

У меня есть критика шаблонов C ++ в том, что они являются своего рода сломанным чистым функциональным подъязыком в императивном языке - чтобы оценить ту же базовую функцию во время компиляции, а не во время выполнения, вам нужно заново реализовать ее, используя совершенно другой стиль кодирования. В Haskell, хотя примеси должны быть помечены как таковые в своем типе, одна и та же функция может быть оценена как в смысле метапрограммирования, так и в смысле неметапрограммирования во время выполнения в одной и той же программе - жесткой линии не существует между программированием и метапрограммированием.

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

Многое из того, что я сказал о Haskell, может быть применено на нечистых функциональных языках, а иногда даже на императивных языках. Haskell отличается тем, что у вас нет выбора, кроме как использовать этот подход - он в основном заставляет вас учиться этому стилю работы. Вы можете «написать C на ML», но вы не можете «написать C на Haskell» - по крайней мере, без изучения того, что происходит под капотом.

Steve314
источник
Спасибо! Мне было интересно, можно ли объединить универсальность шаблонов C ++ в сами функции. Похоже, что Haskell делает это, но важной частью является то, может ли это быть реализовано на скомпилированном языке, чтобы тот же самый движок, создающий универсальные функции из шаблонов во время компиляции, мог также оценивать их во время выполнения ...
Milind R
5

Я лично делю языки на три уровня функциональной чистоты:

  • Чисто функциональные языки - то есть те, которые рассматривают всю вашу программу как чистую функцию и обрабатывают изменчивость исключительно посредством взаимодействия со средой выполнения - вероятно, канонический пример - Haskell

  • Нечистые функциональные языки - то есть те, которые подчеркивают функциональный стиль, но допускают побочные эффекты. Clojure явно относится к этой категории (он допускает контролируемые мутации как часть своей структуры STM), также OCaml или F #

  • Мультипарадигмальные языки - это в первую очередь не функциональные языки, но они могут поддерживать функциональный стиль с помощью функций первого класса и т. Д. Scala - хороший пример, я бы также включил Common Lisp в эту категорию, и вы могли бы даже включить языки, такие как JavaScript .

В вашей ситуации я бы предложил сначала изучить Haskell, а затем Clojure. Это было то, что я сделал, и это сработало очень хорошо для меня! Haskell красив и учит вас самым чистым функциональным принципам, Clojure гораздо более прагматичен и помогает вам многое сделать, оставаясь при этом очень функциональным в душе.

Я не считаю третью категорию функциональными языками (хотя после изучения Haskell и Clojure я часто использую функциональные приемы при их использовании!)

mikera
источник
В очень строгих ограничениях даже C обладает функциональными возможностями. (Основное ограничение - это синтез функций во время выполнения, который действительно ужасен в C, настолько, что большинство людей утверждают, что это невозможно.)
Donal Fellows
2
@Donal Fellows: В пределе, когда глупость уходит в бесконечность, каждый язык, полный Тьюринга, функционален: нужно просто внедрить в язык интерпретатор Lisp, а затем использовать его. :]
CA McCann
Парадигмы не имеют смысла, если вы придерживаетесь точки зрения, что все завершено по Тьюрингу и, следовательно, можете подражать всему остальному. Когда вы думаете о парадигмах, вы должны сосредоточиться на том, что язык делает идиоматическим и что он препятствует / мешает. Чтобы считаться функциональным языком, на мой взгляд, мутации и побочные эффекты должны быть однотипными (для нечистых FP) или запрещенными (для чистых FP). Это означает, что C не работает. Также не являются мультипарадигмальными языками, такими как Scala.
Микера
@mikera: Я нахожу ваш ответ очень интересно: если Scala не работает , но только несколько парадигм, как вы оцениваете функциональное программирование особенности в C ++ 11, C #, или даже Java (планируемое введение лямбды)?
Джорджио
@ Джорджио: Я думаю, что функциональные возможности на всех языках, которые вы упоминаете, являются хорошей идеей, они просто не делают их "функциональными языками". Или, если взглянуть на это с противоположной стороны, тот факт, что вы можете сделать монадический ввод-вывод в императивном стиле, не делает Haskell императивным языком :-). Мультипарадигмальные языки - это в основном результат, когда вы объединяете функции из множества разных парадигм и не ставите какой-либо конкретный стиль в первую очередь. ИМХО C ++, C # и Java все движутся к многопарадигме, но пока еще не достигли этого, поскольку ООП на основе классов все еще доминирует.
Микера
3

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

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

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

Кроме этого, если вы ищете «чистоту», вы можете взглянуть на Pure . Однако обратите внимание, что предельная простота вызова подпрограмм на Си делает его функционально неочищенным (но также очень мощным).

back2dos
источник
3

Не совсем серьезный ответ, но Unlambda должен быть соперником. Вы не можете получить более «чистый функционал», чем комбинаторы SKI.

Стивен С
источник
4
Безумие! Ересь! Какой чистый язык имеет такие нелепости, как комбинаторы с побочными эффектами? Нет нет. То , что вы действительно хотите здесь Ленивый K .
CA McCann
2

Erlang, Haskell, Scheme, Scala, Clojure и F #

Этот вопрос, вероятно , лучше вы помочь вам в вашем поиске , как хорошо .

dustyprogrammer
источник
Спасибо, действительно интересный вопрос. Я начал с PLT-Scheme / Racket, но я еще не смотрел на SICP ... Real World Haskell также выглядит довольно интересным для меня.
Джоанис
Схема поощряет функциональный стиль, но у него есть set!(помимо прочего) ...
Даниэль Любаров
Я предлагаю OCaml, потому что это мой любимый. И у него есть модульная система, которую Haskell и F # пропускают.
Лукстафи
@lukstafi, возможно, haskell изменился за последние 3 года (я знаю, что он вырос как сумасшедший), но в haskell определенно есть модули.
Сара
@kai Под модульной системой я подразумевал модули, параметризованные другими модулями («лямбда-исчисление» модулей).
lukstafi