此代码编译没有问题:如何在ST monad中创建一个多态的unboxed数组?
import Control.Monad.ST (ST)
import Data.Array.MArray (MArray)
import Data.Array.Unboxed (UArray)
import Data.Array.ST (runSTUArray, newArray, STUArray)
new :: Double -> UArray Int Double
new a = runSTUArray (newArray (0, 9) a)
但是,这样的:
new :: e -> UArray Int e
new a = runSTUArray (newArray (0, 9) a)
失败,正如人们所期望的那样,出现错误:
No instance for (MArray (STUArray s) e (ST s))
arising from a use of ‘newArray’
In the first argument of ‘runSTUArray’, namely
‘(newArray (0, 9) a)’
In the expression: runSTUArray (newArray (0, 9) a)
In an equation for ‘new’: new a = runSTUArray (newArray (0, 9) a)
然而,增加的类型级约束将无济于事,因为将类型签名更改为
new :: (MArray (STUArray s) e (ST s)) => e -> UArray Int e
仍然会失败
Could not deduce (MArray (STUArray s0) e (ST s0))
from the context (MArray (STUArray s) e (ST s))
bound by the type signature for
new :: MArray (STUArray s) e (ST s) => e -> UArray Int e
at pilot.hs:7:8-58
The type variable ‘s0’ is ambiguous
In the ambiguity check for the type signature for ‘new’:
new :: forall e s.
MArray (STUArray s) e (ST s) =>
e -> UArray Int e
To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
In the type signature for ‘new’:
new :: (MArray (STUArray s) e (ST s)) => e -> UArray Int e
什么办法,使这项工作?
编辑:发现了这一点已在Haskell和Haskell-Cafe邮件列表的讨论,从here采取这个最小的解决方案:
-- https://mail.haskell.org/pipermail/haskell/2005-August/016354.html
{-# LANGUAGE Rank2Types, FlexibleContexts #-}
import Control.Monad.ST (ST)
import Data.Array.MArray (MArray)
import Data.Array.Unboxed (UArray, Ix)
import Data.Array.ST (runSTUArray, newArray, STUArray)
new :: UArrayElement e => e -> UArray Int e
new a = case freezer of
Freezer runSTUArray' -> runSTUArray' $ (newArray (0, 9) a)
data Freezer i e = Freezer
((forall s. MArray (STUArray s) e (ST s) => ST s (STUArray s i e))
-> UArray i e)
class UArrayElement e where
freezer :: Ix i => Freezer i e
instance UArrayElement Bool where freezer = Freezer runSTUArray
instance UArrayElement Char where freezer = Freezer runSTUArray
instance UArrayElement Double where freezer = Freezer runSTUArray
恐怕这只是不可能,因为'Array'没有明确的类用于不可用的类型。 ['Vector' has](http://hackage.haskell.org/package/vector-0.11.0.0/docs/Data-Vector-Unboxed.html)。 – leftaroundabout
@leftaroundabout我的用例涉及二维索引,这是笨拙的矢量 –