Чи ортогональні FP та OO?


75

Я чув це раз за разом, і намагаюся зрозуміти та підтвердити думку про те, що FP та OO є ортогональними.

Перш за все, що означає для 2 понять бути ортогональними?

FP максимально заохочує незмінність і чистоту, тоді як ОО, здається, створений для стану і мутації - трохи організована версія імперативного програмування? Я усвідомлюю, що об’єкти можуть бути незмінними, але ОО, схоже, натякає на стан / зміну для мене.

Вони здаються протилежними. Як це впливає на їх ортогональність?

Така мова, як Scala, дозволяє легко виконувати OO та FP, чи впливає це на ортогональність двох методів?

Відповіді:


72

Ортогональність передбачає, що дві речі не пов’язані між собою. Це походить від математики, де це означає перпендикуляр . У загальновживаному використанні це може означати, що два рішення не пов’язані між собою або що одна тема не має значення при розгляді іншої теми. Використовуваний тут, ортогональний означає, що одне поняття не передбачає або виключає інше.

Ці дві концепції об'єктно-орієнтованого програмування та функціонального програмування не є несумісними між собою. Об'єктно-орієнтована орієнтація не передбачає змінності. Багато людей, які знайомляться з об'єктно-орієнтованими програмами традиційним способом, часто спочатку використовують мови C ++, Java, C # або подібні мови, де змінність є загальним і навіть заохочується (стандартні бібліотеки пропонують різноманітні мінливі класи для використання людьми). Тому зрозуміло, що багато людей пов'язують об'єктно-орієнтоване програмування з імперативним програмуванням та змінністю, оскільки саме так вони навчилися.

Однак об'єктно-орієнтоване програмування охоплює такі теми:

  • Капсуляція
  • Поліморфізм
  • Абстракція

Ніщо з цього не передбачає змінності, і жодне з них не виключає функціонального програмування. Так так, вони ортогональні тим, що це різні поняття. Вони не є протилежностями - ви можете використовувати одне, або інше, або те й інше (а то й те, і інше). Такі мови, як Scala та F #, намагаються поєднати обидві парадигми в єдину мову:

Scala - це багатопрофільна мова програмування, призначена для інтеграції особливостей об’єктно-орієнтованого програмування та функціонального програмування .

Джерело

F # - це стисла, виразна та ефективна функціональна та об'єктно-орієнтована мова для .NET, яка допомагає писати простий код для вирішення складних проблем.

Джерело


Я збирався поставити під сумнів формулювання "ОО - це ...", тому що я не думав, що це визначає ОО (функціональне програмування - це дуже багато про поліморфізм та абстракцію). Але до того, як я встиг, ви відредагували його до чогось, що я не можу посварити.
Паскаль Куок,

22
Винахідник Scala Мартін Одерський називає Scala "постфункціональною" мовою, що означає прагматичний підхід, що поєднує найкорисніші існуючі функції незалежно від того, звідки вони походять. Слідуючи цій схемі, можна назвати Java дисфункціональною мовою, що є правдою, але трохи не в темі ...
Landei,

15
Але очевидно, що винахідники та дистриб'ютори використовують ці терміни з маркетингових міркувань. Ці цитати повинні бути предметом обговорення та не використовуватися як аргумент на підтвердження.
Debilski

4
Я не згоден з тим, що об’єктно-орієнтовані та функціональні - це „абсолютно не пов’язані між собою поняття”, дизайнери мов, які добре розуміються на обох, можуть інтегрувати ці два поняття одне до одного. Ця відповідь може бути цікавою, якщо ви хочете порівняти підхід, який застосовували різні мови дизайнери: stackoverflow.com/questions/3644251/…
soc

Може бути правдою, що об'єктно-орієнтоване програмування стало асоціюватися з абстракцією, інкапсуляцією тощо, незважаючи на змінність. Однак, здається, трохи розтягнуто говорити про семантику "об'єктів" без згадки про ідентичність, яка може протистояти змінам, тобто змінності. см softwarefordays.com/post / ... і главу 3 в mitpress.mit.edu/sites/default/files/sicp/full-text/book / ...
jbmilgrom

15

Перш за все, що означає для 2 понять бути ортогональними?

