簡體   English   中英

試圖使我的typeclass / instance。 GHC說:“無法推斷……”

[英]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

編輯1

我嘗試了丹尼爾的一些建議 但是我不能讓它們工作。

構造器類

得到:“`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]

多參數類型類別(MPTC)

得到:“循環類聲明(通過超類)”

class (Node n) => Link l n where
  node :: l -> n
class (Link l) => Node n l where
  links :: n -> [l]

具有功能依賴性的MPTC

得到:“循環類聲明(通過超類)”

class (Node n) => Link l n | l -> n where
  node :: l -> n
class (Link l) => Node n l | n -> l where
  links :: n -> [l]

目標(編輯2)

我要實現的是有向無環圖結構,如下所示(更具體地講,為Factor圖 )。

PRML圖8.51
(來源: 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

  1. 它們已從語言中刪除(可通過擴展名獲得)
  2. 無論如何它們從來沒有用

然后以上編譯。 不過,我認為這不會幫助您。 正如克里斯·庫克萊維奇(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)。 n1node的調用方要求該神奇工廠產生的類型。 如果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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM