さて、array
パッケージ内のいくつかの設計の選択が困難になっているので、あなたはちょっとここで立ち往生していますが、ここではボイラープレートを最小限に抑えるのに役立つ可能性がある1つのアプローチがあります。
タイプファミリーを導入して、新しいタイプをその基礎となる表現にマッピングできます。
type family UType e where
UType MyBool = Bool
UType MyInt = Int
UType a = a -- default for built-in types
そして、IOUArray
およびSTUArray
配列型のnewtypeバリアントを導入します。
newtype NTSTUArray s i e = NTSTUArray (STUArray s i (UType e))
newtype NTIOUArray i e = NTIOUArray (IOUArray i (UType e))
そして、使用THESEを適切に得るためにMArray
あなたの新しいタイプのインスタンスを:
instance (MArray (STUArray s) (UType e) (ST s), Coercible e (UType e))
=> MArray (NTSTUArray s) e (ST s) where
getBounds (NTSTUArray arr) = getBounds arr
getNumElements (NTSTUArray arr) = getNumElements arr
newArray (a,b) e = NTSTUArray <$> newArray (a,b) (coerce e)
newArray_ (a,b) = NTSTUArray <$> newArray_ (a,b)
unsafeNewArray_ (a,b) = NTSTUArray <$> unsafeNewArray_ (a,b)
unsafeRead (NTSTUArray arr) i = coerce <$> unsafeRead arr i
unsafeWrite (NTSTUArray arr) i e = unsafeWrite arr i (coerce e)
instance (MArray IOUArray (UType e) IO, Coercible e (UType e))
=> MArray NTIOUArray e IO where
getBounds (NTIOUArray arr) = getBounds arr
getNumElements (NTIOUArray arr) = getNumElements arr
newArray (a,b) e = NTIOUArray <$> newArray (a,b) (coerce e)
newArray_ (a,b) = NTIOUArray <$> newArray_ (a,b)
unsafeNewArray_ (a,b) = NTIOUArray <$> unsafeNewArray_ (a,b)
unsafeRead (NTIOUArray arr) i = coerce <$> unsafeRead arr i
unsafeWrite (NTIOUArray arr) i e = unsafeWrite arr i (coerce e)
さて、あなたは使用することができるはずNTIOUArray
とNTSTUArray
、通常の代わりにIOUArray
とSTUArray
の両方を内蔵しており、あなたのnewtype要素タイプのために:
main = do
x <- newArray (1,10) (MyInt 0) :: IO (NTIOUArray Int MyInt)
y <- newArray (1,10) 0 :: IO (NTIOUArray Int Int)
readArray x 5 >>= writeArray y 8 . coerce
すべてのIArray
インスタンスは、via
派生を使用して自動的に生成できます(要素タイプがIArray
制約の最後の引数であるため機能します)。
deriving via MyBool instance IArray UArray MyBool
deriving via MyInt instance IArray UArray MyInt
または、NTIArray
newtypeで上記と同じ手法を使用できます。
いくつかのサンプルコード:
{-# LANGUAGE DerivingVia, FlexibleContexts, FlexibleInstances, GeneralizedNewtypeDeriving,
MultiParamTypeClasses, StandaloneDeriving, TypeFamilies, UndecidableInstances #-}
import Data.Coerce (coerce, Coercible)
import Data.Array.Base
import Data.Array.IO
import Control.Monad.ST (ST)
newtype MyBool = MyBool Bool deriving (Show)
newtype MyInt = MyInt Int deriving (Show)
-- newtype arrays
type family UType e where
UType MyBool = Bool
UType MyInt = Int
UType a = a
newtype NTSTUArray s i e = NTSTUArray (STUArray s i (UType e))
newtype NTIOUArray i e = NTIOUArray (IOUArray i (UType e))
deriving via MyBool instance IArray UArray MyBool
deriving via MyInt instance IArray UArray MyInt
instance (MArray (STUArray s) (UType e) (ST s), Coercible e (UType e))
=> MArray (NTSTUArray s) e (ST s) where
getBounds (NTSTUArray arr) = getBounds arr
getNumElements (NTSTUArray arr) = getNumElements arr
newArray (a,b) e = NTSTUArray <$> newArray (a,b) (coerce e)
newArray_ (a,b) = NTSTUArray <$> newArray_ (a,b)
unsafeNewArray_ (a,b) = NTSTUArray <$> unsafeNewArray_ (a,b)
unsafeRead (NTSTUArray arr) i = coerce <$> unsafeRead arr i
unsafeWrite (NTSTUArray arr) i e = unsafeWrite arr i (coerce e)
instance (MArray IOUArray (UType e) IO, Coercible e (UType e))
=> MArray NTIOUArray e IO where
getBounds (NTIOUArray arr) = getBounds arr
getNumElements (NTIOUArray arr) = getNumElements arr
newArray (a,b) e = NTIOUArray <$> newArray (a,b) (coerce e)
newArray_ (a,b) = NTIOUArray <$> newArray_ (a,b)
unsafeNewArray_ (a,b) = NTIOUArray <$> unsafeNewArray_ (a,b)
unsafeRead (NTIOUArray arr) i = coerce <$> unsafeRead arr i
unsafeWrite (NTIOUArray arr) i e = unsafeWrite arr i (coerce e)
main = do
x <- newArray (1,10) (MyInt 0) :: IO (NTIOUArray Int MyInt)
y <- newArray (1,10) 0 :: IO (NTIOUArray Int Int)
readArray x 5 >>= writeArray y 8 . coerce
x' <- freeze x :: IO (UArray Int MyInt)
y' <- freeze y :: IO (UArray Int Int)
print $ (x' ! 5, y' ! 8)
foo :: ST s (NTSTUArray s Int MyInt)
foo = newArray (1,10) (MyInt 0)
type role IOUArray nominal nominal
、array-of-intからarray-of-myintに強制変換できません。(なぜ私たちにはそのような役割があるのでしょうか。)