2017-05-03 70 views
4

我正在玩一個可擴展記錄庫,而且我想要編寫一個函數field,根據Symbol密鑰是否在密鑰列表中,它可以作爲LensTraversal運行。該類型的家庭給出:類型系列不能返回RankN類型 - 解決方法或替代方法?

type family LensOrTraversal key keys s t a b where 
    LensOrTraversal key '[] s t a b = 
     Traversal s t a b 
    LensOrTraversal key (key =: val ': xs) s t a b = 
     Lens s t a b 
    LensOrTraversal key (foo =: bar ': xs) s t a b = 
     LensOrTraversal key xs s t a b 

此代碼給我一個錯誤:

/home/matt/Projects/hash-rekt/src/Data/HashRecord/Internal.hs:433:5: 
error: 
    • Illegal polymorphic type: Traversal s t a b 
    • In the equations for closed type family ‘LensOrTraversal’ 
     In the type family declaration for ‘LensOrTraversal’ 

理想情況下,我希望能夠爲這兩個鏡頭和遍歷重用field名字,因爲它會允許你寫

>>> let testMap = empty & field @"foo" .~ 'a' 
>>> :t testMap 
HashRecord '["foo" =: Char] 
>>> testMap ^. field @"foo" 
'a' 
>>> testMap ^. field @"bar" 
Type error 
>>> testMap ^? field @"bar" 
Nothing 

它遵循共同的lens成語。我可以提供一個我想要的fieldTraversal函數,但如果可能的話,我寧願超載名稱field。你將如何解決這種類型家庭的限制?

+0

[使用RankNTypes和TypeFamilies的非法多態或限定類型]可能重複(http://stackoverflow.com/questions/13846284/illegal-polymorphic-or-qualified-type-using-rankntypes-and-typefamilies) –

+0

@ AntalSpector-Zabusky也許是相關的,但這絕對不是重複的。 – leftaroundabout

回答

4

鏡頭已經遍歷,只有它的秩2量詞不使用全約束的(它僅僅需要Functor,不Applicative)。

type Lens s t a b  = ∀ f . Functor f  => (a -> f b) -> s -> f t 
type Traversal s t a b = ∀ f . Applicative f => (a -> f b) -> s -> f t 

正是在這個約束的水平,你應該介紹一下你的家庭類型:

import GHC.Exts (Constraint) 
type family FieldOpticConstraint key keys :: (* -> *) -> Constraint where 
    FieldOpticConstraint key '[] = Applicative 
    FieldOpticConstraint key (key =: val ': xs) = Functor 
    FieldOpticConstraint key (_ ': xs) = FieldOpticConstraint key xs 

然後field不應該產生LensOrTraversal,但總是一個自定義的秩2的簽名與約束由類型家庭決定。

+0

不錯!如果只有我們有暗示約束,我們可以表達漂亮的東西,比如「至少必須是一個」遍歷「。後來我問了這樣的想法。你有沒有明確的字典操作來表達概念的棘手方法? – dfeuer

+0

唷,不知道。我懷疑如果我們試圖從任意多態類型獲得這樣的約束,它會打開一些蠕蟲。這是甚至可以決定的嗎? – leftaroundabout

+0

不錯!這解決了我的問題。現在,我只需要弄清楚如何在價值水平上處理這些信息...... – ephrion