确定临时类型变量的范围

我有大量的vector类型的功能

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

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

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

我've tried a variety of explicit typing (using ScopedTypeVariables, explicit foralls, etc) but haven'找到了解决第一个错误的方法 . 对于LINE 1错误,似乎应该简单地将 m 推断为 ST s ,因为我在 runST 中 .

对于LINE 2错误(LINE 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

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

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

回答(1)

2 years ago

applyFunc 的以下类型是否适合您?

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

只要你有 Rank2Types 扩展名就可以编译出来,因为你需要使用一个必须在所有ST monad上工作的函数 . 原因是 runST 的类型是 (forall s. ST s a) -> a ,所以 runST 之后的代码体需要适用于所有 s ,因此 g 需要适用于所有 s .

(你可以改为使用一个适用于所有 PrimMonads 的函数,但这些函数的数量绝对更少) .

GHC无法推断出更高等级的类型 . 有很好的理由不推断 RankNTypes (它是不可判断的),尽管 Rank2 在理论上是可推断的,但GHC人员决定使用像我这样的人很容易推理的规则"infer if and only if the principle type is a Hindley-Milner type",并且使得编译器编写者不工作太难了

在评论中你要问一个元组 . 具有多态类型的元组需要 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

虽然,通常最好简单地将数字作为单独的参数传递 .