临时类型变量的范围 [英] Scoping for temporary type variables

查看:109
本文介绍了临时类型变量的范围的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有大量的矢量函数

  f ::(M.MVector vr,PrimMonad m)=> 
v(PrimState m)r - > v(PrimState m)r - > m()

这些函数大多在原地工作,所以将它们的参数设置为a这样我就可以编写,迭代等等。但是,在顶层,我只想使用不可变的Haskell/纯矢量。

这个问题的一个例子是:

$ $ p $ $ $ $ $ $ $ b $ {$#$ {$#$ $ $ $ $ $ $ $ $ $ $ $ $ $ { - #LANGUAGE TypeFamilies,
ScopedTypeVariables,
MultiParamTypeClasses,
FlexibleInstances# - }

导入Data.Vector.Generic作为V隐藏(eq)
导入Data.Vector.Generic.Mutable作为M
导入Control.Monad.ST
import Control.Monad.Primitive

f ::(M.MVector vr,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 vr,PrimMonad m, V.Vector v'r,v〜Mutable v')=>
(v(PrimState m)r - > v(PrimState m)r - > m()) - > v'r - > v'r
applyFunc gx = runST $ do
y< - V.thaw x
gyy - LINE 1
V.unsafeFreeze y

topLevelFun: :(V.Vector vr)=> r - > vr
topLevelFun a =
let x = V.在applyFunc fx中复制10 a
- LINE 2

写入的代码导致LINE 1出错:

 无法推断出m〜ST s)
预期类型:ST s()
实际类型:m()
,返回类型g,LINE 1


注释LINE 1导致LINE 2出错:

 在使用`applyFun'

$ b引起的约束:
(PrimMonad m0)中含糊不清的类型变量`m0'
$ b

我尝试了各种显式类型(使用ScopedTypeVariables,显式合并等),但还没有找到解决第一个错误的方法。对于LINE 1错误,似乎应该简单地将 m 推断为 ST s ,因为我处于 runST



对于LINE 2错误(LINE 1注释掉了),我唯一想到的作品是

  class Fake mv其中
kindSig :: ma - > v b c

实例假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. applyFunc(f :: Transform mvr)中的10 a
x - LINE 2

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



我可能会在这里做很多错误的事情,所以任何建议都会有帮助。

解决方案

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

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

只要您有 Rank2Types 扩展名,这是你需要的,因为你需要使用一个必须在所有 ST单元上工作的函数。原因是 runST 的类型是(所有s ST s a) - >一个,所以 runST 之后的代码的主体需要为所有的 s 工作,因此 g 需要适用于所有 s



(你可以改用一个可以与所有 PrimMonads 一起工作的函数,但是这些函数的数量会少得多)。

GHC无法推断更高的排名类型。有很好的理由不推断 RankNTypes (它是不可判定的),尽管 Rank2 在理论上是可推断的, GHC的人决定这个规则只要原则类型是Hindley-Milner类型就可以推断出来,这对于像我这样的人来说很容易推理,并且让编译器编写者的工作不那么难。



在关于获取元组的评论中。具有多态类型的元组需要 ImpredicativeTypes 并且可以像

  applyFuncInt: :(Vector va)=> 
((forall s。Mutable v s a - > Mutable v s a - > ST s()),Int)
- > v a - > va
applyFuncInt(g,_)x = runST $ do
y< - V.thaw x
gyy
V.unsafeFreeze y

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

I have a large number of in place vector functions of the type

f :: (M.MVector v r, PrimMonad m) => 
     v (PrimState m) r -> v (PrimState m) r -> m ()

These functions mostly work in-place, so it is convenient to have their argument be a mutable vector so that I can compose, iterate, etc. However, at the top level, I only want to work with immutable "Haskell"/pure vectors.

Here is an example of the problem:

{-# 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

The code as written results in an error on LINE 1:

Could not deduce (m ~ ST s)
   Expected type: ST s ()
   Actual type: m ()
   in the return type of g, LINE 1

Commenting out LINE 1 results in the error on LINE 2:

Ambiguous type variable `m0' in the constraint:
    (PrimMonad m0) arising from a use of `applyFun'

I've tried a variety of explicit typing (using ScopedTypeVariables, explicit foralls, etc) but haven't found a way to fix the first error. For the LINE 1 error, it seems that m should simply be inferred to be ST s since I'm in a runST.

For the LINE 2 error (with LINE 1 commented out), the only thing I've come up with that works is

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

which is obviously unsatisfactory: I have to create a fake class, with an even more pointless method whose only job is to demonstrate the kinds of the class arguments. Then I create a generic instance for everything so that I can have m in scope in topLevelFun, so that I can add a constraint and cast f. There has GOT to be a better way.

I could be doing a wide variety of things wrong here, so any suggestions would be helpful.

解决方案

Does the following type for applyFunc work for you?

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

That should compile with out problem so long as you have the Rank2Types extension, which you need because you work with a function that has to work on all ST monads. The reason for this is the type of runST is (forall s. ST s a) -> a, so the body of the code after runST needs to work for all s, hence g needs to work for all s.

(You could instead take a function that work with all PrimMonads but there are strictly fewer of those).

GHC can not infer higher rank types. There are very good reasons to not infer RankNTypes (it is undecidable), and although Rank2 is in theory inferable, the GHC people decided for the rule "infer if and only if the principle type is a Hindley-Milner type" which for people like me is very easy to reason about, and makes the compiler writers job not so hard.

In the comments you ask about taking a tuple. Tuples with polymorphic types require ImpredicativeTypes and can be done like

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

although, usually it would be better to simply pass the number as a separate argument.

这篇关于临时类型变量的范围的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