2014-07-13 14 views
15

Mentre l'iterazione il mio codice verso una versione corretta, mi sono imbattuto nel seguente curiosità:Let-rinomina codice pause funzione

{-# LANGUAGE RankNTypes #-} 

module Foo where 

import Data.Vector.Generic.Mutable as M 
import Control.Monad.Primitive 

-- an in-place vector function with dimension 
data DimFun v m r = 
    DimFun Int (v (PrimState m) r -> m()) 

eval :: (PrimMonad m, MVector v r) => DimFun v m r -> v (PrimState m) r -> m() 
eval = error "" 

iterateFunc :: (PrimMonad m, MVector v r) 
      => (forall v' . (MVector v' r) => DimFun v' m r) -> DimFun v m r 
iterateFunc = error "" 

f :: (PrimMonad m, MVector v r) 
     => DimFun v m r 
f = error "" 

iteratedF :: (MVector v r, PrimMonad m) 
      => v (PrimState m) r -> m() 
iteratedF y = 
    let f' = f 
    in eval (iterateFunc f') y 

Questo codice non si compila:

Testing/Foo.hs:87:14: 
    Could not deduce (MVector v0 r) arising from a use of ‘f’ 
    from the context (MVector v r, PrimMonad m) 
     bound by the type signature for 
       iteratedF :: (MVector v r, PrimMonad m) => 
           v (PrimState m) r -> m() 
     at Testing/Foo.hs:(84,14)-(85,39) 
    The type variable ‘v0’ is ambiguous 
    Relevant bindings include 
     f' :: DimFun v0 m r (bound at Testing/Foo.hs:87:9) 
     y :: v (PrimState m) r (bound at Testing/Foo.hs:86:11) 
     iteratedF :: v (PrimState m) r -> m() 
     (bound at Testing/Foo.hs:86:1) 
    In the expression: f 
    In an equation for ‘f'’: f' = f 
    In the expression: let f' = f in eval (iterateFunc f') y 

Testing/Foo.hs:88:26: 
    Couldn't match type ‘v0’ with ‘v'’ 
     because type variable ‘v'’ would escape its scope 
    This (rigid, skolem) type variable is bound by 
     a type expected by the context: MVector v' r => DimFun v' m r 
     at Testing/Foo.hs:88:14-27 
    Expected type: DimFun v' m r 
     Actual type: DimFun v0 m r 
    Relevant bindings include 
     f' :: DimFun v0 m r (bound at Testing/Foo.hs:87:9) 
    In the first argument of ‘iterateFunc’, namely ‘f'’ 
    In the first argument of ‘eval’, namely ‘(iterateFunc f')’ 
Failed, modules loaded: none. 

Tuttavia, se cambio la definizione di iteratedF per

iteratedF y = eval (iterateFunc f) y 

il codice viene compilato con l'apposito GHC 7.8.2. Questa domanda non riguarda le firme oi tipi di dati dall'aspetto strano, è semplicemente questo: perché rinominare f in f' interrompe il codice? Sembra che debba essere un bug per me.

risposta

7

Il problema non è ovviamente la nuova denominazione, ma il legame ad una nuova variabile. Poiché iterateFunc è Rank-2, ha bisogno di una funzione di argomento polimorfico. Naturalmente, f è polimorfico in v, quindi può essere utilizzato. Ma quando scrivi f' = f, non è chiaro quale sia il tipo f': lo stesso tipo polimorfo come f, o un tipo monomorfico, probabilmente in relazione con un'altra variabile di tipo in iteratedF che il compilatore non ha ancora dedotto.

Il compilatore ha come valore predefinito l'opzione monomorfica; come dice chi è colpa del restringimento del monomorfismo, quindi se lo spegni, il tuo codice viene compilato in realtà.

Ancora, lo stesso problema può verificarsi anche senza la limitazione di monomorfismo nel codice RankNTypes, non può essere completamente evitato. L'unica soluzione affidabile è una firma locale, che in genere richiede ScopedTypeVariables.

+2

un altro caso della temuta limitazione del monomorfismo, quindi. – crockeea

+4

Non penso sia vero che la rinomina non possa creare problemi in puro Haskell 98. Si consideri 'let f = show in f 1 ++ f True'. –

12

Disabilitando la restrizione di monomorfismo, posso compilare il codice. Quindi, è sufficiente aggiungere

{-# LANGUAGE NoMonomorphismRestriction #-} 

all'inizio del file.

Il motivo dell'errore tipo è che la definizione

let f' = f 

non utilizza un modello funzionale (es f' x y = ...), quindi la restrizione monomorfismo calci e forze f' essere monomorfico, mentre iterateFunc richiede un polimorfo funzione.

alternativa, aggiungere un tipo di annotazione

let f' :: (PrimMonad m, MVector v r) => DimFun v m r 
    f' = f 
+1

Ciò che è strano è che il flag 'NoMono ...' è persino necessario in ghc-7.8 ... Ho pensato che avesse la limitazione del monomorfismo completamente disattivata, ma a quanto pare funziona solo al livello più alto o qualcosa del genere. – leftaroundabout

+7

@leftaroundabout Penso che sia solo GHCi – bennofs

Problemi correlati