试图创建我的类型类/实例.GHC说"无法演绎......"

tkf*_*tkf 1 haskell instance 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
Run Code Online (Sandbox Code Playgroud)

这是我收到的错误消息:

***.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
Run Code Online (Sandbox Code Playgroud)

编辑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]
Run Code Online (Sandbox Code Playgroud)

多参数类型(MPTC)

得到:"在类声明中循环(通过超类)"

class (Node n) => Link l n where
  node :: l -> n
class (Link l) => Node n l where
  links :: n -> [l]
Run Code Online (Sandbox Code Playgroud)

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]
Run Code Online (Sandbox Code Playgroud)

目标(编辑2)

我想要实现的是一个有向无环图结构,如下所示(更具体地说,一个因子图).

PRML图8.51 http://research.microsoft.com/en-us/um/people/cmbishop/prml/prmlfigs-png/Figure8.51.png

有两种节点(白色圆圈和红色方块),它们只连接到不同类型的节点,这意味着有两种链接.

我想要不同版本的节点和链接,它们附有数据(数组).我也想要"vanilla"DAG,它只有一种类型的节点和链接.但是为了遍历它们,我只想要一个接口来做到这一点.

Dan*_*her 6

类方法的签名

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

class Node n where
  links :: (Link l) => n -> [l]
Run Code Online (Sandbox Code Playgroud)

说,"无论何种类型的来电者的欲望,nodeRESP,links可以生产它,只要它的成员LinkRESP.Node",但执行说,只有一个有价值的特定类型的都可以生产.

它与OOP中的接口有根本的不同,OOP中的实现决定了类型,调用者必须接受它,这里调用者决定.


您正在遇到构造函数类尝试的问题.你的类需要两个参数,l那种kln种类kn.参数的种类(->)必须是*,类型的种类.因此,l n为了成为一个良好的论证(->),l必须是一个类型构造函数,采用类型的论证kn并创建一种类型的结果*,即

l :: kn -> *
Run Code Online (Sandbox Code Playgroud)

现在你尝试将结果类型node设为be n l,这意味着

n :: kl -> *
Run Code Online (Sandbox Code Playgroud)

但在上面我们看到了kl = kn -> *,产量

n :: (kn -> *) -> *
Run Code Online (Sandbox Code Playgroud)

RESP.kn = (kn -> *) -> *,这是一种无限的.无限类型,如无限类型,是不允许的.但那种推理只执行非常简陋,所以编译器假定参数l有样*,但看到从n ln有怎样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
Run Code Online (Sandbox Code Playgroud)

您必须DatatypeContexts从数据声明中删除,

  1. 他们已从语言中删除(可通过扩展程序获得)
  2. 无论如何,它们从未有用

然后上面的编译.不过,我认为它不会对你有所帮助.正如Chris Kuklewicz所说,你的类型追逐自己的尾巴,你会用它们作为

SimpleLink (SimpleNode (SimpleLink (SimpleNode ... {- ad infinitum -})))
Run Code Online (Sandbox Code Playgroud)

对于多参数类,如编译器所说,你不能让每个参与者都有一个需求导致一个依赖循环(同样,在你的约束中你只使用一个参数,

class Node n => Link l n where ...
Run Code Online (Sandbox Code Playgroud)

这是错误的,编译器会拒绝,如果周期被打破).

您可以通过合并类来解决周期,

class NodeLinks l n | l -> n, n -> l where
    node :: l -> n
    links :: n -> l
Run Code Online (Sandbox Code Playgroud)

但是你仍然有你的类型对它没用的问题.

抱歉,我不能很好地理解你的目标,建议一个可行的解决方案.