Разногласия между базами данных и функциональным программированием?

122

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

Одна вещь, которая сделала меня гораздо более продуктивным разработчиком в области ООП, - это открытие объектно-реляционных преобразователей, таких как MyGeneration d00dads для .Net, Class :: DBI для perl, ActiveRecord для ruby ​​и т. Д. Это позволило мне держаться подальше от написания операторов вставки и выбора в течение всего дня и сосредоточиться на простой работе с данными как с объектами. Конечно, я все еще мог писать SQL-запросы, когда требовалась их мощность, но в остальном это было красиво абстрагировано за кулисами.

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

(Обратите внимание, я не очень внимательно изучал веб-блоки или ссылки, возможно, я просто неправильно понимаю, как они используются).

Итак, вопрос в том, что для частей доступа к базе данных (которые, как я считаю, довольно большие) веб-приложения или другой разработки, требующей интерфейса с базой данных sql, мы, похоже, вынуждены пойти по одному из следующих путей:

  1. Не используйте функциональное программирование
  2. Доступ к данным раздражающим, неабстрагированным способом, который включает в себя ручное написание большого количества SQL или SQL-подобного кода ala Links
  3. Заставьте наш функциональный язык превратиться в парадигму псевдо-ООП, тем самым убрав часть элегантности и стабильности настоящего функционального программирования.

Ясно, что ни один из этих вариантов не кажется идеальным. Нашел способ обойти эти проблемы? Здесь действительно есть проблема?

Примечание: я лично больше всего знаком с LISP на фронте FP, поэтому, если вы хотите привести какие-либо примеры и знаете несколько языков FP, то, вероятно, предпочтительным языком будет Lisp.

PS: По вопросам, связанным с другими аспектами веб-разработки, см. Этот вопрос .

Тристан Хавелик
источник
4
Ознакомьтесь с ClojureQL и HaskellDB. Это уровни абстракции, использующие реляционную алгебру.
Masse
10
Вы начинаете с неправильной предпосылки. Функциональное программирование - это явное и разумное управление состоянием. На самом деле они очень хорошо работают с базами данных.
Люциан
3
SQL - один из наиболее успешных языков, ориентированных на функциональное программирование, и я не думаю, что в нем есть какие-то внутренние трудности.
Дуглас
3
Ваши №2 и №3 - ложная дихотомия. Написание необработанного SQL - это не то, чего следует обязательно избегать, и абстракции над базой данных не обязательно должны быть в стиле ООП.
Дэн Бертон

Ответы:

45

Прежде всего, я бы не сказал, что CLOS (Common Lisp Object System) является «псевдо-объектно-ориентированным». Это первоклассный OO.

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

Вы не можете хранить данные без состояния, в то время как функция является потоком данных и на самом деле не требует состояния.

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

Сванте
источник
3
просто для удовольствия, я подумал, что упомянул бы журнал данных, который пытается сделать базу данных без сохранения состояния. он записывает все действия, такие как «пользователю нравится сообщение 1233.» Эти действия приводят к истинному состоянию базы данных. Ключ в том, что запросы - это просто факты, а не мутация ...
Чет
80

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

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

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

Я бы не стал писать T-SQL или использовать концепции дизайна базы данных для создания вашего пользовательского интерфейса, зачем вам пытаться использовать свой язык интерфейса и концепции дизайна для доступа к моей базе данных? Потому что вы думаете, что SQL недостаточно модный (или новый)? Или вам это не нравится? То, что что-то не соответствует модели, с которой вы чувствуете себя наиболее комфортно, не означает, что это плохо или неправильно. Значит, он другой и, вероятно, другой по уважительной причине. Вы используете другой инструмент для другой задачи.

HLGEM
источник
«SQL написан для более эффективного решения первых двух вопросов, чем любой интерфейсный язык». Да неужели? Почему же тогда получается, что ограничения SQL до сих пор не могут делать такие вещи , как это ?
Робин Грин,
Но триггер может, это одна из основных целей триггеров - иметь возможность обрабатывать сложные ограничения.
HLGEM
2
Я бы переместил ваш последний абзац так, чтобы он стал первым. Очень хороший момент, который перекликается с тем, что также призывают другие, а именно - мультипарадигмальный подход (а не универсальный подход).
pestophagous 05
31

Вам следует взглянуть на статью Бена Мозли и Питера Маркса «Out of the Tar Pit» , доступную здесь: «Out of the Tar Pit» (6 февраля 2006 г.)

