2011-12-01 11 views
17

Ecco alcuni pragma e alcune importazioni:errore di tipo con rango-2 tipi e la funzione di composizione

{-# LANGUAGE ScopedTypeVariables #-} 

import Control.Monad.ST 
import Data.Array.ST 
import Data.Array 

Ora qui è il mio problema. I seguenti typechecks codice:

foo :: forall a. a -> [a] 
foo x = elems $ runSTArray $ do 
    newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a) 

Tuttavia, quando si sostituisce la $ con la composizione:

foo :: forall a. a -> [a] 
foo x = elems . runSTArray $ do 
    newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a) 

ottengo questo errore:

Couldn't match expected type `forall s. ST s (STArray s i0 e0)' 
      with actual type `ST s0 (STArray s0 Int a)' 
In the expression: 
    newListArray (1, 10) (replicate 10 x) :: ST s (STArray s Int a) 
In the second argument of `($)', namely 
    `do { newListArray (1, 10) (replicate 10 x) :: 
      ST s (STArray s Int a) }' 
In the expression: 
     elems . runSTArray 
    $ do { newListArray (1, 10) (replicate 10 x) :: 
      ST s (STArray s Int a) } 

Cosa c'è werid è, se mi danno la funzione composizione il proprio nome, quindi riprova digitando nuovamente:

elemSTArray = elems . runSTArray 

foo :: forall a. a -> [a] 
foo x = elemSTArray $ do 
    newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int a) 

Non sono sicuro di cosa sta succedendo qui. Mi aspetto che il secondo pezzo di codice digiti bene. E non capisco perché riprova a digitare se conferisco il nome alla funzione composta.

Questa è una versione semplificata di un codice che ho avuto che si è rotto durante l'aggiornamento da GHC 6.2 a 7 e sto cercando di capire perché questo accade ora. Grazie dell'aiuto!

+0

Non sono realmente un programmatore Haskell, ma qual è la precedenza della composizione relativa a '$'? Cosa succede se si parentesi la sottoespressione 'elem. runSTArray'? – Gian

+1

Non riesco a riprodurlo con GHC 6.12.1. – opqdonut

+0

Gian: '$' ha una precedenza inferiore rispetto a '.', quindi se parentesi la sottoespressione si comporta allo stesso modo. opqdonut: Questo non mi è successo né su GHC 6.2, ma su GHC 7.0.3 – Drekembe

risposta

15

Come già accennare a nel titolo del tuo post, il problema ha a che fare con runSTArray avere un tipo polimorfico di rango 2.

runSTArray :: Ix i => (forall s. ST s (STArray s i e)) -> Array i e 

Con

elems :: Ix i => Array i e -> [e] 

e

($) :: (a -> b) -> a -> b 

scrittura runSTArray $ ... significa che la variabile di tipo a nello schema tipo di ($) deve essere istanziato con un tipo polimorfico piuttosto che un tipo monomorfico. Ciò richiede il cosiddetto polimorfismo impredicativo. Il modo in cui GHC implementa il polimorfismo impredicativo è spiegato nel documento ICFP 2008 di Dimitrios Vytiniotis, Stephanie Weirich e Simon Peyton Jones: FPH : First-class Polymorphism for Haskell. La linea di fondo è che mentre FPH ti dà spesso il comportamento che ti aspetti, la tipizzazione a volte non viene mantenuta in semplici trasformazioni come quelle che descrivi nella tua domanda: vedi la Sezione 6.2 del documento sopra menzionato.

9

Stefan mi ha battuto per la risposta - il po 'complicato è che non è la $ vs . tra elems e runSTArray che è il problema - è il seguente $runSTArray. Dal momento che something $ rankNthing è così comune, c'è un po 'di genio (dimentico i dettagli) che cerca di farcela come caso d'angolo. Ma in qualche modo usare la composizione in precedenza impedisce questo. La posizione della questione è dimostrato dal fatto che la seguente vi TYPECHECK:

foo x = (elems . runSTArray) (
    (newListArray (1,10) (replicate 10 x) :: ST s (STArray s Int String))) 

io non sono sicuro che questo è un bug di per sé, ma la sua certamente un comportamento imprevisto pena la creazione di un biglietto su, dal momento che ci potrebbe essere ancora un algoritmo migliore per individuare casi come quello che hai fornito.