2016-02-14 39 views
0

我有以下的Haskell類型可組合倫辛

import Control.Lens 
import Data.Map.Lens 
import qualified Data.Map as M 

type RepoStats = M.Map String (M.Map String RepoStat) 
data RepoStat = RepoStat { 
    _full_name :: String, 
    _bug_count :: Maybe Int, 
    _commit_count :: Maybe Int 
    } 
    deriving (Generic, Show, Eq, Read) 
makeLenses ''RepoStat 

我希望能夠抽象出嵌套檢查值,並給予默認:

makeStat name bug commit = 
    RepoStat 
    { _full_name = name 
    , _bug_count = Just bug 
    , _commit_count = Just commit 
    } 

getRepoStat :: String -> String -> (RepoStat -> Identity RepoStat) -> RepoStats -> Identity RepoStats 
getRepoStat k1 k2 = at k1 . non (M.empty) . at k2 . non (makeStat k2 0 0) 

fakeMap = M.empty :: RepoStats 
setBug = fakeMap & (getRepoStat "a" "b") . bug_count ?~ 4 
getBug = fakeMap ^. (getRepoStat "a" "b") . bug_count 

setBug編譯和作品,但getBug不。

test/Spec.hs:65:21: Couldn't match type ‘Identity RepoStats’ … 
        with ‘Const RepoStat RepoStats’ 
    Expected type: Getting RepoStat RepoStats RepoStat 
     Actual type: (RepoStat -> Identity RepoStat) 
        -> RepoStats -> Identity RepoStats 
    In the second argument of ‘(^.)’, namely ‘(getRepoStat "a" "b")’ 
    In the expression: fakeDb ^. (getRepoStat "a" "b") 
Compilation failed. 

是否有可能以這種方式抽象出一個鏡頭?

回答

1

是很有用的只是刪除類型簽名:

getRepoStat k1 k2 = at k1 . non M.empty . at k2 . non (makeStat k2 0 0) 

現在我們可以看看推斷類型與:t getRepoStat在ghci中。

這是一個有點亂,主要是因爲at超載:

getRepoStat 
    :: (Functor f, At m, IxValue m ~ M.Map String RepoStat) => 
    Index m -> String -> (RepoStat -> f RepoStat) -> m -> f m 

我們可以發現,雖然我們返回Lens',我們還可以限制鏡頭到RepoStats背景:

getRepoStat :: String -> String -> Lens' RepoStats RepoStat 
getRepoStat k1 k2 = at k1 . non M.empty . at k2 . non (makeStat k2 0 0) 
3

當然是。您爲getRepoStat指定的類型簽名是其類型簽名,作爲setter。如果你希望能夠在其整個通用使用它作爲一個lens那麼類型簽名應該是

getRepoStat :: Functor f => String -> String -> (RepoStat -> f RepoStat) -> RepoStats -> f RepoStats 
-- same definition 

這可能是推斷類型的getRepoStat了。