Is there a fast algorithm to determine the godel number of a term of a context free language?
假设我们有一个简单的语法规范。有一种枚举该语法项的方法,该方法通过对角迭代来确保任何有限项都具有有限位置。例如,对于以下语法:
1 2 3 4 5 6 | S ::= add add ::= mul | add + mul mul ::= term | mul * term term ::= number | ( S ) number ::= digit | digit number digit ::= 0 | 1 | ... | 9 |
您可以列举如下术语:
1 2 3 4 5 6 7 8 9 10 11 | 0 1 0+0 0*0 0+1 (0) 1+0 0*1 0+0*0 00 ... etc |
我的问题是:有没有办法做相反的事情?也就是说,采用该语法的有效术语,例如
对于这个特定的问题,如果我们允许自己选择不同的枚举顺序,那么我们可以做一些相当简单的事情。这个想法基本上是"每一位计数"中的一个,我也在评论中提到了这一点。首先,进行一些准备:一些导入/扩展,表示语法的数据类型以及漂亮的打印机。为了简单起见,我的位数仅增加到2(足够大,不再可以使用二进制数,但是又足够小,不会磨损我的手指和眼睛)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | {-# LANGUAGE TypeSynonymInstances #-} import Control.Applicative import Data.Universe.Helpers type S = Add data Add = Mul Mul | Add :+ Mul deriving (Eq, Ord, Show, Read) data Mul = Term Term | Mul :* Term deriving (Eq, Ord, Show, Read) data Term = Number Number | Parentheses S deriving (Eq, Ord, Show, Read) data Number = Digit Digit | Digit ::: Number deriving (Eq, Ord, Show, Read) data Digit = D0 | D1 | D2 deriving (Eq, Ord, Show, Read, Bounded, Enum) class PP a where pp :: a -> String instance PP Add where pp (Mul m) = pp m pp (a :+ m) = pp a ++"+" ++ pp m instance PP Mul where pp (Term t) = pp t pp (m :* t) = pp m ++"*" ++ pp t instance PP Term where pp (Number n) = pp n pp (Parentheses s) ="(" ++ pp s ++")" instance PP Number where pp (Digit d) = pp d pp (d ::: n) = pp d ++ pp n instance PP Digit where pp = show . fromEnum |
现在让我们定义枚举顺序。我们将使用两个基本的组合器,
1 2 3 4 5 6 |
让我们看看一些术语:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
好的,现在让我们开始吧。假设我们有两个无限列表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | type Nat = Integer -- bear with me here class Godel a where to :: a -> Nat from :: Nat -> a instance Godel Nat where to = id; from = id instance (Godel a, Godel b) => Godel (a, b) where to (m_, n_) = (m + n) * (m + n + 1) `quot` 2 + m where m = to m_ n = to n_ from p = (from m, from n) where isqrt = floor . sqrt . fromIntegral base = (isqrt (1 + 8 * p) - 1) `quot` 2 triangle = base * (base + 1) `quot` 2 m = p - triangle n = base - m |
这里的对的实例是标准的Cantor对角线。只是一些代数:使用三角形数字来确定您要去哪里/从哪里来。现在为此类创建实例很容易。
1 2 3 4 5 6 7 8 9 10 11 12 | -- this instance is a lie! there aren't infinitely many Digits -- but we'll be careful about how we use it instance Godel Digit where to = fromIntegral . fromEnum from = toEnum . fromIntegral instance Godel Number where to (Digit d) = to d to (d ::: n) = 3 + to d + 3 * to n from n | n < 3 = Digit (from n) | otherwise = let (q, r) = quotRem (n-3) 3 in from r ::: from q |
对于其余的三种类型,我们将按照上面的建议检查标记位,以确定要发出的构造函数,并将其余的位用作对角线列表的索引。所有这三个实例看起来都非常相似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | instance Godel Term where to (Number n) = 2 * to n to (Parentheses s) = 1 + 2 * to s from n = case quotRem n 2 of (q, 0) -> Number (from q) (q, 1) -> Parentheses (from q) instance Godel Mul where to (Term t) = 2 * to t to (m :* t) = 1 + 2 * to (m, t) from n = case quotRem n 2 of (q, 0) -> Term (from q) (q, 1) -> uncurry (:*) (from q) instance Godel Add where to (Mul m) = 2 * to m to (m :+ t) = 1 + 2 * to (m, t) from n = case quotRem n 2 of (q, 0) -> Mul (from q) (q, 1) -> uncurry (:+) (from q) |
就是这样!现在,我们可以在语法分析树及其Godel编号之间"高效"转换此语法。此外,此翻译与上面的枚举匹配,您可以验证:
我们确实滥用了该特定语法的许多不错的特性-非歧义性,几乎所有非终结词都有无限多个派生这一事实-但是这种技术的变化可以使您走得很远,尤其是如果您不太严格的话要求每个数字都必须与唯一的事物相关联。
另外,顺便说一句,您可能会注意到,除了