web-dev-qa-db-ja.com

データベースと関数型プログラミングは対立していますか?

私はしばらくの間ウェブ開発者でしたが、最近いくつかの関数型プログラミングの学習を始めました。他の人と同じように、私はこれらの概念の多くを私の専門的な仕事に適用するのにかなりの苦労がありました。私にとって、これの主な理由は、FPのステートレスを維持するという目標の間の矛盾が、私が行ったほとんどのWeb開発作業が非常にデータ中心のデータベースに強く結び付けられているという事実とかなり矛盾しているように見えることです。

OOPの面ではるかに生産的な開発者になったものの1つは、.NetのMyGeneration d00dads、PerlのClass :: DBI、RubyのActiveRecordのようなオブジェクトリレーショナルマッパーの発見でした。これにより、1日中insertおよびselectステートメントを書く必要がなくなり、データをオブジェクトとして簡単に操作することに集中できました。もちろん、必要なときにSQLクエリを書くこともできましたが、それ以外の場合は抽象化されました舞台裏でうまく。

今、関数型プログラミングに目を向けると、多くのFP LinksのようなWebフレームワークでは この例 のように多くのボイラープレートSQLコードを書く必要があります。 Weblocksはもう少し良いように見えますが、データの操作にOOPモデルを使用しているようで、 のようにデータベースの各テーブルにコードを手動で記述する必要がありますこの例 。いくつかのコード生成を使用してこれらのマッピング関数を記述すると思いますが、それは明らかに非LISPのようです。

(注:WeblocksまたはLinksを非常に詳しく見ていないことに注意してください。使用方法を誤解しているだけかもしれません)。

したがって、問題は、Webアプリケーションのデータベースアクセス部分(かなり大きいと思われる)、またはSQLデータベースとのインターフェイスを必要とする他の開発について、次のいずれかのパスを強制されるように思われることです。

  1. 関数型プログラミングを使用しない
  2. 多くのSQLまたはSQLに似たコードを手動で記述することを含む、煩わしい、抽象化されていない方法でデータにアクセスする
  3. 関数型言語を擬似OOPパラダイムに強制し、真の関数型プログラミングの優雅さと安定性の一部を取り除きます。

明らかに、これらのオプションはどれも理想的ではありません。これらの問題を回避する方法を見つけましたか?ここに本当に問題さえありますか?

注:私は個人的にFPフロントでLISPに最も精通しているので、例を挙げて複数のFP言語を知りたい場合、LISPはおそらく選択した優先言語

PS:Web開発の他の側面に固有の問題については、 この質問 を参照してください。

113

まず、CLOS(Common LISP Object System)が「疑似OO」であるとは言いません。ファーストクラスのオブジェクト指向です。

第二に、ニーズに合ったパラダイムを使用すべきだと思います。

関数がデータの流れであり、実際に状態を必要としない間、データをステートレスに保存することはできません。

複数のニーズが混在している場合は、パラダイムを混在させてください。ツールボックスの右下隅のみを使用するように制限しないでください。

43
Svante

これをデータベース担当者の観点から見ると、フロントエンド開発者は、オブジェクト指向または機能的ではなく、リレーショナルで使用するデータベースを使用する最も効果的な方法を検討するのではなく、データベースをモデルに適合させる方法を見つけるのに一生懸命努力していることがわかりますセット理論。これにより、一般的にパフォーマンスの低いコードが発生することがわかりました。さらに、パフォーマンスの調整が難しいコードを作成します。

データベースアクセスを検討する際には、データの整合性(すべてのビジネスルールをユーザーインターフェイスではなくデータベースレベルで実施する必要がある)、パフォーマンス、セキュリティという3つの主な考慮事項があります。 SQLは、フロントエンド言語よりも効果的に最初の2つの考慮事項を管理するために記述されています。それを行うために特別に設計されているからです。データベースのタスクは、ユーザーインターフェイスのタスクとは大きく異なります。タスクの管理に最も効果的なコードの種類が概念的に異なるのは不思議ではありませんか?

