5

我有大量类型的向量函数

f :: (M.MVector v r, PrimMonad m) => 
     v (PrimState m) r -> v (PrimState m) r -> m ()

这些函数大多在原地工作,因此将它们的参数设置为可变向量很方便,以便我可以组合、迭代等。但是,在顶层,我只想使用不可变的“Haskell”/纯向量.

这是问题的一个例子:

{-# LANGUAGE TypeFamilies, 
             ScopedTypeVariables, 
             MultiParamTypeClasses, 
             FlexibleInstances #-}

import Data.Vector.Generic as V hiding (eq)
import Data.Vector.Generic.Mutable as M
import Control.Monad.ST
import Control.Monad.Primitive

f :: (M.MVector v r, PrimMonad m) => 
     v (PrimState m) r -> v (PrimState m) r -> m ()
f vIn vOut = do val <- M.read vIn 0
                M.write vOut 0 val

applyFunc :: (M.MVector v r, PrimMonad m, V.Vector v' r, v ~ Mutable v') => 
             (v (PrimState m) r -> v (PrimState m) r -> m ()) -> v' r -> v' r
applyFunc g x = runST $ do
                    y <- V.thaw x
                    g y y -- LINE 1
                    V.unsafeFreeze y

topLevelFun :: (V.Vector v r) => r -> v r
topLevelFun a =
    let x = V.replicate 10 a
    in applyFunc f x -- LINE 2

编写的代码导致第 1 行出现错误:

Could not deduce (m ~ ST s)
   Expected type: ST s ()
   Actual type: m ()
   in the return type of g, LINE 1

注释掉第 1 行会导致第 2 行出现错误:

Ambiguous type variable `m0' in the constraint:
    (PrimMonad m0) arising from a use of `applyFun'

我尝试了各种显式类型(使用 ScopedTypeVariables、显式 foralls 等),但还没有找到解决第一个错误的方法。对于 LINE 1 错误,似乎m应该简单地推断为,ST s因为我在runST.

对于第 2 行错误(第 1 行注释掉),我想出的唯一可行的方法是

class Fake m v where
    kindSig :: m a -> v b c

instance Fake m v

topLevelFun :: forall m v v' r . (V.Vector v' r, M.MVector v r, PrimMonad m, Fake m v, v ~ Mutable v') => r -> v' r
topLevelFun a =
    let x = V.replicate 10 a
    in applyFunc (f::Transform m v r)  x -- LINE 2

这显然不能令人满意:我必须创建一个假类,使用更无意义的方法,其唯一工作是演示类参数的种类。然后我为所有内容创建一个通用实例,以便我可以m在范围内topLevelFun,以便我可以添加一个约束和强制转换f。必须有更好的方法。

我可能在这里做错了各种各样的事情,所以任何建议都会有所帮助。

4

1 回答 1

1

以下类型applyFunc适合您吗?

applyFunc :: (Vector v a) => 
  (forall s. Mutable v s a -> Mutable v s a -> ST s ()) 
  -> v a -> v a

只要您拥有Rank2Types扩展名,就应该可以毫无问题地编译,因为您使用的函数必须适用于所有ST monad。原因是 is 的类型runST(forall s. ST s a) -> a所以之后的代码主体runST需要为所有人工作s,因此g需要为所有人工作s

(您可以改为使用适用于所有功能的功能,PrimMonads但其中的功能要少得多)。

GHC 无法推断出更高等级的类型。有很好的理由不进行推断RankNTypes(这是无法确定的),尽管Rank2理论上是可推断的,但 GHC 人员决定“推断当且仅当原理类型是 Hindley-Milner 类型”的规则,这对于像我这样的人来说是很容易推理,并使编译器编写者的工作不那么难。

在评论中,您询问有关获取元组的信息。具有多态类型的元组需要ImpredicativeTypes并且可以像这样完成

applyFuncInt :: (Vector v a) => 
   ((forall s. Mutable v s a -> Mutable v s a -> ST s ()),Int)
   -> v a -> v a
applyFuncInt (g,_) x = runST $ do
                            y <- V.thaw x
                            g y y
                            V.unsafeFreeze y

不过,通常最好将数字作为单独的参数简单地传递。

于 2013-01-20T03:35:46.203 回答