使用monadic rank-2类型

时间:2014-07-14 20:23:08

标签: 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 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相关,那里没有字典可以去的地方,但这真的只是在黑暗中刺伤。

1 个答案:

答案 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

将类约束移动到数据类型对您来说可能看起来很可怕,但实际上,您已经有了类限制。 PrimStatePrimMonad的关联类型系列,因此,为了生成或使用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}}