Подтвердить что ты не робот

Функциональное программирование в С# vs LISP

Каковы основные различия между LISP и С# в отношении функционального программирования? В частности, если программист LISP должен был переключиться на использование С#, каковы функции, которые они, скорее всего, пропустят?

4b9b3361

Ответ 1

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

Сверху моей головы, в определенном порядке:

  • Тип вывода
    • Только для локальных жителей теперь
    • Следует применять практически все.
    • Проблема №1, которая у меня есть с С#, такова. В частности, когда вы объявляете локальную функцию... Func <... >= ouch.
  • Полные функции первого класса
    • Делегаты не являются ответом, поскольку они не являются структурно эквивалентными. Нет канонического типа для представления функции определенного типа. Пример: что такое "прирост"? Это Func? Это конвертер? Это что-то еще? Это, в свою очередь, усложняет вывод.
  • Автоматическое обобщение
    • Отказывается, чтобы вычислить и указать все параметры типового типа и их ограничения
  • Лучшая поддержка неизменности
    • Сделать тривиальным объявление простых типов данных
    • Скопировать с изменением типа (var x = oldX {SomeField = newVal})
  • Кортежи С# 7
  • Дискриминационные союзы (типы сумм)
  • Соответствие шаблону С# 7
    • Повышает ценность кортежей и типов сумм.
    • Позволяет использовать более выраженный код
  • Общий синтаксис монады
    • Делает такие вещи, как асинхронный код, намного проще писать С# 5
    • После того, как вы вложили 2+ уровня BeginXXX/EndXXX, он становится довольно уродливым.
  • Простой синтаксис для функциональных блоков, поэтому вы не заканчиваете закрывающими строками типа "});});"

Изменить: Еще один:

  • Состав функций

    • Сейчас больно делать большую часть любой функции. Currying, chaining и т.д. LINQ здесь не так страшен, потому что методы расширения принимают первый параметр, как метод экземпляра.
  • С# также должен испускать tail.call. Не требуется, JIT будет добавлять хвостовые вызовы сам по себе.

Элементы в жирный были рассмотрены с момента написания этого ответа.

Ответ 2

Поддержка неизменности, в первую очередь.

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

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

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

Однако вы, надеюсь, будете довольны LINQ. Это делает жизнь намного проще для работы с последовательностями данных.

Ответ 3

Если вы спрашиваете Lisper, а не функционального программиста ML-семейства, вы ничего не услышите о кортежах или выводах. Они скажут одно, самодовольно: МАКРОС.

Ответ 4

По вашему вопросу, как Lisper, что я пропустил при программировании на Java (извините, я не использую С#):

  • Хороший синтаксис: s-выражения.
  • Динамическая типизация: описания сложных типов.
  • Затворы.

Адреса С# (2) и (3) с var и =>, соответственно, как я понимаю. Таким образом, мое основное зависание - это завитки и полуколоны, а также подробные, запутывающие объявления типового типа.


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

Кроме того, как программист Haskell, мне все еще не нравятся завитки и полуколоны.:)

Ответ 5

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

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

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

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

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

Ответ 6

Небольшое творчество в сочетании с Linq (которое в основном является функциональным языком, встроенным в С#, становится более очевидным при просмотре Dr. Erik Meijers отличный сериал на Haskell) позволит вам сделать ваш код более функциональным.

Здесь пример без использования Linq:

Haskell:

        minThree :: Int -> Int -> Int -> Int
        minThree x y z 
          | x <= y && x <=z   = x
          | y <=z             = y                      
          | otherwise         = z

С#:

    int MinThree(int x, int y, int z)
    {
        return
              x <= y && x <= z    ? x
            : y <= z              ? y
            : z;

    }

Просто не разрешайте очистке кода Resharper Code по вашему коду, так как это будет выглядеть так:

    int MinThree(int x, int y, int z)
    {
        return
            x <= y && x <= z
                ? x
                : y <= z
                      ? y
                      : z;
    }

: (

Ответ 7

Я, и я это делаю. То есть, я использую Lisp дома и С# на работе, и я пропускаю Lisp, когда на С#. Вопрос немного смешной, потому что я не считаю (Common) Lisp более функциональным, чем С# или Ruby, или любой другой язык с несколькими парадигмами.

В целом функциональные возможности С# становятся довольно приличными, до такой степени, что они, вероятно, достаточно хороши, если немного неудобно. (Обычная Lisp поддержка функционального программирования тоже не идеальна!) Но Common Lisp - это язык с несколькими парадигмами; С# не может (и может никогда) соответствовать Lisp синтаксической абстракции, генерации кода, гибкости отправки метода и т.д.

Если вы ищете оправдание, чтобы избежать обучения Lisp, потому что вы считаете, что С# так же мощный, извините.: -)

Ответ 8

В дополнение к ответу Jon

  • Кортежи - Кортежи возможны с библиотекой, но ей не хватает внутреннего синтаксиса, который имеет большинство функциональных языков.
  • Параметры - В значительной степени то же, что и кортежи
  • Поддержка вывода типа Deep Type - С# добавила поддержку вывода основного типа в VS 2008, но она ограничена локалями внутри тел метода. Большинство функциональных языков, ala F #, имеют глубокую поддержку вывода типов, и это действительно делает язык более читаемым IMHO

Эрик о том, почему С# не имеет глубоких выводов: http://blogs.msdn.com/ericlippert/archive/2009/01/26/why-no-var-on-fields.aspx

  1. Рекурсия хвоста: С# имеет базовую поддержку рекурсии хвоста, но она не укоренена в язык. См. Мое сообщение в блоге о том, где рекурсия хвоста С# и продолжение продолжения

http://blogs.msdn.com/jaredpar/archive/2008/11/10/comparing-continuations-in-f-and-c.aspx

Ответ 9

Несколько возвращаемых значений. "out" и "ref" нечитабельно по сравнению с возвращаемыми кортежами.

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

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

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

Например, скажите, что вы хотите добавить сотрудника в компанию, например

public Company AddEmployee(Employee employee)
{
    var newEmployeeList = new List(EmployeeList); 
    newEmployeeList.Add(employee);
    return new Company(newEmployeeList.AsReadOnly(), ....)
}

просто не очень эффективный или приятный для реализации.

В какой-то момент я даже подумал о создании своих собственных коллекций, начиная с простого непреложного класса Cons.:)

С другой стороны, Linq для нас очень понравился. Мне очень нравятся методы, которые он вводит. Я нашел специальный синтаксис Linq не по своему вкусу.

EDIT: у меня слишком низкий рейтинг, чтобы комментировать, поэтому я отвечу на комментарий Jon здесь. Джон, я решил, что это плохая идея из-за ремонтопригодности. Люди, которые будут поддерживать этот проект в течение следующего десятилетия, вероятно, не имеют значительного воздействия Lisp/функционального программирования. Это напоминает мне другое. Интересно, сколько месяцев обслуживания потребуется, прежде чем мои неизменные объекты станут изменчивыми. (Отказ от ответственности, ИТ-бизнес, являющийся чем-то вроде эпохи "золотой лихорадки", временами я мучительно осознаю, что многие разработчики даже не получают какие-то функции, такие как неизменные и закрытые.)