2017-05-09 8 views
2

부 프로젝트의 경우 현재 추상적 인 구문 트리를 처리하고 규칙에 따라 변환해야합니다 (세부 사항은 중요하지 않음).복잡한 AST에서 재귀 분석하기

AST 자체는 중요하지 않으며 일부 형식으로 만 제한된 하위 표현식이 있음을 의미합니다. . (예를 들어, 운영자 A는 유형 B의 인 인수되지 않은 Expr를 취해야합니다 내 데이터 타입의 대폭 단순화 감소 버전은 다음과 같습니다

data Expr = List [Expr] 
      | Strange Str 
      | Literal Lit 
data Str = A Expr 
      | B Expr 
      | C Lit 
      | D String 
      | E [Expr] 
data Lit = Int Int 
      | String String 

내 목표는 명시 적으로 재귀을 고려하고 의지하는 것입니다 . 내가하지 않았다면

data ExprF a = List [a] 
      | Strange (StrF a) 
      | Literal (LitF a) 
data StrF a = A a 
      | B a 
      | C (LitF a) 
      | D String 
      | E [a] 
data LitF a = Int Int 
      | String String 

: 내 AST에 필요한 인수 분해를 적용 작동하는 매우 강력한 범용 도구를 제공 thesetwo 우수 블로그 게시물에서 입증 된 바와 같이 재귀 방식 대신, 우리와 끝까지 엉망진창, type Expr = Fix ExprF은 이전에 정의 된 Expr과 동형이어야합니다. 내가 잘 입력해야 cata에 대한 Str :: ExprF a의 내부에 패턴 일치 B a :: StrF a에 가지고

그러나, 이러한 경우에 cata를 작성하는 것은, 오히려 지루한된다. 원래의 AST 전체에 대해 이것은 실현 불가능합니다.

나는 그것이 내 문제에 대한 해결책 인 것처럼 보였지만, 중복 된 고차 유형 클래스 등의 사용자 친화적이지 않은 인터페이스는 매우 불필요한 보편적 인 것인데 나는 fixing GADTs을 발견했습니다.

그래서, 내 질문을 요약합니다 :

  1. 는 GADT로 AST 이것에 대해 갈 수있는 올바른 방법을 재 작성되어 있습니까?
  2. 그렇다면 예제를 어떻게 잘 작동하는 버전으로 변환 할 수 있습니까? 두 번째 메모에서 GHC에 더 높은 종류의 Functor을 더 잘 지원합니까?

답변

2

데이터 유형의 재귀를 분리하려는 경우 Functor을 파생하면 완료됩니다. 재귀 스키마를 얻으려면 멋진 기능이 필요하지 않습니다. (보조 노트로, Lit 데이터 형식을 매개 변수화 할 이유가 없습니다.)

폴드는 다음과 같습니다

newtype Fix f = In { out :: f (Fix f) } 

gfold :: (Functor f) => (f a -> a) -> Fix f -> a 
gfold alg = alg . fmap (gfold alg) . out 

합니다 (alg 매개 변수)를 대수를 지정하려면에 대한 사례 분석을 할 필요가 ExprF이지만 폴드가 12 개 이상의 매개 변수를 갖게 될 수도 있습니다. 하나는 각 데이터 생성자에 대한 매개 변수입니다. 그렇게하면 실제로 많은 타이핑을 저장하지 않고 읽는 것이 훨씬 더 어려워집니다. 원하는 경우 (일반적으로 순위 2 유형이 필요할 수 있음) 모든 매개 변수를 레코드로 패키지화 한 다음 레코드 업데이트를 사용하여 다양한 상황에서 "기본"동작을 제공하는 "미리 만들어진"레코드를 업데이트 할 수 있습니다 . 이런 식으로 접근하는 오래된 종이 Dealing with Large Bananas이 있습니다. 내가 분명히 말하려는 것은 레코드를 취하는 함수로 위의 gfold 함수를 포장하고 케이스 분석을 수행하고 각 사례에 대한 레코드의 해당 필드를 호출하는 대수를 전달하는 것입니다.

물론 GHC Generics 나 the various "generic/polytypic" programming libraries과 같이이 대신 스크랩하기 Your Boiler Plate를 사용할 수 있습니다.당신은 기본적으로 그들이하는 일을 재현하고 있습니다.