Haskell 在这个例子中,有没有办法避免不可判定的实例?

Haskell 在这个例子中,有没有办法避免不可判定的实例?,haskell,haskell-vector,Haskell,Haskell Vector,当我尝试这个: import GHC.Generics (Generic) import Control.DeepSeq (NFData(..)) import Data.Vector.Generic (Vector) data Entry a = Entry !Bool a deriving (Generic, NFData) -- The variable @v@ is meant to be instantiated with a 'Vector' -- ty

当我尝试这个:

import GHC.Generics (Generic)
import Control.DeepSeq (NFData(..))
import Data.Vector.Generic (Vector)

data Entry a = Entry !Bool a
             deriving (Generic, NFData)

-- The variable @v@ is meant to be instantiated with a 'Vector'
-- type.  Most operations for the type have a @Vector v (Entry a)@
-- constraint.
newtype DenseIntMap v a = DenseIntMap (v (Entry a))

instance NFData (v (Entry a)) => NFData (DenseIntMap v a) where
  rnf (DenseIntMap va) = rnf va
…我得到这个错误:

/Users/casillas/GitHub/tau-sigma/src/TauSigma/Util/DenseIntMap.hs:53:10:
    Constraint is no smaller than the instance head
      in the constraint: Vector v (Entry a)
    (Use UndecidableInstances to permit this)
    In the instance declaration for ‘NFData (DenseIntMap v a)’

/Users/casillas/GitHub/tau-sigma/src/TauSigma/Util/DenseIntMap.hs:53:10:
    Constraint is no smaller than the instance head
      in the constraint: NFData (v (Entry a))
    (Use UndecidableInstances to permit this)
    In the instance declaration for ‘NFData (DenseIntMap v a)’

使用
不可判定实例
确实会让它消失,但我对使用该扩展持谨慎态度。在这种情况下,还有其他方法可以让事情顺利进行吗?(最好不要过多地更改类型。)

警告:我还没有测试过这段代码

在我看来,最干净的方法是遵循
前奏。附加部分
风格的路径:

class NFData1 f where
  rnf1 :: NFData a => f a -> ()
现在可以为每种向量类型编写如下内容

instance NFData1 V where
  rnf1 = rnf
instance (Vector v a, NFData a) => NFData (DenseIntMap v a) where
  rnf = V.foldl' (\() e -> rnf e) ()
然后

instance (NFData1 v, NFData a) => NFData (DenseIntMap v a) where ...

另一种可能更适合当前代码的方法是将
v
明确地看作
向量。与其担心
va
会如何强迫自己,不如把自己的想法塞进它的喉咙里,折叠起来:比如

instance NFData1 V where
  rnf1 = rnf
instance (Vector v a, NFData a) => NFData (DenseIntMap v a) where
  rnf = V.foldl' (\() e -> rnf e) ()

第二种方法似乎在向量融合方面效果不佳,除非您仔细考虑要从左到右强制哪些向量,以及从右到左强制哪些向量。

警告:我没有测试任何代码

在我看来,最干净的方法是遵循
前奏。附加部分
风格的路径:

class NFData1 f where
  rnf1 :: NFData a => f a -> ()
现在可以为每种向量类型编写如下内容

instance NFData1 V where
  rnf1 = rnf
instance (Vector v a, NFData a) => NFData (DenseIntMap v a) where
  rnf = V.foldl' (\() e -> rnf e) ()
然后

instance (NFData1 v, NFData a) => NFData (DenseIntMap v a) where ...

另一种可能更适合当前代码的方法是将
v
明确地看作
向量。与其担心
va
会如何强迫自己,不如把自己的想法塞进它的喉咙里,折叠起来:比如

instance NFData1 V where
  rnf1 = rnf
instance (Vector v a, NFData a) => NFData (DenseIntMap v a) where
  rnf = V.foldl' (\() e -> rnf e) ()

第二种方法似乎在向量融合方面效果不佳,除非您仔细考虑要从左到右强制哪些向量,以及从右到左强制哪些向量。

为什么要使用
vector
约束?这似乎没有任何意义。@dfeuer:哦,是的,你说得对。然而,当我删除它时,如果我不使用扩展名,我仍然会得到
NFData v(条目a)
错误。我将编辑这个问题。另外,你为什么对不可判定的实例保持警惕?Haskell为终止检查器提供了一个非常可怜的借口。@dfeuer:不是出于任何实际知识,而是因为“不可判定”是一个可怕的词。你为什么想要那个
Vector
约束?这似乎没有任何意义。@dfeuer:哦,是的,你说得对。然而,当我删除它时,如果我不使用扩展名,我仍然会得到
NFData v(条目a)
错误。我将编辑这个问题。另外,你为什么对不可判定的实例保持警惕?Haskell为终止检查提供了一个非常可怜的借口。@dfeuer:不是出于任何实际知识,而是因为“不可判定”是一个可怕的词。