在 Data.Array.Unboxed 中使用 newtype 和 ghc 7.10
Using newtype in Data.Array.Unboxed with ghc 7.10
这在 ghc 7.8.4 中运行良好,但在 7.10.3 中失败:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Foo where
import qualified Data.Array.Unboxed as A
import GHC.Generics (Generic)
newtype Elt = Elt Int deriving (Eq, Ord, Show, Num, Integral, Real, Enum, A.IArray A.UArray, Generic)
type MyArr = A.UArray Int Elt
有很多像
这样的消息
/tmp/my.hs:9:75:
Couldn't match type ‘Int’ with ‘Elt’
arising from the coercion of the method ‘Data.Array.Base.numElements’
from type ‘forall i. A.Ix i => A.UArray i Int -> Int’
to type ‘forall i. A.Ix i => A.UArray i Elt -> Int’
Relevant role signatures:
type role A.Ix nominal
type role A.UArray nominal nominal
When deriving the instance for (A.IArray A.UArray Elt)
虽然7.10的release notes没有提到,我明白了
https://ghc.haskell.org/trac/ghc/ticket/9220#comment:11 承认这是一个重大变化。但是解决方案是什么——我真的必须为 MyArr 创建一个新类型的包装器,并为每次使用提供辅助函数吗?
您不必为 MyArr
创建包装器,但您必须手动写出您之前派生的实例。有点蛮力的解决方案是 unsafeCoerce
手动通过 IArray
实例(你不能 coerce
的原因与你无法推导的原因相同)。
{-# LANGUAGE InstanceSigs, ScopedTypeVariables, MultiParamTypeClasses #-}
import Data.Array.Base
import Data.Array.IArray
import Data.Array.Unboxed
import Unsafe.Coerce
instance IArray UArray Elt where
bounds :: forall i. Ix i => UArray i Elt -> (i, i)
bounds arr = bounds (unsafeCoerce arr :: UArray i Int)
numElements :: forall i. Ix i => UArray i Elt -> Int
numElements arr = numElements (unsafeCoerce arr :: UArray i Int)
unsafeArray :: forall i. Ix i => (i,i) -> [(Int, Elt)] -> UArray i Elt
unsafeArray lu ies = unsafeCoerce (unsafeArray lu [ (i,e) | (i,Elt e) <- ies ] :: UArray i Int) :: UArray i Elt
unsafeAt :: forall i. Ix i => UArray i Elt -> Int -> Elt
unsafeAt arr ix = Elt (unsafeAt (unsafeCoerce arr :: UArray i Int) ix)
这在 ghc 7.8.4 中运行良好,但在 7.10.3 中失败:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Foo where
import qualified Data.Array.Unboxed as A
import GHC.Generics (Generic)
newtype Elt = Elt Int deriving (Eq, Ord, Show, Num, Integral, Real, Enum, A.IArray A.UArray, Generic)
type MyArr = A.UArray Int Elt
有很多像
这样的消息/tmp/my.hs:9:75:
Couldn't match type ‘Int’ with ‘Elt’
arising from the coercion of the method ‘Data.Array.Base.numElements’
from type ‘forall i. A.Ix i => A.UArray i Int -> Int’
to type ‘forall i. A.Ix i => A.UArray i Elt -> Int’
Relevant role signatures:
type role A.Ix nominal
type role A.UArray nominal nominal
When deriving the instance for (A.IArray A.UArray Elt)
虽然7.10的release notes没有提到,我明白了 https://ghc.haskell.org/trac/ghc/ticket/9220#comment:11 承认这是一个重大变化。但是解决方案是什么——我真的必须为 MyArr 创建一个新类型的包装器,并为每次使用提供辅助函数吗?
您不必为 MyArr
创建包装器,但您必须手动写出您之前派生的实例。有点蛮力的解决方案是 unsafeCoerce
手动通过 IArray
实例(你不能 coerce
的原因与你无法推导的原因相同)。
{-# LANGUAGE InstanceSigs, ScopedTypeVariables, MultiParamTypeClasses #-}
import Data.Array.Base
import Data.Array.IArray
import Data.Array.Unboxed
import Unsafe.Coerce
instance IArray UArray Elt where
bounds :: forall i. Ix i => UArray i Elt -> (i, i)
bounds arr = bounds (unsafeCoerce arr :: UArray i Int)
numElements :: forall i. Ix i => UArray i Elt -> Int
numElements arr = numElements (unsafeCoerce arr :: UArray i Int)
unsafeArray :: forall i. Ix i => (i,i) -> [(Int, Elt)] -> UArray i Elt
unsafeArray lu ies = unsafeCoerce (unsafeArray lu [ (i,e) | (i,Elt e) <- ies ] :: UArray i Int) :: UArray i Elt
unsafeAt :: forall i. Ix i => UArray i Elt -> Int -> Elt
unsafeAt arr ix = Elt (unsafeAt (unsafeCoerce arr :: UArray i Int) ix)