我正在嘗試習慣一些基本lens功能。在嘗試介紹鏡頭之前,我從以下型別和功能開始:
import qualified Data.Set as S
data Sets = Sets {pending, placed, open :: S.Set Int}
interesting :: Sets -> [Int]
interesting = toList . pending <> placed
即,我想要掛起和放置節點的聯合,表示為一個串列(我后來在串列理解中使用結果,所以集合不方便)。
我的基本問題是:如何使用來自 的工具復制它lens?如果你對這個問題有一個很好的答案,下面的內容是可以跳過的;這是我自己對那個空間的初學者探索的記錄。
我重命名了欄位以給自己鏡頭:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
import qualified Data.Set as S
data Sets = Sets {_pending, _placed, _open :: S.Set Int}
makeLenses ''Sets
現在想重新實作interesting。當然,沒有鏡頭 ( toList . _pending <> _placed)并不難,但我正在努力掌握鏡頭的竅門,這似乎是一個有用的練習。
我的第一個想法是,pending和placed仍然是兩個函式,我仍然想對與結果相關但實際上并不相關的東西進行逐點映射,所以pending <> placed至少應該看起來很有趣:
*Main Data.Foldable> :t pending <> placed
pending <> placed
:: (Semigroup (f Sets), Functor f) =>
(S.Set Int -> f (S.Set Int)) -> Sets -> f Sets
現在,這種型別是什么,我可以對其執行哪些操作?它看起來有點像一個受約束的Getter,也許,即使我無法讓 GHCI 通過撰寫:t pending <> placed :: Getter _s _a. 我們可以嘗試將它傳遞給view任何需要 a Getter,并且有效的方法:
*Main Data.Foldable> :t view (pending <> placed)
view (pending <> placed) :: MonadReader Sets m => m (S.Set Int)
好吧,這是 的概括Sets -> S.Set Int,我可以將其組合起來toList以找回我必須開始的內容:
*Main Data.Foldable> :t toList . view (pending <> placed)
toList . view (pending <> placed) :: Sets -> [Int]
But this doesn't seem very satisfying: it's just what I had before but with an extra view call, and I don't feel like I used any of the power of lenses here. I also don't really understand what pending <> placed "means" in this context.
The other thing I considered is that what I want to do is a lot like foldMap, and what I have is kinda like a Getter, so I should be able to do some foldMapOf.
*Main Data.Foldable> :t foldMapOf (pending <> placed)
foldMapOf (pending <> placed)
:: Semigroup r => (S.Set Int -> r) -> Sets -> r
This needs one more argument, and the obvious candidate is toList:
*Main Data.Foldable> :t foldMapOf (pending <> placed) toList
foldMapOf (pending <> placed) toList :: Sets -> [Int]
This has the right type, but alas different semantics: it uses <> after the conversion to [Int] rather than on the underlying Set Ints, so if _pending and _placed share elements, we get duplicate copies in the result.
Another thing I could do would be to use toListOf (pending <> placed), yielding a list of sets, and then use ordinary non-lens functions to mush those together:
*Main Data.Foldable> :t toList . mconcat . toListOf (pending <> placed)
toList . mconcat . toListOf (pending <> placed) :: Sets -> [Int]
This works, but is rather ugly and seems to miss the point.
So, do lenses give me any better tools here? Have I chosen a problem so simple that I can't see the advantage of lenses over simple record-field getters?
uj5u.com熱心網友回復:
我是否選擇了一個如此簡單的問題,以至于我看不到鏡頭相對于簡單的記錄場吸氣劑的優勢?
我想說的主要是這樣。直觀地說,它pending <> placed是一個只讀目標:沒有明智的方法可以將兩個集合的并集作為Sets結構的一部分進行修改,因為它實際上并不對應于其中的任何內容。這就是為什么你最終會得到一個 getter,正如你所發現的,它本質上是一個函式。
*Main Data.Foldable> :t pending <> placed pending <> placed :: (Semigroup (f Sets), Functor f) => (S.Set Int -> f (S.Set Int)) -> Sets -> f Sets現在,這種型別是什么,我可以對其執行哪些操作?它看起來有點像一個受約束的 Getter,也許,即使我無法讓 GHCI 告訴我約束是什么,寫 :t pending <> place :: Getter _s _a。
雖然該型別允許其他一些不太相關的東西,但您真正想要的是f ~ Const (S.Set Int),這使得鏡頭上的 mappend 實際上 mappend 檢索到的集合。專攻Const確實會給你一個吸氣劑,或者,挑剔,一個Getting. :t對此稍有幫助:
ghci> :t pending <> placed :: Getting _ _ _
<interactive>:1:34: error:
? Found type wildcard ‘_’ standing for ‘S.Set Int’
To use the inferred type, enable PartialTypeSignatures
? In the third argument of ‘Getting’, namely ‘_’
In the type ‘Getting _ _ _’
In an expression type signature: Getting _ _ _
<interactive>:1:32: error:
? Found type wildcard ‘_’ standing for ‘Sets’
To use the inferred type, enable PartialTypeSignatures
? In the second argument of ‘Getting’, namely ‘_’
In the type ‘Getting _ _ _’
In an expression type signature: Getting _ _ _
<interactive>:1:30: error:
? Found type wildcard ‘_’ standing for ‘_’
Where: ‘_’ is a rigid type variable bound by
the inferred type of
it :: Semigroup _ => Getting _ Sets (S.Set Int)
at <interactive>:1:1
To use the inferred type, enable PartialTypeSignatures
? In the first argument of ‘Getting’, namely ‘_’
In the type ‘Getting _ _ _’
In an expression type signature: Getting _ _ _
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/355875.html
上一篇:型別級別集的傳遞“子集”類
