Haskell没有得到我的函数依赖性

Haskell没有得到我的函数依赖性,haskell,constraints,typeclass,functional-dependencies,Haskell,Constraints,Typeclass,Functional Dependencies,我试图创建一个实现基本队列行为的队列类型类。我的代码如下: {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FunctionalDependencies #-} data QueueA a = QueueA { front :: [a], rear :: [a] } class Queue a b | a -> b where empty :: a null :: a -> Boo

我试图创建一个实现基本队列行为的队列类型类。我的代码如下:

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}

data QueueA a = QueueA { front :: [a], rear :: [a] }

class Queue a b | a -> b where

  empty         :: a
  null          :: a -> Bool
  head          :: a -> Maybe b
  tail          :: a -> Maybe a
  toList        :: a -> [b]
  (|>)          :: a -> b -> a

instance Queue (QueueA a) where      

  empty = QueueA [] []

  null (QueueA [] []) = True
  null _ = False

  head (QueueA [] []) = Nothing
  head (QueueA (x:xs) _) = Just x

  tail (QueueA [] []) = Nothing
  tail (QueueA (x:xs) (y:ys)) = Just $ QueueA (xs ++ [y]) ys

  toList (QueueA x y) = x ++ y

  (|>) (QueueA x y) e = if (length x > length y) then QueueA (init $ e : x) ((last x) : y) else QueueA (e : x) y
不幸的是,当我试图编译代码时,ghc告诉我以下几点:

queue.hs:15:10: error:
    • Expecting one more argument to ‘Queue (QueueA a)’
      Expected a constraint,
        but ‘Queue (QueueA a)’ has kind ‘* -> Constraint’
    • In the instance declaration for ‘Queue (QueueA a)’
   |
15 | instance Queue (QueueA a) where 
   |          ^^^^^^^^^^^^^^^^

不过,我并没有真正明白这一点。我所知道的是,我的实例声明中队列的模式必须正确,因为它与我在上面的数据类型中指定的模式完全相同。我尝试了我的实例声明的几种变体,但都没有成功。我只是忽略了什么吗?如何使其可编译?

实例需要与相应类相同数量的参数。但是,您创建了一个具有2个参数的类和一个仅具有1个参数的对应实例。要使其编译,可以执行
实例队列(QueueA a)where
而不是
实例队列(QueueA a)where
。(您还需要
FlexibleInstances
扩展。)

该类不需要多个参数。相反,该类应该采用高阶类型作为其参数,而不是具体类型

class Queue t where
    empty :: t a
    null :: t a -> Bool
    head :: t a -> Maybe a
    tail :: t a -> Maybe (t a)
    toList :: t a -> [a]
    (|>) :: t a -> a -> t a
QueueA
本身有一个
Queue
实例,而不是
QueueA

instance Queue QueueA where
  -- same as above

对我来说这似乎很清楚:
Queue
类需要两种类型,但您只给了它一种,
QueueA a
。我并不完全清楚您试图对这种类型和类执行什么操作,但似乎
实例队列(QueueA)a
可以按您的意愿工作?(事实上,在进一步的研究中,我认为我看到了更多的错误——但至少它会让您继续前进。)好的,在我的类定义中,b应该表示队列的类型“a”,以便在类主体中我能够指定函数(|>)和头的返回值(取决于队列类型)。因此,我希望QueueA实际上会被识别为typeclass队列的类型a,约束a被识别为类中的约束b。你证明了我的假设是错误的,你能告诉我怎么做吗?typeclass的目的不是这样的,这样你就可以声明它的单态实例,而这种方式不允许你这样做吗?我把这个问题解释为问如何使用类来定义抽象数据类型的接口,每个实例都提供了一个实现。例如,您也可以为
Data.Sequence.Seq
定义一个相当普通的
队列
实例,而不是如何将多态容器限制为单态容器。但是,由于队列仅以单态形式依赖于其参数(不像,比方说,函子),我认为应该严格地更灵活地宣布它与fundep的原始方式。然而,使用起来更麻烦。也许我只是不清楚“单态依赖”是什么意思。@chepner认为
IsList
mono-traversable
类。在这种情况下,fundep方法将允许您使用
文本
ByteString
构建队列,但这种方法不会,因为这些类型不能包含任意其他类型。(由于这个原因,在这种特殊情况下,单态方式的限制性比多态方式小。)