就地多态快速排序中的STUArray类型参数

时间:2018-02-24 17:51:19

标签: haskell

我想实现一个多态快速排序。我想指明一下 在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)

2 个答案:

答案 0 :(得分:6)

您可以通过在顶级类型签名中启用ScopedTypeVariablessupplying 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