[英]Trying to make my typeclass/instance. GHC says “Could not deduce…”
我試圖制作一個簡單的圖形結構,並編寫了以下內容。 但是GHG引發了錯誤,因此我在那堆了。 這是我第一次進行自己的類型分類,所以也許我做錯了什么。 有人可以解釋什么地方不對嗎?
我發現了一個類似的問題,但我認為這不適用於我的情況。: 在typeclass實例中綁定類型變量時出錯
class Link l where
node :: (Node n) => l -> n
class Node n where
links :: (Link l) => n -> [l]
data (Node n) => SimpleLink n =
SimpleLink
{ simpleLinkNode :: n
} deriving (Show, Read, Eq)
instance (Node n) => Link (SimpleLink n) where
node = simpleLinkNode
data (Link l) => SimpleNode l =
SimpleNode
{ simpleNodeLinks :: [l]
} deriving (Show, Read, Eq)
instance (Link l) => Node (SimpleNode l) where
links = simpleNodeLinks
這是我收到的錯誤消息:
***.hs:13:10:Could not deduce (n ~ n1)
from the context (Node n)
bound by the instance declaration
at ***.hs:12:10-40
or from (Node n1)
bound by the type signature for
node :: Node n1 => SimpleLink n -> n1
at ***.hs:13:3-23
`n' is a rigid type variable bound by
the instance declaration
at ***.hs:12:16
`n1' is a rigid type variable bound by
the type signature for node :: Node n1 => SimpleLink n -> n1
at ***.hs:13:3
Expected type: SimpleLink n -> n1
Actual type: SimpleLink n -> n
In the expression: simpleLinkNode
In an equation for `node': node = simpleLinkNode
***.hs:21:11:Could not deduce (l ~ l1)
from the context (Link l)
bound by the instance declaration
at ***.hs:20:10-40
or from (Link l1)
bound by the type signature for
links :: Link l1 => SimpleNode l -> [l1]
at ***.hs:21:3-25
`l' is a rigid type variable bound by
the instance declaration
at ***.hs:20:16
`l1' is a rigid type variable bound by
the type signature for links :: Link l1 => SimpleNode l -> [l1]
at ***.hs:21:3
Expected type: SimpleNode l -> [l1]
Actual type: SimpleNode l -> [l]
In the expression: simpleNodeLinks
In an equation for `links': links = simpleNodeLinks
得到:“`n'不適用於足夠的類型參數”
class Link l n where
node :: Node n l => l n -> n l
class Node n l where
links :: Link l n => n l -> [l n]
得到:“循環類聲明(通過超類)”
class (Node n) => Link l n where
node :: l -> n
class (Link l) => Node n l where
links :: n -> [l]
得到:“循環類聲明(通過超類)”
class (Node n) => Link l n | l -> n where
node :: l -> n
class (Link l) => Node n l | n -> l where
links :: n -> [l]
我要實現的是有向無環圖結構,如下所示(更具體地講,為Factor圖 )。
(來源: microsoft.com )
有兩種類型的節點(白色圓圈和紅色正方形),它們僅連接到不同類型的節點,這意味着存在兩種鏈接。
我想要具有附加數據(數組)的節點和鏈接的不同版本。 我還想要“ vanilla” DAG,它只有一種類型的節點和鏈接。 但是對於遍歷它們,我只需要一個接口即可完成。
類方法的簽名
class Link l where
node :: (Node n) => l -> n
class Node n where
links :: (Link l) => n -> [l]
說,“無論何種類型的來電者的欲望, node
RESP。 links
可以生產它,只要它的成員Link
RESP。 Node
”,但執行說,只有一個有價值的特定類型的都可以生產。
它與OOP中的接口從根本上不同,在OOP中,實現由類型決定,調用者必須采用它,而調用者在這里進行決定。
您在構造函數類嘗試中遇到了種種問題。 您的類采用兩個參數,種類為kl
l
和種類為kn
n
。 (->)
的參數種類都必須是*
,即類型。 因此,要使ln
成為(->)
的良好參數, l
必須是一個類型構造函數,並接受類型kn
的參數並創建類型*
的結果,即
l :: kn -> *
現在,您嘗試使node
的結果類型為nl
,這意味着
n :: kl -> *
但在上面我們看到kl = kn -> *
,得出
n :: (kn -> *) -> *
分別 kn = (kn -> *) -> *
,這是一種無限的類型。 不允許使用無限類型,例如無限類型。 但是種類推斷僅是非常基本的實現,因此編譯器假定l
的參數為kind *
,但從nl
看到n
種類為kl -> *
,因此作為l
的參數, n
的種類錯誤,因此不適用於足夠的類型參數。
構造函數類的通常用法是單參數類
class Link l where
node :: l nod -> nod
class Node n where
links :: n lin -> [lin]
-- note that we don't have constraints here, because the kinds don't fit
instance Link SimpleLink where
node = simpleLinkNode
instance Node SimpleNode where
links = simpleNodeLinks
您必須從數據聲明中刪除DatatypeContexts
,
然后以上編譯。 不過,我認為這不會幫助您。 正如克里斯·庫克萊維奇(Chris Kuklewicz)觀察到的那樣,您的類型會追逐自己的尾巴,您將它們用作
SimpleLink (SimpleNode (SimpleLink (SimpleNode ... {- ad infinitum -})))
正如編譯器所說,對於多參數類,您不能每個都具有另一個需求,這會導致一個依賴循環(此外,在約束中,您只能將它們與一個參數一起使用,
class Node n => Link l n where ...
格式錯誤,如果周期中斷,編譯器將拒絕)。
您可以通過合並類來解決周期,
class NodeLinks l n | l -> n, n -> l where
node :: l -> n
links :: n -> l
但是您仍然會遇到類型對您沒有用的問題。
很抱歉,我對您的目標不太了解,無法提出可行的解決方案。
有人可以解釋什么地方不對嗎?
在我解釋錯誤消息之前,有一個最初的問題:多態數據類型很好,但是最后必須使用具體的類型。
隨着那種SimpleNode的* -> *
和種SimpleLinks * -> *
沒有具體的類型:
SimpleNode (SimpleLink (SimpleNode (SimpleLink (SimpleNode (...
在Haskell中,不能具有無限類型,盡管新類型和數據使您更接近:
type G0 = SimpleNode (SimpleLink G0) -- illegal
newtype G1 = G1 (SimpleNode (SimpleLink G1)) -- legal
data G2 = G2 (SimpleNode (SimpleLink G2)) -- legal
也許您需要在創建類型類之前重新考慮數據類型。
現在繼續對錯誤消息進行解釋:您的類型類Link
定義了一個功能node
class Link l where
node :: (Node n) => l -> n
該node
是一個神奇OOP工廠,鑒於類型和值l
,然后可以使任何類型的n
(由邊界Node n
)的調用者 node
的願望。 此n
與您的實例中的n
無關:
instance (Node n) => Link (SimpleLink n) where
node = simpleLinkNode
重復自己:所述n
在上面的實例中是不一樣的n
如在node :: (Node n) => l -> n
定義。 編譯器給出一個相關但新鮮的名稱n1
並給您錯誤:
`n' is a rigid type variable bound by
the instance declaration
at ***.hs:12:16
`n1' is a rigid type variable bound by
the type signature for node :: Node n1 => SimpleLink n -> n1
at ***.hs:13:3
實例中的n
取自node
函數的輸入類型(SimpleLink n)。 n1
是node
的調用方要求該神奇工廠產生的類型。 如果n和n1相同,則編譯器會很高興...但是您對類型類和實例的定義不對此加以限制,因此代碼段被拒絕。
對於SimpleLink中的錯誤,將重復類似的故事。 沒有針對此問題的解決方案。 我希望您可能需要在閱讀其他人的代碼后重新思考和重新設計,以了解實現目標的方法。
你的目標是什么? 圖形數據結構可能會發生很大變化,並且細節很重要。
我打破了堆棧溢出禮節,並添加了第二個答案以保持獨立性。 這是帶有未標記邊的二部無向圖的簡單代碼示例,可能對建模因子圖很有用:
-- Bipartite graph representation, unlabeled edges
-- Data types to hold information about nodes, e.g. ID number
data VariableVertex = VV { vvID :: Int } deriving (Show)
data FactorVertex = FV { fvID :: Int } deriving (Show)
-- Node holds itself and a list of neighbors of the oppostite type
data Node selfType adjacentType =
N { self :: selfType
, adj :: [Node adjacentType selfType] }
-- A custom Show for Node to prevent infinite output
instance (Show a, Show b) => Show (Node a b) where
show (N x ys) = "Node "++ show x ++ " near " ++ show (map self ys)
-- Type aliases for the two node types that will be used
type VariableNode = Node VariableVertex FactorVertex
type FactorNode = Node FactorVertex VariableVertex
data FactorGraph = FG [VariableNode] [FactorNode] deriving (Show)
v1 = N (VV 1) [f1,f2]
v2 = N (VV 2) [f2]
v3 = N (VV 3) [f1,f3]
f1 = N (FV 1) [v1,v3]
f2 = N (FV 2) [v1,v2]
f3 = N (FV 3) [v3]
g = FG [v1,v2,v3] [f1,f2,f3]
在Chris Kuklewicz(http://stackoverflow.com/a/11450715/727827)的提示下,我首先得到了想要的代碼。
但是,我認為Crhis的答案(使用*Vertex
來保存數據)既簡單又好。 我將其留在此處以澄清我想要的內容。
class NodeClass n where
adjacent :: n a b -> [n b a]
data Node selfType adjacentType =
N
{ selfNode :: selfType
, adjNode :: [Node adjacentType selfType] }
data NodeWithData selfType adjacentType =
NWD
{ selfNodeWithData :: selfType
, adjNodeWithData :: [NodeWithData adjacentType selfType]
, getDataWithData :: [Double]
}
instance NodeClass Node where
adjacent = adjNode
instance NodeClass NodeWithData where
adjacent = adjNodeWithData
data VariableVertex = VV { vvID :: Int } deriving (Show)
data FactorVertex = FV { fvID :: Int } deriving (Show)
type VariableNode = Node VariableVertex FactorVertex
type FactorNode = Node FactorVertex VariableVertex
type VariableNodeWithData = NodeWithData VariableVertex FactorVertex
type FactorNodeWithData = NodeWithData FactorVertex VariableVertex
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.