2015-12-22 53 views
5

我看着西蒙佩頓瓊斯談Control.Lens,他表明,鏡頭和LensR這裏定義的是同構:Control.Lens:穿越同構到toListOf及以上

type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t 

data LensR s t a b = LensR { 
    viewR :: s -> a, 
    setR :: b -> s -> t 
} 

我想與遍歷相同:

type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t 

data TraversalR s t a b = TraversalR { 
    toListOfR :: s -> [a], 
    overR :: (a -> b) -> s -> t 
} 

newtype CL a b = CL { getCL :: [a] } -- ConstantList 

instance Functor (CL a) where 
    fmap _ (CL xs) = CL xs 

instance Applicative (CL a) where 
    pure _ = CL [] 
    (CL xs) <*> (CL ys) = CL (xs ++ ys) 


travToTravR :: Traversal s t a b -> TraversalR s t a b 
travToTravR tr = TraversalR { 
    toListOfR = getCL . tr (CL . pure), 
    overR = \f -> runIdentity . tr (Identity . f) 
} 

但我被卡住了travRToTrav。這是我能拿出最好的:

travRToTrav :: TraversalR s t a b -> Traversal s t a b 
travRToTrav trR a2fb s = (\bs-> overR trR magic s) <$> f_bs 
    where as = toListOfR trR s 
     f_bs = sequenceA . map a2fb $ as 
     magic = undefined 

這裏,魔法:: A - > B,但我不能讓一般的功能(A - > B)。相反,我可以通過做一個部分函數來作弊:我知道函數應該返回什麼類型的可以遍歷的值。所以我可以從as和bs中創建一個關聯列表,然後從中創建一個部分函數。

這是行不通的?如果是這樣,請告訴我有更好的辦法!

或者我選擇了TraversableR的錯誤形式,而實際上沒有同構?

感謝您的任何建議。


編輯:

所以感謝安德拉斯·科瓦克斯我現在認爲,TraversalR應該是這樣的:

data TraversalR s t a b = TraversalR { 
    toListOfR :: s -> [a], 
    setListR :: [b] -> s -> t 
} 

然後travRToTrav非常相似lensRToLens:

travRToTrav :: TraversalR s t a b -> Traversal s t a b 
travRToTrav trR a2fb s = (`setL` s) <$> f_bs 
    where as = toListOfR trR s 
     f_bs = sequenceA . map a2fb $ as 
     setL = setListR trR 

但是,那麼,如何在travToTravR中定義setListR?基本上,索引遍歷如何工作?

+0

'TraversalR'似乎不好。使用'Traversal',你可以做有狀態的遍歷和e。 G。用每個'a'的位置索引替換。用'(a - > b) - > s - > t',這是不可能的。 –

+0

噢好 - 我沒有意識到。 TraversalR應該是什麼樣子?你認爲呢? – RhubarbAndC

+1

'overR :: [b] - > s - > t'會使'TraversalR'與['biplate']非常相似(https://hackage.haskell.org/package/uniplate-1.6.12/docs/Data -Generics-Uniplate-Operations.html#t:Biplate),所以這可能值得一試。 –

回答

2

經過與AndrásKovács的討論後,我發現了一個很好的簡單答案:我們需要狀態monad,這是一個應用函子。這裏是整個同構:

type Traversal s t a b = forall f. Applicative f => (a -> f b) -> (s -> f t) 

data TraversalR s t a b = TraversalR { 
    toListOfR :: s -> [a], 
    setListR :: [b] -> s -> t 
} 

newtype CL a b = CL { getCL :: [a] } -- ConstantList 

instance Functor (CL a) where 
    fmap _ (CL xs) = CL xs 

instance Applicative (CL a) where 
    pure _ = CL [] 
    (CL xs) <*> (CL ys) = CL (xs ++ ys) 

collectBs :: State [b] b 
collectBs = state $ \xs -> case xs of []  -> error "Too few bs" 
             (y:ys) -> (y,ys) 

travToTravR :: Traversal s t a b -> TraversalR s t a b 
travToTravR tr = TraversalR { 
    toListOfR = getCL . tr (CL . pure), 
    setListR = \bs s -> evalState (tr (const collectBs) s) bs 
} 

travRToTrav :: TraversalR s t a b -> Traversal s t a b 
travRToTrav trR a2fb s = (`setL` s) <$> f_bs 
    where as = toListOfR trR s 
     f_bs = sequenceA . map a2fb $ as 
     setL = setListR trR