また、データベースには企業の存続に不可欠な情報が保持されます。生き残りが危ぶまれているときに、企業が新しい方法で実験する気がないのは不思議です。多くの企業は、既存のデータベースの新しいバージョンにアップグレードすることすら嫌がっています。したがって、データベース設計には固有の保守主義があります。そして、それは意図的にそうなっています。

T-SQLを記述したり、データベースの設計概念を使用してユーザーインターフェイスを作成したりしないのに、インターフェイス言語と設計概念を使用してデータベースにアクセスしようとするのはなぜですか。あなたはSQLが十分に(または新しい)空想ではないと思うので?それとも、あなたはそれに満足していないのですか?何かがあなたが最も快適に感じるモデルに合わないからといって、それが悪いか間違っているという意味ではありません。それは、正当な理由で異なること、おそらく異なることを意味します。別のタスクに別のツールを使用します。

78
HLGEM

ベン・モズレーとピーター・マークスの論文「Out of the Tar Pit」をご覧ください。 "Out of the Tar Pit"(2006年2月6日)

これは、Functional-Relational Programmingと呼ばれるプログラミングパラダイム/システムを詳述するモダンクラシックです。データベースに直接関係するわけではありませんが、システムの機能コアから外の世界(データベースなど)との相互作用を分離する方法について説明します。

また、この論文では、リレーショナルデータベースに明らかに関連するリレーショナル代数を使用して、アプリケーションの内部状態を定義および変更するシステムの実装方法についても説明します。

このペーパーでは、データベースと関数型プログラミングの統合方法に関する正確な答えは提供しませんが、問題を最小限に抑えるシステムの設計に役立ちます。

29
Kevin Albrecht
  1. 関数型言語には、ステートレスを維持するという目標はなく、状態の管理を明示的にするという目標があります。たとえば、Haskellでは、Stateモナドを「通常」状態の中心と見なすことができ、IOモナドはプログラムの外部に存在しなければならない状態の表現です。これらのモナドはどちらも許可します(a)ステートフルアクションを明示的に表し、(b)参照透過ツールを使用してステートフルアクションを構成することにより、ステートフルアクションを構築します。

  2. 複数のORMを参照します。ORMは、名前ごとに、データベースをオブジェクトのセットとして抽象化します。本当に、これはリレーショナルデータベースの情報が表すものではありません!名前ごとに、リレーショナルデータを表します。 SQLは、リレーショナルデータセットの関係を処理するための代数(言語)であり、実際にはそれ自体が非常に「機能的」です。 (a)ORMがデータベース情報をマップする唯一の方法ではないこと、(b)SQLが実際にはいくつかのデータベース設計にとって非常に素晴らしい言語であること、および(c)関数型言語にしばしばリレーショナル代数があることを考慮するためにこれを取り上げます慣用的な(そしてHaskellの場合は型チェックされた)方法でSQLの力を公開するマッピング。

ほとんどのlispsは貧しい人の関数型言語だと思います。現代の機能的な慣行に従って使用することは完全に可能ですが、それらを必要としないため、コミュニティはそれらを使用する可能性が低くなります。これにより、非常に便利なメソッドが混在することになりますが、純粋に機能的なインターフェースがデータベースを有意義に使用できる方法を確実に曖昧にします。

24
J. Abrahamson

Fp言語のステートレスな性質は、データベースへの接続に問題があるとは思いません。 LISPは非純粋な関数型プログラミング言語であるため、状態の処理に問題はありません。 Haskellのような純粋な関数型プログラミング言語には、データベースの使用に適用できる入力と出力を処理する方法があります。

あなたの質問から、あなたの主な問題は、データベースから返されるレコードベースのデータを、多くのSQLを書かずにLISP-y(LISP-ish?)に抽象化する良い方法を見つけることにあるようですコード。これは、言語パラダイムの問題というよりも、ツール/ライブラリの問題のようです。純粋なFPを実行したい場合、LISPは適切な言語ではないかもしれません。一般的なLISPは、純粋なfpよりもoo、fp、およびその他のパラダイムからの良いアイデアを統合することについてのようです。純粋なFPルートを使用したい場合は、ErlangまたはHaskellを使用してください。