Это современная классика, в которой подробно описывается парадигма / система программирования, называемая функционально-реляционным программированием. Хотя в нем нет прямого отношения к базам данных, в нем обсуждается, как изолировать взаимодействие с внешним миром (например, с базами данных) от функционального ядра системы.

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

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

Кевин Альбрехт
источник
4
Какая отличная бумага. Ссылка, которую вы даете, не работает (временно?), Но я нашел этот документ также на shaffner.us/cs/papers/tarpit.pdf
pestophagous
2
@queque Исходная ссылка все еще мертва. Я вставил новую ссылку в ответ Кевина.
Дэвид Тонхофер
25
  1. Функциональные языки не преследуют цель оставаться без состояния, они имеют цель сделать управление состоянием явным. Например, в Haskell вы можете рассматривать монаду состояния как основу «нормального» состояния, а монаду ввода-вывода - как представление состояния, которое должно существовать вне программы. Обе эти монады позволяют (а) явно представлять действия с сохранением состояния и (б) создавать действия с сохранением состояния путем их компоновки с использованием ссылочно прозрачных инструментов.

  2. Вы ссылаетесь на ряд ORM, которые, согласно своему названию, представляют собой абстрактные базы данных как наборы объектов. По правде говоря, это не то, что представляет собой информация в реляционной базе данных! Судя по названию, он представляет реляционные данные. SQL - это алгебра (язык) для работы с отношениями в реляционном наборе данных, и на самом деле он сам по себе довольно "функциональный". Я поднимаю это, чтобы учесть, что (а) ORM - не единственный способ сопоставить информацию о базе данных, (б) что SQL на самом деле является довольно хорошим языком для некоторых проектов баз данных, и (в) что функциональные языки часто имеют реляционную алгебру. сопоставления, которые раскрывают возможности SQL идиоматическим (а в случае Haskell - с проверкой типов) способом.

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

Дж. Абрахамсон
источник
15

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

Из вашего вопроса кажется, что ваша основная проблема заключается в том, чтобы найти хороший способ абстрагироваться от данных на основе записей, которые вы возвращаете из своей базы данных, во что-то, что является lisp-y (lisp-ish?) Без необходимости писать много SQL код. Это больше похоже на проблему с инструментами / библиотеками, чем на проблему с языковой парадигмой. Если вы хотите делать чистый FP, возможно, вам не подходит язык Lisp. Common lisp, похоже, больше связан с интеграцией хороших идей из oo, fp и других парадигм, чем с чистым fp. Возможно, вам стоит использовать Erlang или Haskell, если вы хотите пойти по пути чистого FP.

Я действительно думаю, что идеи «псевдо-оо» в шепелявке тоже имеют свои достоинства. Вы можете попробовать их. Если они не подходят так, как вы хотите работать с вашими данными, вы можете попробовать создать слой поверх Weblocks, который позволит вам работать с вашими данными так, как вы хотите. Это может быть проще, чем писать все самому.

Отказ от ответственности: я не эксперт по Лиспу. Меня больше интересуют языки программирования, и я играл с Lisp / CLOS, Scheme, Erlang, Python и немного с Ruby. В повседневной жизни программирования я все еще вынужден использовать C #.

Mendelt
источник
3
Erlang - это не чистый FP по любому определению этого слова. Вы пишете erlang, создавая множество процессов (все выполняющиеся параллельно), которые отправляют друг другу сообщения, как объекты, скажем, в smalltalk. Так что с точки зрения высокого уровня это может даже показаться несколько оригинальным и определенно имеет состояние. Если вы увеличите масштаб (в коде, выполняемом внутри процесса), он выглядит более функциональным, но все еще не является чисто функциональным, поскольку вы можете отправлять сообщения (и, следовательно, выполнять ввод-вывод и т.д.) из любого места, где хотите, а также сохранять " глобальные переменные »(глобальные для процесса, внутри чего-то, что называется« процессный диктат ».)
Амадиро
@Amadiro "определенно имеет состояние". Конечно, есть. У нас всегда есть государство. Проблема не в состоянии, это изменчивое состояние . Хорошая часть «функционального программирования» - это избавление от хрупких представлений состояния (например, экземпляров объектов, которые изменяются другими процессами, пока мы держим на них ссылку, нетранзакционным способом, чтобы добавить оскорбление к травме). Erlang имеет неизменяемое состояние и соответствует этим критериям функционального программирования. Итак: базы данных любого типа никогда не являются проблемой. Обновление базы данных - проблема (см. Также неприятное утверждение в Прологе).
Дэвид Тонхофер
15

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

