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

Эффективность придерживаться только функциональной парадигмы в Scala

Недавно я купил Программу Scala и читал ее. Язык определенно не то, что я ожидал! В частности, он, похоже, реализует практически любую идею языка программирования, о которой я знаю, вне макросов Lisp и сегрегации побочных эффектов типа Haskell.

Честно говоря, это меня несколько ошеломило. Хотя я полагаю, что в моем распоряжении было так много инструментов, я действительно искал строго типизированный функциональный язык JVM. Я предполагаю, что я мог бы, вероятно, использовать Scala таким образом, но я думаю, что если я буду взаимодействовать с любыми библиотеками или пройти через любой другой код, я буду сталкиваться с этим передовым (для меня) материалом ООП - чертами и "линеаризация иерархии объектов", все эти абстрактные и переопределяющие бизнес-объекты, одиночные, пакетные и сопутствующие объекты, неявные преобразования... не говоря уже о различных синтаксических ярлыках и сахарах.

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

Могут ли более опытные программисты Scala помочь мне здесь? Изменить для ясности: В принципе, могу ли я безопасно использовать только (или в основном) функции FP Scala, не беспокоясь о своей расширенной стороне ООП?

Извините за бессвязный вопрос!

4b9b3361

Ответ 1

Я думаю, что в этом вопросе, безусловно, есть твердая точка. Он подсвечивается путем изучения того, как любая библиотека может обрабатывать исключения.

Если вы взаимодействуете с библиотекой Java, любой метод может вызвать исключение. Это может быть либо явно, либо через проверенное исключение, либо прозрачно (с точки зрения API) через исключение среды выполнения. Что вы должны делать с этим, как программист, который может попытаться использовать более функциональный тип Either для указания отказа (или scalaz Validation)?

Это совсем не ясно, как это будет происходить в scala (т.е. приближается к проблеме и выбирается чисто функциональный подход). Конечно, это может привести к созданию разных стилей. Тем не менее, есть много, что богато и полезно по функциональной стороне scala, которую вы можете выбрать; и, безусловно, возможно, что это сочетание функционального и императивного кода в вашей программе работает вместе друг с другом. Хотя функциональный пурист может, конечно, не согласиться с тем, является ли это оптимальной ситуацией.

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

Но он стирает пол Java; и получить это на JVM (с практическим преимуществом сосуществования со всеми нашими библиотеками Java) - это приложение-убийца, с моей точки зрения.


По краям, когда вы начнете использовать функциональную сторону scala больше, есть ряд проблем, с которыми вы столкнетесь. Это наиболее очевидно:

  • отсутствие каркаса неявной функции (т.е. эквивалентность A => B => C и (A, B) => C)
  • отсутствие непроверки функции (т.е. эквивалентность между n-арной функцией и 1-арной функцией, которая принимает n-кортеж в качестве параметра)
  • отсутствие вывода для частично прикладных конструкторов типов (т.е. эквивалентность M[A] с, например, Either[Int, A])

Оба эти вопроса делают то, что должно быть красивым и понятным функциональным кодом, уродливым и неясным.

Ответ 2

Одна из вещей, которые вы видите, заключается в том, что Scala - это, прежде всего, строго типизированный функциональный язык на JVM

Scala - это не только функциональный язык. Он начинался как один (Воронка: http://lamp.epfl.ch/funnel/), но затем она была расширена, чтобы сделать его объектно-ориентированным языком, с явная цель сделать его сильно совместимым с Java-классами.

абстракция и переопределение и пакеты являются примерами этой функциональной совместимости в действии.


Остальные могут рассматриваться не как новые функции, а просто как удаление ограничений с Java. Принимая их по одному:

черты и линеаризация иерархии объектов

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

одиночек

Статические методы Java - это похмелье от его синтаксического наследия С++, которое, в свою очередь, добавило их для лучшей поддержки процедурного стиля для взаимодействия с C. Статические методы очень НЕ объектно ориентированы (см. этот вопрос: Почему объектные объекты более объектно-ориентированные?)

объекты-компаньоны

Разрешить использование синглетонов вместо статических методов с их привилегированными правами доступа.

неявные преобразования

Java уже делает это, но ограничивается только неявным преобразованием объектов и примитивов в строки, как в выражении "" + 3. Scala просто расширяет эту идею и позволяет программисту использовать ее для других преобразований.

Ответ 3

Позвольте мне добавить несколько комментариев к ответу Кевина.

Черты используются в основном как абстракции (не говоря уже о том, что классы типа Haskell определяют абстракции) и mixins. Таким образом, мой код может использовать свойство Map, но он действительно использует экземпляр типа HashMap. И наоборот, если я хочу, чтобы у моего типа "Служба" была функция ведения журнала, я мог бы смешивать его с возможностью повторного использования.

К счастью, вам редко приходится думать о линеаризационном алгоритме за пределами простых случаев, например, я могу смешивать в признаке, который перехватывает (обертывает) вызов метода для регистрации того факта, что метод был вызван. Алгоритм должен обрабатывать более сложные случаи линеаризации (например, примеры, которые мы приводим в книге), но на самом деле такие сложные типы - плохой дизайн, ИМХО.

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

Неявные преобразования очень полезны, если бит "волшебный". Возможно, вам будет полезно увидеть, как они используются для имитации типов классов Haskell. Здесь отличный пост от Debasish Ghosh: http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html

Ответ 4

Хотя я начал программировать в scala, я определенно не более опытный член сообщества scala. Но я долго работал с другим языком - питоном, который в меньшей степени имеет подобную ситуацию. Он поддерживает процедурные, объектно-ориентированные и функциональные стили. Я обнаружил, что, хотя некоторые люди склонны придерживаться одной крайности, многие объединяют конструкции из разных стилей. Таким образом, идиоматический python будет состоять из интенсивного использования списков, первого класса, более высокого порядка и частичных функций, даже если данные, над которыми работают эти функции, являются объектами. Однако следует отметить, что на протяжении многих лет тенденция заключалась в том, чтобы слегка сдвинуться в сторону функциональности.

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