LISPの「疑似oo」のアイデアにもメリットがあると思います。あなたはそれらを試してみたいかもしれません。データの操作方法に合わない場合は、Weblocksの上にレイヤーを作成して、データを希望どおりに操作できるようにします。これはすべてを自分で書くよりも簡単かもしれません。

免責事項:私はLISPの専門家ではありません。私は主にプログラミング言語に興味があり、LISP/CLOS、Scheme、Erlang、Python、および少しのRubyで遊んでいます。毎日のプログラミング生活では、C#を使用せざるを得ません。

15
Mendelt

データベースが情報を破壊しない場合、データベース全体の機能を値として操作することにより、「純粋な機能」プログラミング値と一貫した機能的な方法で操作できます。

時刻Tにデータベースが「ボブがスージーを好む」と述べ、データベースとライカーを受け入れる機能が好きだった場合、時刻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 の背後にある主要なアイデアです。

14
animal

どういたしまして。 「機能データベース」として知られるデータベースのジャンルがありますが、その中の Mnesia がおそらく最もアクセスしやすい例です。基本的な原則は、関数型プログラミングは宣言型であるため、最適化できることです。永続コレクションで List Comprehensions を使用して結合を実装でき、クエリオプティマイザーはディスクアクセスの実装方法を自動的に決定できます。

Mnesiaは Erlang で記述されており、そのプラットフォームで利用可能な少なくとも1つのWebフレームワーク( Erlyweb )があります。 Erlangは本質的にシェアードナッシングスレッドモデルと並行しているため、特定の方法でスケーラブルなアーキテクチャに適しています。

データベースは、ステートレスAPIで状態を追跡するのに最適な方法です。 RESTをサブスクライブする場合、目標は、データストア(または他のバックエンド)と対話するステートレスコードを記述し、クライアントが必要としないように透過的に状態情報を追跡することです。

データベースレコードをオブジェクトとしてインポートしてから変更するオブジェクトリレーショナルマッパーの概念は、オブジェクト指向プログラミングの場合と同様に、関数型プログラミングにも同様に適用可能で有用です。 1つの注意点は、関数型プログラミングではobjectを変更しないことですが、データベースAPIではrecordを変更できます。クライアントの制御フローは次のようになります。

  • レコードをオブジェクトとしてインポートします(データベースAPIはこの時点でレコードをロックできます)。
  • 必要に応じて、コンテンツに基づいてオブジェクトとブランチを読み取り、
  • 目的の変更を加えた新しいオブジェクトをパッケージ化し、
  • データベースのレコードを更新する適切なAPI呼び出しに新しいオブジェクトを渡します。

データベースは、変更に応じてレコードを更新します。純粋な関数型プログラミングでは、変数の再割り当てが許可されない可能性がありますプログラムのスコープ内ですが、データベースAPIではインプレース更新を引き続き許可できます。

6
Fried Brice

私はHaskellに最も満足しています。最も有名なHaskell Webフレームワーク(RailsおよびDjangoに匹敵)はYesodと呼ばれます。かなりクールで、タイプセーフな、マルチバックエンドORMを持っているようです。 永続性の章 彼らの本で。

6
Honza Pokorny

データベースと関数型プログラミングを融合できます。

例えば:

Clojureは、リレーショナルデータベース理論に基づいた関数型プログラミング言語です。

               Clojure -> DBMS, Super Foxpro
                   STM -> Transaction,MVCC
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では、specはRMDBに似ています。参照: spec-alpha2 wiki:Schema-and-select

私は、NoSQLとRMDBの利点の組み合わせを実現するために、ハッシュマップの上にリレーショナルデータモデルを構築することを推奨しています。これは、実際にはposgtresqlの逆実装です。

アヒルのタイピング:それがアヒルのように見え、カックがアヒルのように見える場合、それはアヒルでなければなりません。

clojureのデータモデルがRMDBのように、clojureの機能がRMDBのように、clojureのデータ操作がRMDBの場合、clojureはRMDBでなければなりません。

Clojureはリレーショナルデータベース理論に基づく関数型プログラミング言語です

すべてがRMDB

ハッシュマップ(NoSQL)に基づくリレーショナルデータモデルとプログラミングの実装

0
Lin Pengcheng