2013-12-15 43 views
3

我想學習斯卡拉茲鏡頭。有沒有更好的方式來鎖定集合操作?鏈接斯卡拉斯鏡頭集操作

case class Outer(left: Inner, right: Inner) 
case class Inner(top: Int, bottom: Int) 

val left = Lens.lensu[Outer, Inner](
    (o,v) => o.copy(left = v), 
    _.left 
) 
val right = Lens.lensu[Outer, Inner](
    (o,v) => o.copy(right = v), 
    _.right 
) 
val top = Lens.lensu[Inner, Int](
    (o,v) => o.copy(top = v), 
    _.top 
) 

val leftTop = left >=> top 
val rightTop = right >=> top 

val outer0 = Outer(Inner(10,20), Inner(30, 40)) 
val outer1 = rightTop.set(leftTop.set(outer0, 11), 33) 

更新:

我有一種感覺,答案可能是使用狀態單子,雖然我不太瞭解爲什麼這似乎工作。有興趣知道是否有更好的方法。

val modifier = for{ 
    _ <- leftTop := 11 
    _ <- rightTop := 33 
} yield Unit 

modifier(outer0)._1 // = Outer(Inner(11,20),Inner(33,40)) 

回答

1

可以簡化有些國家單子版本:

(leftTop := 11) >> (rightTop := 33) exec outer0 

或者,如果你喜歡:

val modifier = (leftTop := 11) >> (rightTop := 33) 
modifier.exec(outer0) 

你的原始狀態的版本看起來有點怪異,因爲<-for聲明僅僅是撥打.flatMap的語法糖。簡化一下,leftTop := 11的結果有一個類似於State[Outer, Outer, Int]的類型,這大致相當於Outer => (Outer, Int)類型的函數。 State記錄結果的Outer部分,並將Int部分傳遞給.flatMap。由於您不關心Int結果,因此將其分配給_並忽略它。

>>做同樣的事情,這是一個.flatMap忽略它的參數,並且是一樣的文字:

(leftTop := 11) flatMap (_ => rightTop := 33) 

這樣做的結果是一個國家計算,它有一個輔助函數.exec在運行計算初始狀態(outer0)並返回最終狀態(丟棄任何結果)。

如果你想避免使用狀態,你幾乎必須按照你開始的方式去做。國家的整個觀點是在步驟之間傳遞中間結果而不明確提及它們。