Есть две проблемы. Во-первых, поскольку dave4420 pointed out, runST
нуждается в функции alter
, чтобы быть полиморфной в состоянии s
.
Устранение этого, тем не менее, делает невозможным решение второй проблемы, что вам нужен пример MArray
для thaw
(и freeze
). Вы должны были бы ограничение
alterUArray :: (Ix i, Ord e, IArray UArray e, forall s. MArray (STUArray s) e (ST s)) => ...
, чтобы заставить его работать, так как runST
это один выбрать s
. Но вы не можете указать такое ограничение.
Если вы дать конкретный тип элемента (Int
, Double
...), она работает так как существует
instance MArray (STUArray s) Int (ST s) where ...
поэтому требования thaw
и freeze
не удовлетворены, независимо от того, что s
выбирают runST
(и ограничение не нужно указывать).
Это также работает, если вы выбираете штучной массивы вместо распакованный из них, поскольку также является
instance MArray (STArray s) e (ST s) where ...
и поэтому нет никаких ограничений на тип элемента, который должен быть указан в подписи alterUArray
. (Нет ограничений на типы элементов списка, а элементы списка вставляются в бокс, поэтому массивы в штучной упаковке соответствуют спискам, а не распакованным массивам).
Если вы можете нести замарать руки, вы можете обойти эту проблему, заменив ST s
на IO
,
alterUArray :: (Ix i, Ord e, MArray IOUArray e IO, IArray UArray e) =>
(IOUArray i e -> IO()) -> UArray i e -> UArray i e
alterUArray alter ua = unsafePerformIO $ do
mua <- thaw ua
alter mua
freeze mua
нужен только FlexibleContexts
. Это позволяет передать плохой аргумент alter
, который делает нечестный файл IO
, и спрячет его от вызывающего. Так давайте использовать unsafePerformIO
здесь безопасно, заставляя более общий вид на alter
аргумент:
{-# LANGUAGE FlexibleContexts, RankNTypes, ScopedTypeVariables #-}
import Data.Array.Unboxed
import Data.Array.IO
import System.IO.Unsafe
alterUArray :: forall i e. (Ix i, Ord e, IArray UArray e, MArray IOUArray e IO) =>
(forall m u. MArray u e m => u i e -> m()) -> UArray i e -> UArray i e
alterUArray alter ua = unsafePerformIO $ do
mua <- thaw ua :: IO (IOUArray i e)
alter mua
freeze mua
Теперь мы дали alter
тип, который делает это невозможно сделать мерзкой IO
без самостоятельно, используя unsafePerformIO
, так использование unsafePerformIO
здесь не создает дополнительной неуверенности - за счет более необходимых расширений.
(Примечание: при использовании thaw
, чтобы получить копию исходного массива не нужно, нет необходимости в дополнительной копии при замораживании, что может быть unsafeFreeze
без проблем.)
Если удалить аннотацию типа от 'thaw ua', какая ошибка вы получаете? – dave4420
@ dave4420 http://hpaste.org/84910 –