无法显示 haskell 中实例函数的结果

cannot show result from an instance function in haskell

class (Eq k, Ord k, Show k) => KEY k where
  keyBuild    :: NumId -> NumId -> NumId  -> k
  keyDummy    :: k
  keyFromList :: [NumId] -> k
  -- keyGenerate :: (DATAPOOL p) => p -> Int -> [k]  -- p = Pool k e s


newtype PrimaryKey = PK (NumId, NumId, NumId) deriving (Eq, Ord, Show) 

instance KEY PrimaryKey where
  keyBuild k0 k1 k2 = PK (k0,k1,k2)
  keyDummy          = PK (0,0,0)
  keyFromList is    = keyFromList (take 3 (is ++ (replicate 3 0)))
  keyGenerate p cnt = let
                        ks = keys p
                        pks = map (\l ->  keyFromList (randomize l))                   (replicate cnt 3)
                      in pks

我在 ghci 中

let k1 = keyBuild 1 2 3
let k2 = PK (1,2,3)
k1 == k2 
True
k2
PK (1,2,3)

并按预期得到 True 和 k2 的值,但是

k1
231:1: error:
    • Ambiguous type variable ‘a0’ arising from a use of ‘it’
      prevents the constraint ‘(KEY a0)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a0’ should be.
      These potential instance exist:
        instance [safe] KEY PrimaryKey -- Defined at Work

预期 PK(1,2,3) PrimaryKey 派生 (Eq, Ord, Show) 那么我做错了什么或错过了什么?

你没有给k1一个固定的类型。因为 keyBuild 可以用正确的实例构造 any 类型的键,所以它具有多态类型 k1 :: KEY k => k。这很好,因为您可以将 k1 与不同具体类型的键进行比较......在您的情况下,您已经尝试使用 k2 :: PrimaryKey,但您也可以使用 k1 == k3 k3 :: SomeOtherKeyType,前提是 SomeOtherKeyType 也是 KEY class 的一个实例——在这种情况下,k1 也将简单地“接管”类型 SomeOtherKeyType.

不利的一面是 k1 没有 特定的 类型。它实际上可能是 any 适用类型,但编译器应该如何知道你想要哪个?当使用 == 时,它的两边必须是相同的类型,所以在一侧有一个具体的类型就足够了,但是单独使用 k1 是不明确的。

碰巧在你的模块中只有一个匹配的实例,即 KEY PrimaryKey 但通常会有很多(或零!)这样的实例。如果编译器随便选一个就很奇怪不是吗?

所以如果你想显示k1,你需要手动选择一种类型。做起来很简单,只需添加一个本地签名:

*Main> let k1 = keyBuild 1 2 3
*Main> :t k1
k1 :: KEY k => k
*Main> k1 :: PrimaryKey
PK (1,2,3)