2012-08-03 60 views
7

当我尝试编译此:哈斯克尔:“无法演绎”错误与runST

module Main where 

import qualified Data.Vector.Unboxed.Mutable as MV 
import Control.Monad.ST 

myRead mv = runST $ MV.read mv 0 

我收到以下错误信息:

Could not deduce (t ~ U.MVector s a) 
    from the context (U.Unbox a) 
     bound by the inferred type of myRead :: U.Unbox a => t -> a 
     at src/Main.hs:53:1-32 
     `t' is a rigid type variable bound by 
      the inferred type of myRead :: U.Unbox a => t -> a 
      at src/Main.hs:53:1 
    Expected type: U.MVector (PrimState (ST s)) a 
     Actual type: t 
    In the first argument of `MV.read', namely `mv' 
    In the second argument of `($)', namely `MV.read mv 0' 
    In the expression: runST $ MV.read mv 0 

我可以读取从一个可变矢量纯粹与runST?如果是这样,怎么样?我认为它需要myRead的类型签名,但我尝试过的所有内容都会导致越来越多的不可理解的错误消息。

编辑:他强调了一点,我只是把一个评论如下:这里的背景是,我有一个函数,它在一个可变矢量,使用可变矢量作为临时空间,然后需要做一些计算返回一个浮点值。因为我不关心可变向量的变化,所以我想知道是否有办法忽略它的“状态变化”,并简单地从其中返回一个值。

+1

我认为智者Breitner和Fischer的观点是,我们需要更多地了解你如何达到这一点。什么函数产生你建议应用myRead的可变向量?请参阅Breitner回复中的最后一句。如果我们知道是什么让你在这个角落里,我们可以说如何重新分析东西,让它们一起挂。因此,更多的代码行将会有所帮助。例如,如果'mv'在ST块内,则可以使用更简单的定义'myRead mv = MV.read mv 0'(no'runST')。 – applicative 2012-08-03 20:12:38

+0

让我强化一下应用说:我们需要更多的上下文。不知道你实际想要达到什么目标,我们找不到合适的解决方案。 – 2012-08-03 21:40:45

回答

2

其他答案是好的,但我认为你有一个关于ST的基本知识,你错过了。每次调用runST都会有效地创建一个新的“ST Universe”,其中包含一些命令式代码。因此,如果你有一个调用runST来创建数组,并单独调用runST以从该数组中获取值,那么事情不可能奏效。这两个runST调用需要他们自己独特的Universe,而您希望他们共享一个。

什么答案详细解释了这些独特的宇宙是如何通过某种类型系统欺骗来创建的。

+0

这个。 'runST'应该从外面看起来很纯净,所以没有什么可变的可以从'ST' monad中逃脱。 – MathematicalOrchid 2012-08-06 13:43:42

3

编译器默认在某个特定类型的左侧看到参数mv,但在右侧需要一些多态类型。类型签名可以解决问题。

{-#LANGUAGE Rank2Types#-} 
module Main where 

import qualified Data.Vector.Unboxed.Mutable as MV 
import Control.Monad.ST 

myRead :: MV.Unbox a => (forall s . MV.MVector s a) -> a 
myRead mv = runST $ MV.read mv 0 

的想成为你的函数的签名会是这样的,如果我的理解:

-- myBadRead :: forall s a . MV.Unbox a => MV.MVector s a -> a 
-- myBadRead mv = runST $ MV.read mv 0 

但这里runST :: (forall s. ST s a) -> a不会有一个不依赖s事情上下工夫,因为s在LHS上编写mv时是固定的。

编辑:但是,正如Joachim B和Daniel F.所强调的那样,尽管上述定义是一致的,但在实践中这将是没有用的,因为您将无法构建一个矢量mv给它。简单地说,任何生成mv的方法都已经在编译器的引导下为其分配了s。一种标准方法是使这样的功能作用在由Data.Vector.Unboxed一个“纯”矢量然后,在右手侧时,从.Mutable模块

import qualified Data.Vector.Unboxed as UV 
import qualified Data.Vector.Unboxed.Mutable as MV 
import Control.Monad.ST 

myRead :: MV.Unbox a => UV.Vector a -> a 
myRead v = runST $ do mv <- UV.unsafeThaw v 
         MV.read mv 0 

当然施加操作之前解冻它,这种特殊的定义等同到myRead = (UV.! 0)同样,像这样的道理,在myRead

mhead :: MV.Unbox a => MV.MVector s a -> ST s a 
mhead mv0 = MV.read mv0 0 

mrx = runST $ do mv <- UV.unsafeThaw $ UV.enumFromStepN 0 1 20 
          -- ^^^ or however the mv is generated. 
        x <- MV.unsafeRead mv 17 -- arbitrary 'scratch pad' 
        MV.unsafeWrite mv 17 (2*x) -- computations 
        mhead mv 
        -- ^^^ we return just the first element, after all the mutation 

定义撞击runST在这里,而不是封闭myReadmheadrunST我们保持我t在s中多态,然后可以在出现可变向量mv的相同ST块内使用它。因此,编译器将能够使用它用于do-block的'secret's作为一个整体来解释将mhead应用于mv的结果,因为它是我们的多态定义mhead

剩下的一种可能性
3

应用程序的答案告诉你如何让你的代码编译。但是代码将不可用:runST的要点是命令式计算无法逃避它,因为那里存在着一个存在的绑定类型变量。

现在你创造的地方将有一个固定 S型MVector s a,而你myRead预计提供矢量任何个值的任何可变数组。

似乎之前有一个问题让你想拥有这个(不可能)的功能。

+0

我同意这是一个不受欢迎的功能,我试图解释类型错误。解释是否无效?如果是的话,我应该删除它。我正在考虑把作家当作一个关于类型推理如何与ST合作的窍门。 – applicative 2012-08-03 19:26:38

+0

@applicative否,解释没问题。也许补充说该功能将无法使用,这样两个答案都有这个重要的事实。 – 2012-08-03 19:31:25

+0

我不能说我很了解你上面说的,但是,我想知道你是否可以进一步解释为什么这个功能是不可能的。上下文是我有一个函数,它接受一个可变向量,做一些使用可变向量作为临时暂存空间的计算,然后需要返回一个浮点值。因为我不关心可变向量的变化,所以我想知道是否有办法忽略它的“状态变化”,并简单地从其中返回一个值。 – brooks94 2012-08-03 19:31:26