GADT之间的映射

我对Haskell比较陌生,正在使用它编写一个编译器,使用Alex和Happy。 我为它写的语言是空白敏感的:块由缩进分隔,并且行继续增加两个缩进级别。

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

描述词法分析两个阶段的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转换为数据构造函数结果的好方法到令牌Pn。

有没有一种很好的方式来执行这种转换? 如果没有,有没有其他方法可以保护类型安全? 我很感兴趣,因为我想象一下类似的方法在本项目稍后的AST各个不同阶段之间转换时会很有用。

链接地址: http://www.djcxy.com/p/65641.html

上一篇: Mapping between GADTs

下一篇: What causes Happy to throw a parse error?