确定临时类型变量的范围

时间:2013-01-19 17:45:44

标签: haskell monads

我有大量类型

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'

我尝试了各种显式输入(使用ScopedTypeVariables,显式foralls等),但还没有找到修复第一个错误的方法。对于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

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

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

1 个答案:

答案 0 :(得分:1)

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

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

只要您拥有Rank2Types扩展名,就应该编译没有问题,因为您使用的函数必须处理所有 ST monads。原因是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

尽管通常最好将数字作为单独的参数传递。