5

タイプのインプレースベクトル関数が多数あります。

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

これらの関数はほとんどの場合その場で動作するため、それらの引数を変更可能なベクトルにして、作成、反復などを行うことができると便利です。ただし、最上位レベルでは、不変の「Haskell」/純粋なベクトルのみを使用したいと考えています。 .

問題の例を次に示します。

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

記述されたコードでは、LINE 1 でエラーが発生します。

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

LINE 1 をコメントアウトすると、LINE 2 でエラーが発生します。

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

さまざまな明示的な型付け (ScopedTypeVariables、明示的な foralls などを使用) を試しましたが、最初のエラーを修正する方法が見つかりませんでした。mLINE 1 エラーについてはST srunST.

LINE 2エラー(LINE 1がコメントアウトされている)の場合、私が思いついた唯一のことは

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

これは明らかに満足のいくものではありません。偽のクラスを作成する必要があり、クラス引数の種類を示すことだけが仕事であるさらに無意味なメソッドを使用します。次に、すべての汎用インスタンスを作成してm、スコープ内でtopLevelFunを使用できるようにし、制約を追加して をキャストできるようにしますf。もっと良い方法があるはずです。

ここでさまざまなことを間違っている可能性があるため、提案があれば役立ちます。

4

1 に答える 1

1

次のタイプはapplyFuncあなたに合っていますか?

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

すべてのST モナドRank2Typesで動作する必要がある関数を操作するために必要な拡張機能がある限り、問題なくコンパイルできます。この理由は is の型であるため、後のコードの本体はall に対して機能する必要があるため、 all に対して機能する必要があります。runST(forall s. ST s a) -> arunSTsgs

(代わりに、すべてで機能する関数を使用できますが、PrimMonads厳密にはそれらの数は少なくなります)。

GHC は上位の型を推論できません。推論しない非常に正当な理由がありRankNTypes(決定不能です)、Rank2理論的には推論可能ですが、GHC の人々は、「原理型が Hindley-Milner 型である場合にのみ推論する」というルールを決定しました。推論するのは非常に簡単で、コンパイラ作成者の仕事はそれほど難しくありません。

コメントでは、タプルの取得について尋ねます。ポリモーフィック型のタプルは、次のように必要でありImpredicativeTypes、実行できます

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

ただし、通常は数値を別の引数として単純に渡す方がよいでしょう。

于 2013-01-20T03:35:46.203 に答える