2011-12-01 17 views
17

Aquí están algunos pragmas y algunas importaciones:error de tipo 2 con rangos de tipos y composición de la función

{-# LANGUAGE ScopedTypeVariables #-} 

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

Ahora aquí es mi problema. Los siguientes typechecks código:

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

Sin embargo, cuando se sustituye la $ con la composición:

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

me sale este error:

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) } 

¿Cuál es werid es, si me dan la función composición de su propio nombre, luego vuelve a marcar de nuevo:

elemSTArray = elems . runSTArray 

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

No estoy seguro de lo que está pasando aquí. Esperaría que la segunda pieza de código sea chequeada muy bien. Y no entiendo por qué se vuelve a tipear si le doy a la función compuesta su propio nombre.

Esta es una versión simplificada de algún código que tuve que se rompió al actualizar de GHC 6.2 a 7 y estoy tratando de entender por qué sucede esto ahora. ¡Gracias por ayudar!

+0

No soy realmente un programador de Haskell, pero ¿cuál es la precedencia de la composición relativa a '$'? ¿Qué sucede si entre paréntesis la sub-expresión 'elems. runSTArray'? – Gian

+1

No puedo reproducir esto con GHC 6.12.1. – opqdonut

+0

Gian: '$' tiene una prioridad menor que '.', de modo que si hago una paréntesis entre las expresiones secundarias, se comporta igual. opqdonut: Esto no me sucedió ni en GHC 6.2 pero sí en GHC 7.0.3 – Drekembe

Respuesta

15

Como ya se insinúan en el título de la entrada, el problema tiene que ver con runSTArray tener un tipo polimórfico de rango 2.

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

Con

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

y

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

escribiendo runSTArray $ ... significa que el tipo variable a en el esquema de tipo ($) necesita ser instanciado con un tipo polimórfico en lugar de un tipo monomórfico. Esto requiere el llamado polimorfismo impredicativo. La forma en que GHC implementa el polimorfismo impredicativo se explica en el documento de ICFP 2008 de Dimitrios Vytiniotis, Stephanie Weirich y Simon Peyton Jones: FPH : First-class Polymorphism for Haskell. En resumidas cuentas, si bien la FPH a menudo le proporciona el comportamiento que espera, la capacidad de escritura a veces no se conserva en transformaciones simples como las que describe en su pregunta: consulte la Sección 6.2 del documento mencionado anteriormente.

9

Stefan me pegaba a la respuesta - el truco es que no es la $ vs . entre elems y runSTArray esa es la cuestión - es la siguiente $runSTArray. Dado que something $ rankNthing es tan común, hay una parte inteligente (se me olvidan los detalles) que intenta dejar que lo haga como un caso de esquina. Pero de alguna manera, usar la composición más temprano evita esto. La ubicación de la cuestión se demuestra por el hecho de que el siguiente será typecheck:

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

no estoy seguro de que esto es un error en sí, pero es ciertamente un comportamiento inesperado vale la pena crear un boleto acerca, ya que podría seguir siendo un algoritmo mejor para detectar casos como el que proporcionó.

Cuestiones relacionadas