2011-03-25 17 views
5

Quiero escribir una función para reemplazar renameString nombres (que representan identificadores jerárquicos) en mis AST con GUID nombres (enteros) a partir de una tabla de símbolos realizada como estado escondido en una mónada Renamer.¿Es posible usar SYB para transformar el tipo?

Tengo un tipo AST a que se parametriza sobre el tipo de nombre. Los nombres en las hojas de la AST son de tipo Name a:

data Name a = Name a 

que hace que sea fácil para ellos se dirigen con un transformador SYB.

El analizador se escribe (ignorando la posibilidad de error por razones de brevedad):

parse :: String -> AST String 

y quiero la función rename a ser escrito:

rename :: AST String -> Renamer (AST GUID) 

¿Es posible utilizar SYB para transformar todos Name String 's en Name GUID' s con un transformador:

resolveName :: Name String -> Renamer (Name GUID) 

y todos los demás valores desde c String hasta c GUID transformando sus hijos y pegándolos junto con el mismo constructor, aunque con un parámetro de tipo diferente?

La función everywhereM está cerca de lo que quiero, pero solo puede transformar c a -> m (c a) y no c a -> m (c b).

Mi solución alternativa (que no sea escribir la caldera de la placa con la mano) es eliminar el parámetro de tipo de AST, y definir Name así:

data Name = StrName String 
      | GuidName GUID 

de modo que el cambio de nombre se escribiría:

rename :: AST -> Renamer AST 

haciendo que funcione con everywhereM. Sin embargo, esto dejaría la posibilidad de que un AST aún podría contener StrName después de haber sido renombrado. Quería utilizar el sistema de tipos para capturar formalmente el hecho de que un nombre AST solo puede contener GUID nombres.

+2

Si todos sus tipos tienen un solo parámetro, probablemente pueda convertirlos en instancias de Functor, Plegable y Traversable, luego use la operación de mapeo de Traversable. En general, cambiar el tipo de árboles de sintaxis es problemático: la parametrización de un árbol de sintaxis no es muy flexible (Haskell solo tiene clases para el caso de Arity 1 Functor) y sin parámetros tiene el problema de "nanopass". Neil Brown escribió un artículo sobre esto en el Taller Haskell hace un par de años. –

+0

Gracias! Encontré el [artículo] (http://offog.org/publications/fita200811-generics.pdf). Se ve muy interesante. – pat

+0

Quieres 'sintetizar'. – sclv

Respuesta

2

Una solución (tal vez menos eficiente que usted esperaba) sería hacer su AST una instancia de Functor, Data y Typeable (GHC 7 probablemente puede derivar todos ellos para usted) y luego hacer:

import Data.Generics.Uniplate.Data(universeBi) -- from the uniplate package 
import qualified Data.Map as Map 

rename :: AST String -> Renamer (AST GUID) 
rename x = do 
    let names = nub $ universeBi x :: [Name String] 
    guids <- mapM resolveName names 
    let mp = Map.fromList $ zip names guids 
    return $ fmap (mp Map.!) x 

dos puntos:

  1. estoy asumiendo que es fácil de eliminar el bit Name de resolveName, pero sospecho que es.
  2. Puede cambiar universeBi por algo equivalente en SYB, pero me resulta mucho más fácil de entender las versiones de Uniplate.
Cuestiones relacionadas