Если во время T в базе данных указано, что «Бобу нравится Сьюзи», и у вас была функция Like, которая принимала базу данных и лайкера, то, если вы можете восстановить базу данных в момент T, у вас есть чисто функциональная программа, которая включает базу данных. , например

# Start: Time T
likes(db, "Bob")
=> "Suzie"
# Change who bob likes
...
likes(db "Bob")
=> "Alice"
# Recover the database from T
db = getDb(T)
likes(db, "Bob")
=> "Suzie"

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

Это основная идея DatomicНапример, .

животное
источник
Ницца. Я даже не знал о Datomic. См. Также: обоснование Datomic .
Дэвид Тонхофер
12

Не за что. Существует жанр баз данных, известный как «Функциональные базы данных», из которых Mnesia , пожалуй, является наиболее доступным примером. Основной принцип заключается в том, что функциональное программирование декларативно, поэтому его можно оптимизировать. Вы можете реализовать соединение, используя List Compression Computing для постоянных коллекций, и оптимизатор запросов может автоматически решить, как реализовать доступ к диску.

Mnesia написана на Erlang, и для этой платформы доступна как минимум одна веб-платформа ( Erlyweb ). Erlang по своей сути параллелен потоковой модели без совместного использования, поэтому в определенных отношениях он поддается масштабируемым архитектурам.

ConcernedOfTunbridgeWells
источник
1
Я не думаю, что это хорошее решение. Есть и объектно-ориентированные базы данных, но обычно вы хотите подключиться к простой старой реляционной базе данных SQL.
jalf 01
4
У вас все еще есть несоответствие импеданса с объектно-ориентированными языками и базами данных во многом так же, как у вас есть несоответствие импеданса функционального SQL.
ConcernedOfTunbridgeWells,
1
@ConcernedOfTunbridgeWells Я произвольно заявляю, что это несоответствие импеданса - плод воображения людей с молотками, которым нужно, чтобы все было гвоздями. Очень тонкие слои и знание SQL могут иметь большое значение, поэтому jOOQ и аналогичные прокладки.
Дэвид Тонхофер
6

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

Идея объектно-реляционного сопоставителя, в котором вы импортируете запись базы данных как объект, а затем изменяете ее, столь же применима и полезна для функционального программирования, как и для объектно-ориентированного программирования. Одно предостережение заключается в том, что функциональное программирование не изменяет объект на месте, но API базы данных может позволить вам изменить запись на месте. Поток управления вашего клиента будет выглядеть примерно так:

  • Импортируйте запись как объект (на этом этапе API базы данных может заблокировать запись),
  • Прочтите объект и ветку на основе его содержимого, как хотите,
  • Упакуйте новый объект с желаемыми модификациями,
  • Передайте новый объект соответствующему вызову API, который обновит запись в базе данных.

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

Жареный Брайс
источник
5

Мне удобнее всего работать с Haskell. Самый известный веб-фреймворк Haskell (сравнимый с Rails и Django) называется Yesod. Похоже, у него довольно крутая, безопасная по типу, мультибэкендная ORM. Взгляните на главу о стойкости в их книге.

Хонза Покорный
источник
0

Базы данных и функциональное программирование могут быть объединены.

например:

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

               Clojure -> DBMS, Super Foxpro
                   STM -> TransactionMVCC
Persistent Collections -> db, table, col
              hash-map -> indexed data
                 Watch -> trigger, log
                  Spec -> constraint
              Core API -> SQL, Built-in function
              function -> Stored Procedure
             Meta Data -> System Table

Примечание. В последней версии spec2 спецификация больше похожа на RMDB. см .: spec-alpha2 wiki: Schema-and-select

Я выступаю за: создание реляционной модели данных поверх хеш-карты для достижения комбинации преимуществ NoSQL и RMDB. Фактически это обратная реализация posgtresql.

Утиный ввод: если он выглядит как утка и крякает, как утка, это должно быть утка.

Если модель данных clojure похожа на RMDB, средства clojure, такие как RMDB, и средства обработки данных clojure, такие как RMDB, clojure должны быть RMDB.

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

Все есть RMDB

Внедрение реляционной модели данных и программирования на основе хэш-карты (NoSQL)

Линь Пэнчэн
источник