我想实现一个多态快速排序。我想指明一下
在IArray UArray a => [a] -> [a]
中输入a和ST s (STUArray s Int a)
的类型相同。我怎么能这样做?
{-# LANGUAGE FlexibleContexts #-}
module Quicksort where
import Control.Monad.ST (ST)
import Data.Array.ST (runSTUArray, newListArray, STUArray)
import Data.Array.IArray (elems)
import Data.Array.Unboxed (UArray, IArray)
quicksort :: IArray UArray a => [a] -> [a]
quicksort l = elems $ runSTUArray $
do newListArray (0, 9) l :: ST s (STUArray s Int a)
答案 0 :(得分:6)
您可以通过在顶级类型签名中启用ScopedTypeVariables
和supplying an explicit forall
来完成下一个错误:
quicksort :: forall a. IArray UArray a => [a] -> [a]
然后,您会发现STUArray
不是MArray
的实例,因为no instance代表a
。如果你把它变成Int
,它就会编译。
当然,明显缺少这样一个实例的原因是未装箱的数组只能包含 unboxeable 值,这个值是一个原语类型,一个详尽的名单,您可以在the relevant documentation中查看。
答案 1 :(得分:2)
您可以使用Data.Constraint.Forall
将此功能用于任何无法使用的内容。但是,由于机制的运作方式,它可能不是最有效的。一个更烦人但可能更好的方法是编写一个MArray
类的类,它采用一个期望s
参数的构造函数。
{-# Language MultiParamTypeClasses, ScopedTypeVariables, ConstraintKinds,
FlexibleInstances, FlexibleContexts, UndecidableInstances, TypeOperators #-}
module QS where
import Control.Monad.ST (ST, runST)
import Data.Constraint (Dict (..), (:-) (..))
import Data.Constraint.Forall (Forall, inst)
import Data.Array.ST (runSTUArray, newListArray, STUArray, MArray)
import Data.Array.IArray (elems)
import Data.Array.Unboxed (UArray, IArray)
type UnboxF a s = MArray (STUArray s) a (ST s)
class UnboxF a s => UnboxC a s
instance UnboxF a s => UnboxC a s
marrayDict :: Forall (UnboxC a) => Dict (UnboxC a s)
marrayDict = case inst :: Forall (UnboxC a) :- UnboxC a s of
Sub x -> x
quicksort :: forall a. (IArray UArray a, Forall (UnboxC a)) => [a] -> [a]
quicksort l = elems $ runSTUArray
( case marrayDict :: Dict (UnboxC a s) of { Dict ->
do
newListArray (0,9) l
} :: forall s. ST s (STUArray s Int a))
test :: [Char] -> [Char]
test = quicksort