以下是代码:
{-# LANGUAGE RankNTypes, FlexibleContexts, ScopedTypeVariables #-}
module Foo where
import Data.Vector.Generic.Mutable as M
import Data.Vector.Generic as V
import Control.Monad.ST
import Control.Monad.Primitive
import Control.Monad
data DimFun v s r =
DimFun {dim::Int, func :: v (PrimState s) r -> s ()}
runFun :: (Vector v r) =>
(forall s . (PrimMonad s) => DimFun (Mutable v) s r) -> v r -> v r
runFun t x = runST $ do
y <- thaw x
evalFun t y
unsafeFreeze y
evalFun :: (PrimMonad s, MVector v r) => DimFun v s r -> v (PrimState s) r -> s ()
evalFun (DimFun dim f) y | dim == M.length y = f y
fm :: (MVector v r, PrimMonad s, Num r, Monad m) => m (DimFun v s r)
fm = error ""
f :: forall v r m . (Vector v r, Num r, Monad m) => m (v r -> v r)
f = liftM runFun $ (fm :: forall s . (PrimMonad s) => m (DimFun (Mutable v) s r))
这会导致错误:
Couldn't match type ‘DimFun (Mutable v) s0 r’
with ‘forall (s :: * -> *). PrimMonad s => DimFun (Mutable v) s r’
Expected type: DimFun (Mutable v) s0 r -> v r -> v r
Actual type: (forall (s :: * -> *).
PrimMonad s =>
DimFun (Mutable v) s r)
-> v r -> v r
Relevant bindings include
f :: m (v r -> v r) (bound at Testing/Foo.hs:36:1)
In the first argument of ‘liftM’, namely ‘runFun’
In the expression: liftM runFun
但是,我不确定如何修复或诊断问题。它可能就像一个好位置(并且编写良好)的类型签名一样简单。
在试图弄清楚发生了什么的时候,我写了一个非monadic版本(对我没用),但它编译:
gm :: (MVector v r, PrimMonad s, Num r) => DimFun v s r
gm = error ""
g :: forall v r m . (Vector v r, Num r) => v r -> v r
g = runFun (gm :: forall s . (PrimMonad s) => DimFun (Mutable v) s r)
这让我觉得上面的错误与this question相关,那里没有字典可以去的地方,但这真的只是在黑暗中刺伤。
答案 0 :(得分:4)
一种解决方案是在PrimMonad
数据类型中移动DimFun
约束。
data DimFun v r = DimFun
{ dim :: Int
, func :: forall s . PrimMonad s => v (PrimState s) r -> s ()
}
其余代码按原样编译,从s
中移除DimFun
参数:
runFun :: Vector v r => DimFun (Mutable v) r -> v r -> v r
runFun = ...
evalFun :: (PrimMonad s, MVector v r) => DimFun v r -> v (PrimState s) r -> s ()
evalFun = ...
fm :: (MVector v r, Num r, Monad m) => m (DimFun v r)
fm = ...
f :: (Vector v r, Num r, Monad m) => m (v r -> v r)
f = liftM runFun fm
将类约束移动到数据类型对您来说可能看起来很可怕,但实际上,您已经有了类限制。 PrimState
是PrimMonad
的关联类型系列,因此,为了生成或使用v (PrimState s) r
,您需要PrimMonad
约束。
如果你想避免它,你将不得不改变某种类型。要查看为什么您的函数是不适合的,请考虑以下(需要ImpredictiveTypes
):
fm :: (MVector v r, PrimMonad s, Num r, Monad m) => m (DimFun v s r)
fm = error ""
g :: (Vector v r, Monad m)
=> m (forall s . PrimMonad s => DimFun (Mutable v) s r) -> m (v r -> v r)
g = liftM runFun
应该清除为什么g fm
处于非状态状态:g
需要forall s . PrimMonad s =>
m
内的某些内容,而不是fm
fm' :: (MVector v r, Monad m, Num r) => m (forall s . PrimMonad s => DimFun v s r)
fm' = error ""
f :: forall v r m . (Vector v r, Num r, Monad m) => m (v r -> v r)
f = g fm'
的案例。您必须编写类型为
{{1}}