代码之家  ›  专栏  ›  技术社区  ›  Snark

F中的上下文敏感数据处理#

  •  3
  • Snark  · 技术社区  · 14 年前

    我这样做的方式是通过一个传递上下文参数和术语的函数,如果可以接受,它将递归地继续,如果它没有终止(因为不能接受更多的字符串)。该函数还接收一个“length”参数,以确保它最终终止

    基本上,这是生成一种语言(具有一定长度)所接受的所有可能的字符串。

    现在,我得到了这个工作,甚至相当好和干净,但我想知道是否有一个更好的方法来做到这一点。具体来说,“状态机”单子能否很好地生成上下文敏感语法?或者至少是类似的?问题似乎很简单,如果想启动parsec之类的东西,是否还有其他结构可以有效地操纵语言?

    1 回复  |  直到 14 年前
        1
  •  0
  •   RD1    13 年前

    我觉得这个问题看起来很有趣,所以我尝试了几种不同的实现方法。下面的代码是最有希望的方法。我认为它解决了所描述的问题,尽管我不确定一些细节。

    基本上,它允许上下文敏感语法的一种形式,但只有一种非常简单的形式,其中每个产品只能依赖于前面的符号。下面的代码构建了一些组合器,允许将产品直接编码为“生成器”,并考虑场景后面的长度限制。

    type sym = Xa | Xb | Xc          // The terminal symbols 
    type word = sym list             // A string of terminals
    
    type gen = int -> sym list seq   // Generate words up to the given length
    
    /// Passes the previous symbol to a generator, after checking the length.
    let (+>) : sym  -> (sym -> gen) -> gen = 
        fun x g l -> if l<=0 then Seq.empty 
                             else seq { for xs in g x (l-1) -> x :: xs }
    
    let nil _ = seq { yield [] }                    // Generate just the empty word            
    let (|||) xs ys l = Seq.append (xs l) (ys l)    // Union of two generators
    let notAccepted _ = Seq.empty                   // Don't generate anything
    
    let tryAll g = Xa +> g ||| Xb +> g ||| Xc +> g  // Run g starting with any sym
    
    // Generators for non-terminals.  Each takes the previous symbol as an argument,
    // and generates a (possibly empty) sequence of lists of symbols.
    let rec gR = function Xa ->  Xb +> gS ||| Xc +> gR  ||| nil  
                        | Xc ->  Xb +> gS                        | _ -> notAccepted
        and gS = function Xb ->  Xa +> gR                        | _ -> notAccepted
    
    
    let genTop = tryAll gR  // The top level generator begins with gR with any sym
    
    let words = genTop 4    // Generate words up to length 4
    // val words : seq<sym list> 
    //           = seq [[Xa; Xb; Xa]; [Xa; Xc; Xb; Xa]; [Xa]; [Xc; Xb; Xa]]