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