2011-03-25 3 views
5

ASTGUID 모나드에서 숨김 상태로 전달 된 기호 테이블의 이름 (정수)을 사용하여 String (계층 적 식별자를 나타냄) 이름을 바꿀 rename 함수를 작성하고 싶습니다.SYB를 사용하여 유형을 변환 할 수 있습니까?

나는 AST a 유형의 이름 유형에 대해 매개 변수가 지정되어 있습니다. 대서양 표준시의 잎에서 이름 유형 Name a의 위치 :

data Name a = Name a 

이 쉽게 SYB 변압기를 대상으로 할 수있다. 파서는 입력 된

(짧음에 대한 오류의 가능성을 무시) :

parse :: String -> AST String 

을하고 난 rename 기능은 입력해야 할 :

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

이 가능 변환 SYB을 사용할 수 있나요 모두 Name String에 의 변압기가있는 경우 :

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

및 기타 모든 값은 c String에서 c GUID까지이며, 다른 유형 매개 변수를 사용하더라도 동일한 생성자를 사용하여 자녀를 변형하여 붙여 넣을 수 있습니다.

everywhereM 기능이 원하는대로 가깝지만 c a -> m (c a)이 아닌 c a -> m (c b) 만 변환 할 수 있습니다.

data Name = StrName String 
      | GuidName GUID 

이름 바꾸기가 입력 될 수 있도록하는 것이 :

(손으로 보일러 플레이트를 쓰는 것보다 다른)

내 대체 솔루션은 AST에서 유형 매개 변수를 제거하고,이 같은 Name을 정의하는 것입니다

rename :: AST -> Renamer AST 

everywhereM과 호환됩니다. 그러나이 경우 AST은 여전히 ​​이름을 바꾼 후에 StrName을 보유 할 수 있습니다. 형식 시스템을 사용하여 이름이 AST이고 이름이 GUID 인 경우에만 형식적으로 캡처하려고했습니다.

+2

모든 유형에 단일 매개 변수가있는 경우 Functor, Foldable 및 Traversable의 인스턴스를 만든 다음 Traversable의 mapM 연산을 사용할 수 있습니다. 일반적으로 구문 트리의 유형을 변경하는 것은 문제가 있습니다. 구문 트리를 매개 변수화하는 것은 매우 유연하지 않습니다 (Haskell은 arity 1 Functor의 경우 클래스를 가지고 있습니다). 매개 변수가 없으면 "nanopass"문제가 있습니다. Neil Brown은 2 년 전에 하스켈 워크샵에서 이걸 써 냈습니다. –

+0

감사합니다. 나는 [논문] (http://offog.org/publications/fita200811-generics.pdf)을 발견했다. 그것은 매우 흥미 보입니다. – pat

+0

당신은'synthesize'를 원합니다. – sclv

답변

2

하나 개의 솔루션 (아마 덜 효율적인 당신이 바라고보다) 당신의 AST (아마 당신이 모든을 유도 할 수 GHC 7) Functor, DataTypeable의 인스턴스를 만들 것 다음을 수행하십시오

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 

두 지점 :

  1. 나는 그것이 resolveName에서 Name 비트를 제거하기 쉽게 있으리라 믿고있어,하지만 난 그것을 의심.
  2. SYB에서 universeBi 스위치를 사용할 수 있지만 Uniplate 버전을 훨씬 쉽게 이해할 수 있습니다.