F# F中的上下文敏感数据处理#
我最近完成了一个项目,其中我正在生成字符串列表,我想知道最好的方法是什么 字符串生成是上下文敏感的,以确定是否可以接受(这是游戏中的一系列游戏,因此您必须知道最后一个游戏是什么) 我这样做的方式是使用一个传递了上下文参数和术语的函数,如果它是可接受的,它将递归地继续,如果它不是终止的(因为不能接受更多的字符串)。该函数还接收一个“length”参数,以确保它最终终止 基本上,这是生成一种语言(特定长度)接受的所有可能字符串 现在,我让这个工作,甚至相当好和干净,但我想知道是否有更好的方法来做到这一点。具体地说,“状态机”单子在生成上下文敏感语法方面是否工作良好?或者至少是类似的?问题似乎很简单,如果想启动类似于parsec的东西,是否还有其他结构可以有效地操纵语言F# F中的上下文敏感数据处理#,f#,grammar,monads,F#,Grammar,Monads,我最近完成了一个项目,其中我正在生成字符串列表,我想知道最好的方法是什么 字符串生成是上下文敏感的,以确定是否可以接受(这是游戏中的一系列游戏,因此您必须知道最后一个游戏是什么) 我这样做的方式是使用一个传递了上下文参数和术语的函数,如果它是可接受的,它将递归地继续,如果它不是终止的(因为不能接受更多的字符串)。该函数还接收一个“length”参数,以确保它最终终止 基本上,这是生成一种语言(特定长度)接受的所有可能字符串 现在,我让这个工作,甚至相当好和干净,但我想知道是否有更好的方法来做到这
任何想法都将不胜感激。我认为这个问题看起来很有趣,所以我尝试了几种不同的方法来实现它。下面的代码是最有希望的方法。我认为它解决了所描述的问题,尽管我不确定一些细节 基本上,它允许上下文敏感语法的形式,但只有一种非常简单的形式,其中每个生成只能依赖于前面的符号。下面的代码构建了一些组合器,这些组合器允许将作品直接编码为“生成器”,并负责场景后面的长度限制
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]]
键入sym=Xa | Xb | Xc//终端符号
键入word=sym list//一组终端
键入gen=int->sym list seq//生成给定长度的单词
///检查长度后,将上一个符号传递给生成器。
let(+>):sym->(sym->gen)->gen=
funxgl->if lx::xs}
让nil=seq{yield[]}//只生成空单词
让(| | |)xs ys l=Seq.append(xs l)(ys l)//两个生成器的并集
让notAccepted=Seq.empty//不生成任何内容
让tryAll g=Xa+>g | | | | Xb+>g | | | Xc+>g//从任何符号开始运行g
//非终端发电机。每个符号都将前一个符号作为参数,
//并生成(可能为空)符号列表序列。
设rec gR=函数Xa->Xb+>gS | | | Xc+>gR | | | nil
|Xc->Xb+>gS | |->不接受
和gS=函数Xb->Xa+>gR | |->未接受
让genTop=tryAll gR//顶级生成器以gR开头,带有任何符号
让words=genTop 4//生成长度不超过4的单词
//val单词:seq
//=seq[[Xa;Xb;Xa];[Xa;Xc;Xb;Xa];[Xa];[Xc;Xb;Xa]]
您可以发布您创建的任何代码吗?这将更容易理解你的意思。非常有趣的答案。。。我不知道我在做什么,我最初发布了这个,但我后来进入了一个象棋游戏,这将有助于一点。。。谢谢