假設我想創建一個 「光」 爲MaybeT m a
內容:通用透鏡狀像映射並遍歷
maybeTContents = _Wrapped .
something
. _Just
是否有這樣的something
?
maybeTContents
將例如爲Traversal
當m
是[]
, 但只有當Setter
是m
(->) Int
。
用法示例:
假設我想創建一個 「光」 爲MaybeT m a
內容:通用透鏡狀像映射並遍歷
maybeTContents = _Wrapped .
something
. _Just
是否有這樣的something
?
maybeTContents
將例如爲Traversal
當m
是[]
, 但只有當Setter
是m
(->) Int
。
用法示例:
一種方法是讓自己的類,讓右視覺的類型您使用:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
class Ocular f t where
optic :: LensLike f (t a) (t b) a b
instance Settable f => Ocular f ((->) a) where
optic = mapped
instance Functor f => Ocular f Identity where
optic = _Wrapped
instance Applicative f => Ocular f [] where
optic = traversed
instance Applicative f => Ocular f Maybe where
optic = _Just
這將給予(->) s
二傳手和[]
等
> let maybeTContents = _Wrapped . optic . _Just
> MaybeT [Just 1, Nothing, Just 2] ^.. maybeTContents
[1,2]
> runMaybeT (MaybeT (Just . ('e':)) & maybeTContents %~ ('H':)) "llo"
Just "Hello"
你也可以寫一個實例MaybeT
和ReaderT
:
instance (Applicative f, Ocular f m) => Ocular f (MaybeT m) where
optic = _Wrapped . optic . _Just
instance (Ocular f m, Settable f) => Ocular f (ReaderT r m) where
optic = _Wrapped . mapped . optic
> MaybeT [Just 1, Nothing, Just 2] ^.. optic
[1,2]
> runReaderT (ReaderT (\r -> [r,r+1]) & optic *~ 2) 1
[2,4]
請注意,Identity
的情況僅爲Lens
,而非Iso
。爲此,您需要在Ocular
類中包含Profuctor
。您也可以編寫一個允許索引鏡頭和遍歷的版本。
這個更好的版本是爲約束使用一個類關聯類型,w /一個證明你的光學元件至少是一些最小光學級別的元件。很難做400字符評論,我無法格式化代碼,但'類HasFoo e其中{類型T e :: * - >約束; foo':: T e f => LensLike'f e Foo; fooIsalens :: T e f: - Functor f}'然後你可以通過操作約束來定義'foo :: HasFoo e => Lens'e Foo'。在單形態的情況下,你可以像以前一樣繼續進行操作,但現在你可以合理地使用'foo'參數化地將每個中間'f'漏入你的簽名中。 –
@EdwardKMETT - 這是我到目前爲止: https://github.com/lamdu/lamdu/blob/master/bottlelib/Data/Traversable/Generalized.hs 幾乎和你所描述的一樣,但用'Functor f'在鏡頭的約束,而不是'fooIsALens' – yairchu
@愛德華凱特我已經去了,這是你的意思? http://lpaste.net/168558你不能使用類型同義詞來獲得類似的效果(即'SetFoo = HasFoo Identity')嗎? – cchalmers
是的!首先要注意的是something
必須有Setter
(並且不失一般性,Setter'
)。至於什麼類型讓我們使用洞。
maybeTContents :: Setter' (MaybeT m a) a
maybeTContents =
_Wrapped . _ . _Just
GHC告訴我們,它想要類型Settable f => (Maybe a -> f (Maybe a)) -> (m (Maybe a) -> f (m (Maybe a))
的洞。
隨着Hackage之旅,我們認識到這種類型爲Setter' (m (Maybe a)) (Maybe a)
。因此,修正u ~ Maybe a
,我們可以更一般地重新提出這個問題:是否存在一個與Setter' [u] u
存在和Setter' (Reader u) u
相一致的存在?
但是,因爲這兩個[]
和Reader
有仿函數情況下,我們可以把一個二傳手mapped
,the setter heard around the world的絕對經典。 mapped
的類型爲mapped :: Functor f => Setter (f a) (f b) a b
- 事實證明,當您有一個可用的函數實例時,mapped = sets fmap
是遵從所有設置法則的值。
我們可以在這裏的行動看到這一點:
% stack ghci
GHCi, version 7.10.3: http://www.haskell.org/ghc/ :? for help
Ok, modules loaded: none.
λ> import Control.Lens
λ> import Control.Monad.Trans.Maybe
λ> import Control.Monad.Trans.Reader
λ> MaybeT [Just 1, Nothing, Just 2, Nothing, Just 3] & _Wrapped . mapped . _Just .~ 100
MaybeT [Just 100,Nothing,Just 100,Nothing,Just 100]
λ> data A = A
λ> data B = B
λ> :t MaybeT (ReaderT (\r -> Identity (Just A)))
MaybeT (ReaderT (\r -> Identity (Just A)))
:: MaybeT (ReaderT r Identity) A
λ> :t MaybeT (ReaderT (\r -> Identity (Just A))) & _Wrapped . mapped . _Just .~ B
MaybeT (ReaderT (\r -> Identity (Just A))) & _Wrapped . mapped . _Just .~ B
:: MaybeT (ReaderT r Identity) B
,因爲那裏可ReaderT
沒有Show
比如我能做的最好說明的是,二傳手工作是產生兩個品牌spankin'新類型A
和B
。
這個問題很好,我認爲它是lens
包背後動機的核心。從Traversable
世界給定fmapDefault
,您可以修復遍歷爲Identity
來編寫over
。然後你可以寫出over
,sets
的倒數,例如over . sets = id
和sets . over = id
。然後我們不得不得出結論,mapped = sets fmap
是一個自然的設置者,它遵循我們想要的設置者的法則,其中最重要的是mapped . mapped . mapped
與(.)
合成。緊接着是lens
的其餘部分。要做到這一點
使用'something = mapped',你可以做' MaybeT [只有1,沒有,只有2]^.. maybeTContents'? (剛剛更新我的問題有這個例子) – yairchu
@yairchu是的。所有制定者也是遍歷的。 (請參閱鏡頭Hackage頁面上那個巨大的UML圖。) – hao
它似乎不起作用。 ':t MaybeT [只'a',沒什麼,只'b']^.. _包裹。映射。 _Just'導致錯誤'No set for(Settable(Const(Data.Monoid.Endo [Char])))由於使用'mapped''而產生... – yairchu
基於以前的答案几個例子:
> MaybeT [Just 1, Nothing, Just 2] ^.. _Wrapped . traverse . _Just
[1,2]
> runMaybeT (MaybeT (Just . ('e':)) & _Wrapped . collect . _Just %~ ('H':)) "llo"
Just "Hello"
即對於Traversal
/Fold
,我們使用traverse
,對於Setter
:collect
(或mapped
)。
不幸的是Traversable
和Distributive
沒有所有實例: (->) r
不Traversable
和Const
不Distributive
(他們不能,AFAICS)。
如果你想到這一點,你會發現它是有道理的。 Traversal
和Distributive
是雙向的,我們使用collect
來「去其他方向」traverse
。
@haoformayor關於標題編輯 - 'MaybeT'只是我正在尋找的一個例子。希望新的標題更好地解釋我在找什麼 – yairchu
另請參閱https://github.com/ekmett/lens/wiki/Varying-lens-properties-by-instance – phadej