2011-01-13 22 views
8

私はちょうどFPを使い始めていますが、Scalaを使用していますが、これは最善の方法ではないかもしれません。私はちょうどそうではないだろう。私は、FPの理解において、より広いラクーナを指し示す、非常に具体的な質問を持っています。FPでPOSTを処理するにはどうすればいいですか?

WebアプリケーションがGETリクエストを処理している場合、ユーザーはWebサイトに既に存在する情報が必要です。アプリケーションは何らかの方法でデータを処理しフォーマットするだけで済みます。 FB方法は明らかです。

WebアプリケーションがPOSTリクエストを処理しているとき、ユーザーはサイトに保持されている情報を変更する必要があります。本当に、情報は通常アプリケーション変数に保持されていません。データベースやフラットファイルに格納されていますが、私は FPが正しくないと感じています。

静的データの更新をFP言語で処理するパターンはありますか?

私の漠然としたこの写真は、アプリケーションがリクエストと現在のサイトの状態を渡すことです。アプリケーションはそのことを行い、新しいサイト状態を返します。アプリケーションが開始されてから現在のサイト状態が変更されていない場合、新しい状態が現在の状態になり、返信がブラウザに返されます(これはClojureのスタイルのわかりにくいイメージです)。現在の状態が別のスレッドによって(変更された場合には、よく、何か他のものは...

+0

定義あたりのIOは必須です – Cine

+1

このシンクロジズムに従うかどうかを確認してください。(a)I/Oは必須です。 (b)重要でないプログラムにはI/Oが必要です。したがって、機能的なプログラムは簡単です。私はそれを信じていると言っているわけではありません、なぜ私はそれが間違っているのか分かりません。それが私の元の質問の本質です。 – Malvolio

+0

機能プログラミングとは、誰かがI/Oを行うことを意味します。 :-D – ephemient

答えて

-1

注意起こる:私はすべてのScalaを知らないので、私はただの例から構文で推測している

。ここで

マップを実施する1つの機能的な方法です:代わりに、伝統的なデータ構造の

val empty   = x =>    scala.None 
def insert(k, v, m) = x => if k == x then scala.Some(v) else m(k) 
def delete(k, m) = x => if k == x then scala.None else m(k) 
def get(k, m)  = m(k) 

、マップは単なる関数とすることができるマップからエントリを追加または削除するには、関数は既存で構成されています。新しい地図を得るためにマップする。

私もこのようなwebappsの考えが好きです。 Webアプリケーションは、要求をトランザクションに変換します。トランザクションはある状態を別の状態に変更しますが、現在の状態、過去の状態、または未知の未知の状態に適用することができます。トランザクションだけでは役に立ちません。何かをシーケンシングして、順番にそれを適用しなければなりません。しかし、要求ハンドラはそれについて全く考える必要はありません。

例として、Happstackフレームワークモデルの状態を見てみましょう。着信要求は、モナド内で実行されるハンドラにルーティングされます。部分的にはTHというマジックのおかげで、フレームワークはmoteという結果をシリアル化し、成長するトランザクションログの末尾に追加します。最新の状態を判断するには、トランザクションを順番に適用してログファイルをステップ実行するだけです。

6

純粋なFP環境でこの種の問題に対処する1つの方法は、Haskellのようなモナド(IOやStateなど)です。 Cleanには "unique types"(値の参照を1つだけ許可する)のような選択肢があります。

ここGROKにあまりありません:あなたは可変状態を持っている場合、あなたはそれへのアクセスを制限するために何とか必要があるが、その状態のすべての変更がの「新しいバージョン」として知覚されるような方法で、プログラムの残りの部分からのその構造。例えば。あなたはハスケルのIOを「世界の残りの部分」と考えることができますが、それに時計の種類が付いています。もしあなたがIOで何かをするなら、時計は動くので、同じIOを再び見ることはありません。あなたがそれに触れる次回のIOは、あなたがしたことがすべて起こった別の世界です。

実際には、映画の中で物事が「変化する」ことを「見る」ことができます。それは絶対的な見方です。しかし、もしあなたが映画をつかまえれば、 "変化"の痕跡がなく、小さな不変の絵のストリングだけが見えます - それがFPの視点です。両方のビューは、それぞれ独自のコンテキストで有効で「真」です。

ただし、Scalaを使用している場合、に変更可能な状態があります。問題はありません。 Scalaはこれを特別に扱う必要はありません。使用するのに間違いはありません(ただし、 "不純な"スポットはできるだけ小さくしておくのが良いスタイルです)。

+0

マルチスレッド環境では、これらのモナドを実際のI/Oにどのように変換すればよいですか? (あなたが持っているならば、ちょうど私にリンクを与えることを気軽に)。はい、私はScalaが私にFPパラダイムから逃れることを許していることを理解しますが、私は欲しくない、私はさらに進んで行きたい。 – Malvolio

+0

私は間違いなくこれの専門家ではないが、これはFRPで最も有望な技術だと思われる: http://en.wikipedia.org/wiki/Functional_reactive_programming – Landei

3

答えはモナドです。具体的には、状態とioのモナドはこれを完全に処理します。プログラムで変更可能である単一のものが存在しないことを

trait Monad[A] { 
    def flatMap[B, T[X] <: Monad[X]](f: A => T[B]): T[B] 
} 

class State[A](st: A) extends Monad[A] { 
    def flatMap[B, T[X] <: Monad[X]](f: A => T[B]): T[B] = f(st) 
    def map[B](f: A => B): State[B] = new State(f(st)) 
} 

object IO extends Monad[String] { 
    def getField = scala.util.Random.nextString(5) 
    def getValue = scala.util.Random.nextString(5) 
    def fieldAndValue = getField + "," + getValue 
    def flatMap[B, T[X] <: Monad[X]](f: String => T[B]): T[B] = f(fieldAndValue) 
} 

object WebServer extends Application { 
    def programLoop(state: State[Map[String, String]]): State[Map[String, String]] = programLoop(
     for { 
      httpRequest <- IO 
      database <- state 
     } yield database.updated(httpRequest split ',' apply 0, httpRequest split ',' apply 1) 
    ) 

    programLoop(new State(Map.empty)) 
} 

注意、および、しかし、それは表現(「データベース」を変更していきます。ここでは

は、これが機能する方法の例です不変のMapによって)メモリが不足するまで実行します。 IOオブジェクトは、ランダムに生成されたキーと値のペアを供給することによって仮想のHTTP PUT要求をシミュレートします。

これは、HTTP PUTを処理しデータベースを供給する機能的なプログラムの一般的な構造です。データベースを不変オブジェクトと考えてください。データベースを更新するたびにという新しいデータベースオブジェクトが得られます。

+0

しかし、あなたは多くのタイプのリクエストと多くのタイプのリソースといくつかの抽象レイヤーを持っているとどうなりますか? – IttayD

+0

@IttayDあなたは問題として何を見ていますか?非機能環境では、リクエストを応答に変換する関数の連鎖とネストがあります。それは逆さにするかもしれない - コードは返すのではなく応答を提供するものを呼び出しますが、Lift、BlueEyes、Unfiltered、Scalatra、Circumflexなどを参照してください。ここでは、(状態、要求)から(状態、応答)が必要です。実際、BlueEyesはちょっと、「コンテキスト」を渡すことでこれを行います。 –

3

ウェブ上の状態の非同期の変更に最も慣用FPの答えは、私が推測するcontinuation-passing style次のとおりです。現在実行中の関数は、その呼び出し元の現在の計算から生じた引数で「次のアクション」、と継続機能を提供しています(命令番号の返信の類似)は状態通過を表します。

ウェブに適用すると、サーバーがユーザーからの入力を必要とするときは、セッションごとの継続を保存するだけです。ユーザーが何らかの情報で応答すると、保存された継続が復元され、提供された入力が何らかの計算によって処理され、次に継続の値として返されます。

継続ベースのWebアプリケーションフレームワークhereの例があります。アイデアの詳細な高レベルの書き出しはhereです。このhereを実装する多数のリソースとFPアプリケーションも参照してください。

コンティニュエーションはsupported in Scala as of 2.8であり、継続的に通過するスタイルは200-300 LoC example of a webserverです。

関連する問題