Domanda

Sto cercando un modo per avere Enum a => UArray a (Il che ha senso per me perché possiamo mappare banale enums a Int e di nuovo da toEnum e fromEnum)

Finora ho provato a rubare il codice di UArray Int da Data.array.base e contrabbandare alcuni toEnumsabbia fromEnums qua e là:

{-# LANGUAGE MagicHash, UnboxedTuples #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

module UArrays where

import           Data.Array.Base
import           Data.Array.ST
import           Data.Array.Unboxed

import           GHC.Base -- (Int(I#), Int#(..))
import           GHC.Prim -- (indexIntArray#, readIntArray#, writeIntArray#)
import           GHC.ST (ST(..), runST)

import           Unsafe.Coerce

instance (Enum a, Bounded a) => IArray UArray a where
    {-# INLINE bounds #-}
    bounds (UArray l u _ _) = (l, u)
    {-# INLINE numElements #-}
    numElements (UArray _ _ n _) = n
    {-# INLINE unsafeArray #-}
    unsafeArray lu ies = runST (unsafeArrayUArray lu ies minBound)
        {-# INLINE unsafeAt #-}
    unsafeAt (UArray _ _ _ arr#) (I# i#) =
        I# $ fromEnum (indexIntArray# arr# i#)
    {-# INLINE unsafeReplace #-}
    unsafeReplace arr ies = runST (unsafeReplaceUArray arr ies)
    {-# INLINE unsafeAccum #-}
    unsafeAccum f arr ies = runST (unsafeAccumUArray f arr ies)
    {-# INLINE unsafeAccumArray #-}
    unsafeAccumArray f initialValue lu ies =
      runST (unsafeAccumArrayUArray f initialValue lu ies)

-- data STUArray s i e = STUArray !i !i !Int (GHC.Prim.MutableByteArray# s)
instance (Enum a, Bounded a) => MArray (STUArray s) a (ST s) where
    {-# INLINE getBounds #-}
    getBounds (STUArray l u _ _) = return (l, u)
    {-# INLINE getNumElements #-}
    getNumElements (STUArray _ _ n _) = return n
    {-# INLINE unsafeNewArray_ #-}
    unsafeNewArray_ (l, u) = unsafeNewArraySTUArray_ (l, u) wORD_SCALE
    {-# INLINE newArray_ #-}
    newArray_ arrBounds = newArray arrBounds minBound
    {-# INLINE unsafeRead #-}
    -- unsafeRead :: GHC.Arr.Ix i => a i e -> Int -> m e
    unsafeRead (STUArray _ _ _ marr#) (I# i#) =
      ST $ \ s1# ->
      case readIntArray# marr# i# s1# of
        (# s2#, e# #) -> (# s2#, I# (toEnum e#) #)
    {-# INLINE unsafeWrite #-}
    -- unsafeWrite :: GHC.Arr.Ix i => a i e -> Int -> e -> m ()
    unsafeWrite (STUArray _ _ _ marr#) (I# i#) (I# e#) =
      ST $ \ s1# ->
      case writeIntArray# marr# (unsafeCoerce i#) (I# $ fromEnum e#) s1# of
        s2# -> (# s2#, () #)

Ma ovviamente non si compila:

[2 of 4] Compiling UArrays          ( UArrays.hs, interpreted )

UArrays.hs:27:14:
    Couldn't match expected type `Int#' with actual type `Int'
    In the return type of a call of `fromEnum'
    In the second argument of `($)', namely
      `fromEnum (indexIntArray# arr# i#)'
    In the expression: I# $ fromEnum (indexIntArray# arr# i#)

UArrays.hs:52:45:
    Couldn't match expected type `Int' with actual type `Int#'
    In the first argument of `toEnum', namely `e#'
    In the first argument of `I#', namely `(toEnum e#)'
    In the expression: I# (toEnum e#)

UArrays.hs:57:57:
    Couldn't match expected type `Int#' with actual type `Int'
    In the return type of a call of `fromEnum'
    In the second argument of `($)', namely `fromEnum e#'
    In the third argument of `writeIntArray#', namely
      `(I# $ fromEnum e#)'
Failed, modules loaded: Utils.

Inoltre non c'è magico unboxInt :: Int -> Int# in GHC.*, e matching pattern I# non cede Int ma un Int# Invece, eppure in qualche modo UArray Int esiste e lavora Int#S.

Ho anche trovato un post su Fare un Uarray per i newTypes, ma non sembra applicarsi perché si basa su unsafeCoerce. L'ho provato ma ha reso divertente listArray (0, 54) $ cycle [Red, Yellow, Green] in cui erano tutti i costruttori Blue.

Sono sulla pista sbagliata?

Aggiornare:

Funziona ora, ecco il codice sorgente:

Nessuna soluzione corretta

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top