Как создать экземпляр измененного массива unboxed

скажем, у меня есть следующий тип:


data MyType = Constructor0 | Constructor1 | Constructor2
            deriving (Eq,Show,Enum)

Есть ли способ создать один из таких экземпляров:


MArray (STUArray s) MyType (ST s)
MArray IOUarray MyType IO

На данный момент я храню все как Word8, и я делаю преобразование с помощью (wrapped) fromEnum/toEnum, но это не так. Мне нужно строгость и unboxing, потому что я использую большую структуру данных ( > 1.2Go) в памяти, и я не могу загрузить ее лениво. Если я не найду какое-либо решение, я собираюсь повторно реализовать все на С++, чего я предпочитаю избегать для своего текущего проекта.

Я задал вопрос о #haskell, но я не получил ответа, возможно, это было не самое подходящее время дня.

Ответ 1

Простейшая реализация, о которой я мог подумать: просто оберните операции STUArray/IOUArray с помощью fromEnum/toEnum.

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}

module UnpackedEnumArray (STUEArray, IOUEArray) where

import Control.Monad.ST
import Data.Array.Base
import Data.Array.IO
import Data.Array.ST

data STUEArray s i e = STUEArray { fromSTUEArray :: STUArray s i Int }
instance (Enum e) => MArray (STUEArray s) e (ST s) where
    getBounds = getBounds . fromSTUEArray
    getNumElements = getNumElements . fromSTUEArray
    newArray is = fmap STUEArray . newArray is . fromEnum
    newArray_ = fmap STUEArray . newArray_
    unsafeRead (STUEArray a) = fmap toEnum . unsafeRead a
    unsafeWrite (STUEArray a) i = unsafeWrite a i . fromEnum

data IOUEArray i e = IOUEArray { fromIOUEArray :: IOUArray i Int }
instance (Enum e) => MArray IOUEArray e IO where
    getBounds = getBounds . fromIOUEArray
    getNumElements = getNumElements . fromIOUEArray
    newArray is = fmap IOUEArray . newArray is . fromEnum
    newArray_ = fmap IOUEArray . newArray_
    unsafeRead (IOUEArray a) = fmap toEnum . unsafeRead a
    unsafeWrite (IOUEArray a) i = unsafeWrite a i . fromEnum

Теперь вы можете

import UnpackedEnumArray
main = do
    a <- newArray (0,9) Constructor0 :: IO (IOUEArray Int MyType)
    getAssocs a >>= print

Аналогично, экземпляры IArray могут быть тривиально записаны.

Ответ 2

Создание экземпляра для MArray IOUarray MyType IO должно быть возможным. Взгляните на источник для объявления экземпляра для MArray IOUarray Bool IO.

Так как Bool является экземпляром как Enum, так и Bounded (и не намного больше), они, вероятно, используют функции из этих классов при создании экземпляра.

Возможно, вам придется получить Bounded, но это, вероятно, не проблема, так как распакованные массивы могут содержать только элементы фиксированного размера.

Edit:

В в этой статье можно прочитать

Вы можете даже реализовать распакованные массивы самостоятельно для других простых типов, включая перечисления.