2016-08-30 50 views
0

我剛剛開始學習Scala時開始了我的FP旅程。在scala中處理狀態的不可變方式

現在需要在未過濾的Web應用程序中保留List[String]。當POST請求被髮送到端點時,應該從文件更新列表。當GET請求發送到同一端點時,將使用該列表。

現在,我試圖避免使用var保存列表。我知道有時我們必須使用var,但只是好奇,有沒有一種優雅的方式來處理這種情況。我試過使用scalaz.State Iterator和Steam。但是因爲我不知道如何將當前不可變狀態傳遞給下一個請求而陷入困境。有什麼建議嗎?

def update = State(l => { 
    retrieve(filepath) match { 
    case Success(lines) => (lines.split("[,\n\r]").toVector.map (_.trim), true) 
    case Failure(_) => { 
     log.error(s"Cannot retrieve the file.") 
     (l, false) 
    } 
    } 
}) 

def isContained(message: String) = State(l => (l, l.exists(message.contains))) 

/* assume the following get or post method will be invoked when GET or POST request is sent to the endpoint */ 

def post() = update(Vector.empty) // how can I pass the updated state to the get method 

def get(msg: String): Boolean = isContained(msg)(???)._2 

然後,我不知道我怎麼能傳遞當前狀態下訪作爲輸入,而不使用var

回答

0

沒有免費的午餐。如果你想避免可變性並避免在某處存儲狀態,你需要使用返回的值。

State只不過是一個功能A => B以上(我簡化了一點的目的),其中A是初始狀態,B是endresult

所以你的情況,該模型將看起來像:

def post(newMessage: String, state: List[String]): List[String] = { 
    newMessage :: state 
} 

def get(msg: String, state: List[String]): Boolean = { 
    state.contains(msg) 
} 

正如您在此處看到的,您需要爲每個postget提供當前狀態。帖子只是從文件中添加一條新消息(將您的業務邏輯放在此處),並返回一個新狀態。而對於get,您需要提供當前狀態,以便能夠檢索到您想要的內容。 你可以這樣改寫:

def post(newMessage: String): List[String] ⇒ List[String] = state ⇒ { 
    newMessage :: state 
} 

def get(msg: String): List[String] ⇒ Boolean = 
    _.contains(msg) 

注意,後回報你到底A ⇒ A(其中A = List[String])。

ScalaZ State給你的單子裏面鏈接的功能的理解,以及一些額外的便利(如mapgetsput等)。但實質上 - 底層模型將是相同的。

這個代碼表示更正是State做:

type YourListState = List[String] ⇒ List[String] 

    def post(newMessage: String, state: YourListState): YourListState = li ⇒ { 
    newMessage :: state(li) 
    } 

    def get(msg: String, state: YourListState): List[String] ⇒ Boolean = { 
    state(_).contains(msg) 
    } 

這允許你結合的狀態,並提供初始值,只要你想「跑」了,不知道,你真的需要這個。