我有大量的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 回答
applyFunc
的以下类型是否适合您?只要你有
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
并且可以像这样完成虽然,通常最好简单地将数字作为单独的参数传递 .