Эффективность соблюдения только функциональной парадигмы в Scala - PullRequest
16 голосов
/ 22 ноября 2010

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

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

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

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

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

Ответы [ 4 ]

16 голосов
/ 22 ноября 2010

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

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

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


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

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

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

одиночки

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

сопутствующие объекты

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

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

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

8 голосов
/ 22 ноября 2010

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

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

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

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

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

7 голосов
/ 23 ноября 2010

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

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

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

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

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

<Ч />

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

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

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

3 голосов
/ 22 ноября 2010

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

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

...