這個問題是關於How to pattern match against a typeclass value?的後續。如何模式匹配其實例是遞歸數據類型的類型類型?
我開始了一階邏輯的寵物項目,並決定使用Haskell來達到此目的。我的第一個障礙是定義一個「一階邏輯的公式」,因此數據類型:
data Formula v = Belong v v -- x in y
| Bot -- False
| Imply (Formula v) (Formula v) -- p -> q
| Forall v (Formula v) -- forall x, p
但是,我不願意基礎上,實現細節來編寫代碼,而寧願抽象掉的細節,情況下,我改變了主意,或在情況下,我想用另一種實現重複使用的功能,因此,類型類:
class FirstOrder m where
belong :: v -> v -> m v
bot :: m v
imply :: m v -> m v -> m v
forall :: v -> m v -> m v
asFormula :: m v -> Formula v
我已經添加了最後一個函數asFormula
爲了使用ViewPatterns
(如上面的鏈接提示),以便能夠對此類型類型的值進行模式匹配。
現在假設我想要定義一個簡單的函數:
subst :: (FirstOrder m) => (v -> w) -> m v -> m w
其中替換變量的公式中作爲每一個給定的映射f::v -> w
(感覺fmap
),所以式belong x y
被映射到belong (f x) (f y)
等,然後使用ViewPatterns
:
subst f (asFormula -> Belong x y) = belong (f x) (f y)
到目前爲止好...
然而,當試圖寫subst f p->q = (subst f p) -> (subst f q)
:
subst f (asFormula -> Imply p q) = imply (subst f p) (subst f q)
我得到一個類型的錯誤,其未來想它非常有意義:模式匹配結合p
和q
來,而不是期望的類型Formula v
類型的元素m v
。
現在我可以看到問題了,甚至可以想辦法通過在類型類中添加fromFormula
函數來轉換回m v
類型,但我認爲這從性能角度來看是瘋狂的(就像asFormula
一樣瘋狂),爲了保持代碼的通用性,付出巨大的代價。
因此,我現在試圖通過結構遞歸來定義一個簡單的函數,它是一個自由代數(遞歸數據類型),但是我希望將實現細節抽象出來(並且將類代碼寫入類型類型而不是數據類型)是讓我陷入似乎不可能的境地。
有沒有出路,或者我應該忘記抽象和使用遞歸數據類型?
這對您的項目可能是巨大的矯枉過正,但如果它是您正在尋找的抽象DSL(並且看起來像您),那麼請不要再進一步:http://okmij.org/ftp/tagless-final/ TaglessStaged/beyond.pdf。你可以在這裏看到一個功能完整的示例[https://github.com/cpeikert/Lol/tree/applicative-alchemy-env-in-interpreter/alchemy/Crypto/Alchemy]。 – crockeea
@crockeea這篇文章看起來很棒謝謝你。即使是過度殺傷,這也是我喜歡閱讀的東西。一定會檢查代碼。 –
爲什麼你說服自己,你首先需要你的FirstOrder類呢? –