Haskell 使用一元秩-2类型
代码如下:Haskell 使用一元秩-2类型,haskell,higher-rank-types,Haskell,Higher Rank Types,代码如下: {-# 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 DimF
{-# 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))
但是,我不确定如何修复或诊断该问题。它可能像一个好地方(而且写得很好)的类型签名一样简单
在试图弄清楚发生了什么的时候,我写了一个非一元版本(对我来说没用),但它编译:
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)
这让我觉得上面的错误与字典没有地方可去的地方有关,但这真的只是一个暗中的尝试 一种解决方案是将
PrimMonad
约束移动到DimFun
数据类型中
data DimFun v r = DimFun
{ dim :: Int
, func :: forall s . PrimMonad s => v (PrimState s) r -> s ()
}
其余代码按原样编译,从DimFun
中删除s
参数:
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
约束
然而,如果你想避免它,你必须改变某些东西的类型。要了解为什么您的函数是非类型化的,请考虑下面的(这需要<代码> iVixTiVePype < /代码>):
应该弄清楚为什么g fm
类型错误:g
期望所有类型错误的内容。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'
看起来你可能做了一个双重职位。这可能应该被删除,答案在这里:@jberryman这两个问题中的问题是否相关对我来说并不明显(尽管代码的某些子集实际上是相同的)。这就是为什么我发布了两个问题。这可能是一个不明确的多态性问题。你可以用一个容器包装你的通用量化字体。@J.Abrahamson我宁愿有更多的注释也不要用包装器。注释会去哪里?它们看起来会是什么样子?@Eric一旦你看到需要多少注释才能使其工作,你可能会改变主意。这两种解决方案都很好。我只希望这是我需要做的事情,这一点更加明显!这也解决了问题,因为我不再需要对排名2的类型进行模式匹配。我唯一能要求的是一个提示,告诉我如何知道这是未来应该做的正确的事情。为什么我更喜欢数据中的rank-2类型而不是数据中的rank-2类型?在我看来,您应该总是在数据类型中选择通用的量化字段,而不是不可预测的类型。对于不可预测类型,几乎总是很难判断正确的类型应该是什么,正如您所看到的,正确类型和错误类型之间的差异通常非常小。更重要的是,typechecker对您毫无用处,因为它无法推断不精确的类型,而您遇到的类型错误将是可怕的。
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
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'