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

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

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

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

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

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

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

2 ответа

Решение

Самая простая реализация, о которой я мог подумать: просто обернуть 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 экземпляры также могут быть написаны тривиально.

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

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

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

Редактировать:

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

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

Другие вопросы по тегам