GADT之间的映射

时间:2017-02-27 06:36:20

标签: haskell lexer gadt

我对Haskell相对较新,并且使用它来编写编译器,使用Alex和Happy。我写的语言是空格敏感的:块是由缩进分隔的,并且通过增加两个缩进级别继续行。

虽然我已经使用Alex的monadUserState包装器走了这条路,但是作为一个不熟悉monad的人我发现这种方法非常混乱。因此,我在思考而不是将lexing过程分为两个阶段,一个是扫描令牌,另一个是用缩进,持续和持续令牌替换原始空白(这种方法可能性能较差,但我和#39 ; m在这个阶段并不十分关心表现。)

描述词汇分析两个阶段的GADT如下所示:

{-# Language DataKinds, GADTs, KindSignatures #-}

module Tokens where

data Phase = P0 | Pn

data Token (p :: Phase) where

  -- Phase 0
  TokenTabs :: Int -> Token 'P0

  -- Phase n
  TokenIndent :: Token 'Pn
  TokenDedent :: Token 'Pn
  TokenLineCont :: Token 'Pn

  -- Common tokens
  TokenIf :: Token p
  -- ...
  -- Many other data constructors with result Token p, that can appear in either stage
  -- ...
  TokenName :: String -> Token p

执行第二个lexing阶段的函数如下所示:

postLex :: [Token 'P0] -> [Token 'Pn]
postLex tokens = postLex' 0 tokens where
  postLex' :: Int -> [Token 'P0] -> [Token 'Pn]
  postLex' depth [] = replicate depth TokenDedent
  postLex' depth ((TokenTabs n) : rest)
    | n == depth = postLex' depth rest
    | n == (depth + 1) = TokenIndent : postLex' n rest
    | n >= (depth + 2) = TokenLineCont : postLex' depth rest
    | n < depth = replicate (depth - n) TokenDedent ++ postLex' n rest
  postLex' depth (t:rest) = t : postLex' depth rest

我遇到的问题是,在匹配标签令牌后,所有剩余的令牌都可以存在于任一阶段,但我不知道使用签名TokenX转换数据构造函数的结果的任何好方法:: Token p从Token P0到Token Pn。

有没有一种很好的方式来执行这样的转换?如果没有,是否有任何替代方法可以保护类型安全?我非常感兴趣,因为我想在这个项目的后期转换AST的各个不同阶段时,类似的方法会很有用。

0 个答案:

没有答案