简体   繁体   English

在此示例中,有没有办法避免UndecidableInstances?

[英]Is there a way to avoid UndecidableInstances in this example?

When I try this: 当我尝试这个:

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

...I get this error: ...我得到这个错误:

/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)’

Using UndecidableInstances indeed makes it go away, but I'm wary of using that extension. 确实使用UndecidableInstances可以使它消失,但是我对使用该扩展名有所警惕。 Is there some other way to make things work in this case? 在这种情况下,还有其他方法可以使事情正常吗? (Without changing the types too much, preferably.) (最好不要过多更改类型。)

Warning: I haven't tested any of this code. 警告:我尚未测试任何此代码。

The approach that seems cleanest to me is to follow a Prelude.Extras -style path: 在我看来,最干净的方法是遵循Prelude.Extras风格的路径:

class NFData1 f where
  rnf1 :: NFData a => f a -> ()

You can now write, for each vector type, something like 现在,您可以为每种向量类型编写类似

instance NFData1 V where
  rnf1 = rnf

And then 接着

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

An alternative approach that may fit your current code better is to think about v as a Vector explicitly. 可能更适合您当前代码的另一种方法是将v明确视为Vector Instead of worrying about how va would prefer to force itself, ram your own notion down its throat by folding: something like 不必担心va会如何强迫自己,而是通过折叠将自己的想法打倒:

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

This second approach seems likely to play poorly with vector fusion unless you're careful about which vectors you want to force from left to right and which from right to left. 除非您对要从左向右强制使用哪些向量以及从右向左强制使用哪些向量保持谨慎,否则第二种方法似乎在矢量融合中可能效果不佳。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM