2013-01-19 14 views
5

ho un gran numero di in luogo vector funzioni del tipoScoping per le variabili di tipo temporaneo

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

Queste funzioni lavorano soprattutto sul posto, quindi è conveniente avere loro tesi essere un vettore mutevole in modo che Posso comporre, iterare, ecc. Tuttavia, al livello più alto, voglio solo lavorare con immutabili "Haskell"/pure vettori.

Ecco un esempio del problema:

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

Il codice come risultati scritti in un errore sulla linea 1:

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

commentare la linea 1 genera l'errore sulla linea 2:

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

Ho provato una varietà di digitazione esplicita (utilizzando ScopedTypeVariables, foral esplicito ls, ecc.) ma non ho trovato un modo per correggere il primo errore. Per l'errore LINE 1, sembra che m debba essere semplicemente considerato come ST s poiché sono in un runST.

Per l'errore di linea 2 (linea 1 commentato), l'unica cosa che mi è venuta in mente che funziona è

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 

che è ovviamente insoddisfacente: devo creare una classe falso, con un metodo ancora più inutile il cui unico compito è dimostrare i tipi di argomenti della classe. Quindi creo un'istanza generica per tutto in modo che possa avere m nell'ambito di topLevelFun, in modo da poter aggiungere un vincolo e trasmettere f. Ci deve essere un modo migliore.

Qui potrei fare una grande varietà di cose, quindi qualsiasi suggerimento sarebbe utile.

+0

'applyFunc' promette di funzionare per qualsiasi' PrimMonad m' il _caller_ sceglie, ma poi 'runST $ do ...' forza 'm' per essere' ST s'. Puoi aggiustarlo affermando che 'g' funziona per qualsiasi' PrimMonad m' _you_ scelto, o semplicemente restringendo 'm' per essere' ST s'. Ecco il [codice] (http://hpaste.org/80991). Se questo effettivamente risponde al tuo problema, fammelo sapere e scriverò una risposta. – Vitus

+0

Credo che funzioni, con alcune modifiche minori. Assicurati di aggiungere "Rank2Types" alle importazioni della lingua, e il tipo rank2 in "applyFunc" dovrebbe essere (per tutti i m. (PrimMonad m) => ...) Molte grazie! Rank2Types è passato alla fine. – crockeea

+0

Ah sì, ho dimenticato "RankNTypes" in ".ghci". A proposito, credo che 'Rank2Types' sia deprecato a favore di' RankNTypes'. – Vitus

risposta

1

Il seguente tipo per applyFunc funziona per voi?

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

Questo dovrebbe compilare con problema fuori fino a quando si ha la Rank2Types estensione, che è necessario perché si lavora con una funzione che deve lavorare su tutti monadi ST. La ragione di questo è il tipo di runST è (forall s. ST s a) -> a, quindi il corpo del codice dopo runST deve funzionare per tutti s, quindi g deve funzionare per tutti s.

(Si potrebbe invece prendere una funzione che funziona con tutti PrimMonads ma ce ne sono rigorosamente meno).

GHC non può inferire tipi di rango più alti. Ci sono ottime ragioni per non dedurre RankNTypes (è indecidibile), e anche se teoricamente lo Rank2 è ipotizzabile, la gente del GHC ha deciso per la regola "inferire se e solo se il tipo di principio è di tipo Hindley-Milner" che per persone come a me è molto facile ragionare, e rende il lavoro dei compilatori non così difficile.

Nei commenti si chiede di prendere una tupla.Tuple con tipi polimorfici richiedono ImpredicativeTypes e può essere fatto come

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 

anche se, di solito sarebbe meglio passare semplicemente il numero come argomento separato.