我想編寫一些可以處理Haskell中的所有數據類型的函數(至少Data.Data中的所有Data實例)。我遇到的一個普遍問題是根據構造函數是否遞歸來選擇做什麼 - 通過遞歸構造函數我的意思是數據類型是D,並且存在構造函數C,其中一個參數是D.Generic Haskell:確定構造函數是否遞歸
我可以通過解決一個更簡單的問題來解決上述問題:給定一個數據,確定最外層的構造函數是否是遞歸的。
這裏是嘗試數1:
data B a = T | F
gIsLeafCons :: (Data a) => a -> B a
gIsLeafCons m = gfoldl (\x y -> F) (\x -> T) m
的想法是,如果構造是遞歸的,那麼我們回到˚F否則我們返回T.這第一眼的偉大工程:
gIsLeafCons 1 ==> T
gIsLeafCons ([] :: [Int]) ==> T
然而,gfoldl是多態的,所以給定樹數據類型如
data Tree a = Leaf a | Node (Tree a) (Tree a)
我們失敗了。
gIsLeafCons (Leaf 1) ==> F
其原因是(1葉)不是一個真正空構造:它有參數1,依此構造函數(\ X Y - > F)被施加。
嘗試數2:
我們可以用「葉子構造」走的是一個所有兒童評估爲F.這是一個略有改善:
gIsLeafByChild (Leaf 1) ==> T
但是,如果葉子舉行不同的遞歸結構;這將再次失敗。
gIsLeafByChild (Leaf (Leaf 1)) ==> F
我真的想停在第一個「葉構造」,但gfoldl的多態特性使得它似乎很難做到這一點,因爲上面看到的。
最後,有沒有辦法來指出構造函數是否是「葉構造函數」。我目前的解決方案是讓用戶傳入一個葉構造函數列表([Constr]),然後檢查構造函數是否是其中之一。但是,如果能夠自動推斷出該列表中是否有東西,那就太好了。
你會做什麼,如果有不同的數據類型的兩個相互遞歸的構造函數?數據T = T Int F;數據F = F Int T',例如。這可以合理地被認爲是遞歸或「葉」。 – amalloy 2014-10-16 18:01:48
@amalloy:這是一個很好的問題。我沒有想太多這個,但我會說,如果摺疊構造函數需要調用摺疊,構造函數是遞歸的。在上述foldT t f(T n a)= t n(foldF f t a)中; foldF f t(F n a)= f n(foldT t f a)。所以我會稱它們都是遞歸的。這是合理的嗎? – 2014-10-16 18:31:15
您可能對Transformers包中的'Data.Constant.Functor'中的'Constant'感興趣。 https://hackage.haskell.org/package/transformers-0.4.1.0/docs/Data-Functor-Constant.html它通常捕捉你的'B a'類型的想法,例如'B a'將會是'常量布爾a'。 – Cirdec 2014-10-16 19:17:00