Це означає, що ці дві концепції не мають протилежних ідей або не є несумісними між собою.

FP максимально заохочує незмінність і чистоту. і ОО здається чимось, що створено для стану та мутації (трохи організована версія імперативного програмування?). І я усвідомлюю, що предмети можуть бути незмінними. Але OO, схоже, натякає на стан / зміни для мене.

Вони здаються протилежними. Як це впливає на їх ортогональність?

Така мова, як Scala, дозволяє легко виконувати OO та FP, чи впливає це на ортогональність двох методів?

OO - це інкапсуляція, склад об’єкта, абстракція даних, поліморфізм за допомогою підтипу та контрольована мутація, коли це необхідно (незмінність заохочується і в OO). FP - це склад функцій, абстракція управління та обмежений поліморфізм (він же параметричний поліморфізм). Таким чином, ці дві ідеї не суперечать один одному. Вони обидва надають вам різні види повноважень та механізми абстракції, які, безумовно, можна мати однією мовою. Власне, це теза, на якій побудована Scala !

У своєму експерименті Scala доповіді про в Google Мартін Одерський дуже добре пояснює, як він вважає, що обидві концепції - OO і FP - ортогональні одна одній, і як Scala елегантно та безперешкодно об'єднує дві парадигми в нову парадигму, широко відому в спільноті Scala як об’єктно-функціональна парадигма. Потрібно спостерігати за вами, щоб говорити. :-)


Інші приклади об’єктно-функціональних мов: OCaml , F # , Nemerle .


1
Ось посилання на Youtube для зручного завантаження ~> youtube.com/watch?v=01rXrI6xelE
letronje

2
Моя думка полягає в тому, що хоча oop і fp взагалі не протилежні, є деякі моменти, в яких вам слід вибрати функціонал або oop aprox. Однією з характеристик oop є прив'язка даних і поведінки, а в fp, хоча ви можете це зробити, це не стандарт. Ще один шар. це організація даних та система типів в ієрархічному порядку (з успадкуванням у більшості випадків) для управління абстракціями та полімосфізмом. Можливо, з fp ця сцена є можливою, але вона не популярна.
jneira

ортогональність означає не лише не суперечливість. Це також означає, що одне не означає іншого.
Дедулікатор

12

Перш за все, що означає для 2 понять бути ортогональними?

Це означає, що вони не впливають один на одного. Тобто функціональна мова не менш функціональна, оскільки вона також об’єктно-орієнтована.

Вони здаються протилежними. Як це впливає на їх ортогональність?

Якби вони були протилежними (тобто суто функціональна мова не могла бути об’єктно-орієнтованою), вони за визначенням не були б ортогональними. Однак я не вірю, що це так.

і ОО здається чимось, що створено для стану та мутації (трохи організована версія імперативного програмування?). І я усвідомлюю, що предмети можуть бути незмінними. Але OO, схоже, натякає на стан / зміни для мене.

Незважаючи на те, що це справедливо для більшості основних мов ОО, немає жодної причини, що мова ОО повинна мати змінний стан.

Якщо мова має об’єкти, методи, віртуальне успадкування та спеціальний поліморфізм, це об’єктно-орієнтована мова - незалежно від того, має вона змінний стан чи ні.


4
Об'єктно-орієнтовані мови не потребують розділення класу / об'єкта: Self, JavaScript, Io, Cecil та декілька (десятків) інших мов чудово ілюструють це.
ТІЛЬКИ МОЙ правильний ДУМКА

@JUST: Добре, я видалив посилання на класи. Однак, чесно кажучи, я не казав, що вони це робили. Я просто сказав, що якщо вони мають ці функції, вони OO. Я кажу "тоді і лише тоді", коли я це маю на увазі.
sepp2k

7

Якщо два поняття є ортогональними, це означає, що їх можна незалежно реалізувати в будь-якій мірі в будь-якому даному прояві. Наприклад, розглядаючи музику, ви можете класифікувати музичний твір за тим, наскільки він гармонійний та ритмічний. Два поняття "гармоніка" та "ритміка" є ортогональними в тому сенсі, що існують гармонічні та ритмічні твори, дисгармонічні та аритмічні твори, але також дисгармонічні та ритмічні твори, а також гармонічні та аритмічні твори.

Застосовано до оригінального запитання, це означає, що існують суто функціональні, не об'єктно-орієнтовані мови програмування, такі як Haskell, суто об'єктно-орієнтовані, "нефункціональні" мови, такі як Ейфель, але також мови, які не є такими як C та мови, які є обидва такі як Скала.

Простіше кажучи, об'єктно-орієнтована Scala означає, що ви можете визначити структури даних ("класи" та "ознаки"), які інкапсулюють дані методами, що обробляють ці дані, гарантуючи, що екземпляри цих структур ("об'єкти") завжди знаходяться в визначений стан (контракт об'єкта, викладений у його класі).

З іншого боку, Scala, будучи функціональною мовою, означає, що вона надає перевагу незмінному перед змінним станом і що функції є об'єктами першого класу, які можуть використовуватися так само, як і будь-який інший об'єкт як локальні змінні, поля чи параметри інших функцій. На додаток до цього, майже кожен вислів у Scala має значення, яке спонукає вас використовувати функціональний стиль програмування.

Ортогональність об’єктно-орієнтованого програмування та функціонального програмування в Scala додатково означає, що ви як програміст можете вільно обирати будь-яку суміш цих двох понять, яку вважаєте за потрібну для своєї мети. Ви можете писати свої програми в суто імперативному стилі, використовуючи лише змінні об'єкти і взагалі не використовуючи функції як об'єкти, з іншого боку, ви також можете писати чисто функціональні програми в Scala, не використовуючи жодної з його об'єктно-орієнтованих функцій.

Scala насправді не вимагає від вас використання того чи іншого стилю. Це дозволяє вибрати найкраще з обох світів для вирішення вашої проблеми.


7

Як і всі класифікації, поділ мов програмування на функціональні, об’єктно-орієнтовані, процедурні тощо є вигаданим. Але нам потрібні класифікації, і в мовах програмування ми класифікуємо за набором мовних особливостей та філософським підходом тих, хто користується мовою (де на пізній впливає перший).

Тому іноді «об’єктно-орієнтовані» мови можуть мати успіх, переймаючи особливості та філософію «функціональних» мов програмування та навпаки. Але, звичайно, не всі особливості мови та філософії мови програмування сумісні.

Наприклад, така функціональна мова, як OCaml, здійснює інкапсуляцію за допомогою лексичного масштабування та закриття, тоді як об’єктно-орієнтовані мови використовують публічні / приватні модифікатори доступу. Це несумісні механізми самі по собі, але вони надлишкові, і така мова, як F # (здебільшого функціональна мова, яка прагне жити в гармонії з чітко об'єктно-орієнтованою .NET-бібліотекою та мовним стеком), повинна докласти максимум зусиль, щоб зв'язати розрив.

В якості іншого прикладу, OCaml використовує структурну систему типів для об'єктної орієнтації, тоді як більшість об'єктно-орієнтованих мов використовують систему номінального типу. Вони майже несумісні та цікаво представляють несумісність у сфері об’єктно-орієнтованих мов.


1
Цікаві моменти. Хоча OCaml - це мій хліб і масло (і "перша" мова, що поєднує орієнтацію на об'єкти з висновками типу Хіндлі-Мілнера), я уникав прямого порівняння. Якби я цього не зробив, я б також згадав модульну систему Caml Special Light, яка передує OCaml на пару років і забезпечує механізми абстракції / інкапсуляції, які конкурують з об'єктно-орієнтованою (вони намагаються вирішити подібні проблеми по-різному).
Паскаль Куок,

@Pascal Cuoq - Радий, що вам це було цікаво, мене давно захоплює концепція класифікації штучних конструкцій, і я неодноразово карався за перелік рослин як тварин у Скатергорі.
Стівен Свенсен,

Слід зазначити, що F # заснований безпосередньо на OCaml.
Jacobs Data Solutions

6

Ідея об’єктів може бути реалізована незмінним чином. Прикладом є книга « Теорія об’єктів ", зроблена Абаді та Карделлі, метою якої є формалізація цих ідей і де об'єктам спочатку надається незмінна семантика, оскільки це робить міркування про об'єктно-орієнтовані програми простішими.

У цьому випадку метод, який традиційно міняв би об'єкт на місці, замість цього повертає новий об'єкт, тоді як попередній об'єкт зберігається.


5

Ви можете реалізовувати функції як об’єкти, а об’єкти як набори функцій, тому між цими двома поняттями явно існує певний зв’язок.

FP максимально заохочує незмінність і чистоту

Ви говорите про суто функціональне програмування.

тоді як ОО здається побудованим для стану та мутації

Немає вимоги, щоб об’єкти могли змінюватися. Я б сказав, що об'єкти та мутації були ортогональними поняттями. Наприклад, мова програмування OCaml забезпечує синтаксис для чисто функціонального оновлення об’єкта.

Така мова, як Scala, дозволяє легко робити OO та FP

Не зовсім. Відсутність оптимізації виклику хвоста означає, що більшість ідіоматичних чисто функціональних кодів переповнюються в Scala, оскільки вони витікають з кадрів стека. Наприклад, стиль передачі продовження (CPS) та всі методи, описані у статті « Про те, що завершує » Брюс МакАдам. Немає простого способу це виправити, оскільки сам JVM не здатний оптимізувати хвостовий виклик.

Щодо ортогональності суто функціонального програмування та об'єктно-орієнтованого програмування, я б сказав, що вони принаймні близькі до того, щоб бути ортогональними просто тому, що суто функціональне програмування має справу лише з програмами в малому (наприклад, функції вищого порядку), тоді як об'єктно-орієнтоване програмування має справу з великими -масштабне структурування програм. Ось чому мови функціонального програмування зазвичай забезпечують інший механізм широкомасштабної структуризації, наприклад, модульні системи вищого порядку Standard ML та OCaml, або CLOS для Common Lisp або типи класів для Haskell.


3
-1. Вам справді не потрібно було порушувати цю проблему Scala-TCO тут. Ви не залишаєте жодної можливості бити Скалу, правда?
missingfaktor

7
@missingfaktor: TCO є очевидним протилежним прикладом його твердження про те, що Scala робить FP легким. Ви не залишаєте жодної можливості сліпо виступати за Скалу перед величезними доказами протилежного, правда?
JD,

5
Проголосувавши за відверто провідне слово "більшість". Навіть у чисто функціональних мовах основна частина циклу виконується не за допомогою явної рекурсії, а за допомогою викликів до функцій вищого порядку, які Scala забезпечує чудово.
Дейв Гріффіт,

5
Читання та запис дуже великої кількості функціонального коду протягом занадто багатьох років. Рекурсія хвоста - це молоток, який витягується, коли map / zip / scan / fold / reduce / etc не відповідає задачі. Це не повинно бути занадто дивно. Причина, по якій існують ці дзвінки, полягає в тому, щоб зрештою абстрагувати якомога більше загальних шаблонів рекурсії. Єдиним винятком, про який я можу подумати (де найкращим рішенням є зворотний виклик), є трюк Ерланга "підробляти змінний стан компонента як аргументи зворотного виклику".
Дейв Гріффіт,

3
Якщо я не розумію, виклик у списку складки в жодному разі не знаходитиметься у хвостовій позиції всередині деревної складки. У будь-якому випадку, я стикаюся з проблемою виклику хвоста в Scala, можливо, раз на місяць в середньому, можливо, менше. Я просто не вважаю, що це є особливо великою справою, не кажучи вже про калічу. Можливо, вам доведеться попрацювати над розплутуванням графіків залежностей дещо ретельніше.
Дейв Гріффіт,

3

Одне, що допомогло мені зрозуміти взаємозв'язок між FP та OO, - це книга про SICP, зокрема розділ "Модульність функціональних програм та модульність об'єктів". Якщо ви думаєте над цими проблемами і у вас є вільні вихідні, можливо, варто прочитати перші три глави, його гарне відкриття очей.


1

Я щойно знайшов чудове пояснення ортогональності ООП та ФП.

Основна ідея така. Уявіть, що ми працюємо з AST математичних виразів. Отже, ми маємо різні типи іменників (константа, додавання, множення) та різні дієслова (eval, toString).

Скажімо, вираз є (1 + 2) * 3. Тоді AST буде таким:

       множення
         / \
     додаток 3
      / \
     1 2

Для реалізації дієслова ми повинні забезпечити його реалізацію для кожного типу іменника. Ми можемо представити це у вигляді таблиці:

                +---------------------+-------------------------------------+
                | eval                | toString                            |
+---------------+---------------------+-------------------------------------+
| constant      | value               | value.toString                      |
+---------------+---------------------+-------------------------------------+
| addition      | lhs.eval + rhs.eval | lhs.toString + " + " + rhs.toString |
+---------------+---------------------+-------------------------------------+
| mutiplication | lhs.eval * rhs.eval | lhs.toString + " * " + rhs.toString |
+---------------+---------------------+-------------------------------------+

«Ортогональність» походить від того, що в OOP ми будемо реалізовувати цю таблицю по рядках : ми будемо представляти кожен іменник як клас, який повинен реалізовувати кожен метод.

У FP , навпаки, ми будемо реалізовувати цю таблицю по стовпцях - ми напишемо функцію для кожного дієслова, і ця функція буде по-різному реагувати на аргументи різних типів (використовуючи, мабуть, відповідність шаблону).


Поясненням, схоже, є аргумент, що FP та OOP не є ортогональними, а насправді є протилежними, взаємовиключними, всеохоплюючими підходами.
Натан Таггі,

1
Я тут якось інтуїтивно люблю “ортогональний”. Звичайно, не в тому розумінні, що вони незалежні. У тому сенсі, що вони застосовують протилежний, графічно ортогональний підхід для декомпозиції проблеми.
Даніла Піатов,

Це математично необхідно (так як осі таблиці знаходяться перпендикулярно), але , до жаль , не в тому сенсі , в якому хто -то використовує його для порівняння, скажімо, програмування методів. Отже, це випадок етимологічної помилки.
Натан Таггі,

-1

Ортогональний. Звучить гарно. Якщо ви здобули освіту, ви можете трохи пограбувати її і вдавати. Це трохи схоже на парадигму.

Все залежить від того, в яких колах ви подорожуєте і що вам дасть кожен тип техніки програмування. Я прочитав кілька дописів про СС, і більшість із тих, хто походить з мови функціонального програмування, зазвичай наполягають на тому, що функціонувати можна лише функціонально, а все інше суперечить мисленню та розуму.

Об’єктно-орієнтоване програмування полягає в основному у захопленні стану та збереженні цього стану якомога локалізованішим, щоб на нього не впливало щось, що не є частиною об’єкта, яким ви керуєте станом. З іншого боку, функціональне програмування розглядає проблему стану з іншої точки зору і намагається відокремити стан від системи і звести його до функцій. Так, ви можете використовувати обидва методи у своєму коді, але вони обидва дивляться на розробку програмного забезпечення з різних сторін.

Існує великий інтерес до методів функціонального програмування, головним чином через управління, необхідне державі при роботі з багатоядерними чіпами та паралельним програмуванням. На цей момент здається, що функціональне програмування має перевагу у вирішенні цього, однак ви можете досягти того ж ефекту за допомогою Objects. Ви просто думаєте про проблему інакше. Замість того, щоб дряпати собі голову, намагаючись якомога більше позбутися стану, ви дивитесь на об’єкти в дизайні і бачите, як ви можете з’єднати їх з тим, що є суттю того, що вони очікують зробити, використовуючи шаблони дизайну, CRC та Об’єктний аналіз. Однак там, де об’єкти потрапляють там власні, і де функціональне програмування набагато складніше - це аналіз реального світу та відображення його в зрозумілій комп’ютеризованій системі. Наприклад, в ОО об'єктом особи є інкапсуляція стану з методами, що діють на особу-державу. У функціональному програмуванні людина буде розбита на частини даних та функції, які діють на дані особи, з доданим умовою, що дані повинні створюватися один раз і лише один раз і бути незмінними.

Я повинен визнати, що, походячи з фона OO, що в більшості мов OO, маючи справу з багатоядерними мікросхемами, я пішов функціональним шляхом, головним чином за допомогою основних структур проектування програм (таких як потоки та делегати) і передаю псевдо об'єкти даних навколо. Це змусило мене поставити під сумнів техніку програмування ОО, оскільки, здається, це не відповідає цій різьбовій конструкції.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.