我正确使用功能组合吗?

Cha*_*ion 7 f# functional-programming function-composition

为了理解函数式编程的功能,我将一些基本函数组合在一起,您可以将它们组合在一起构建复杂的正则表达式.现在经过一些测试我发现它有效,但你可以用任何可行的语言编写一些可怕的代码.这是你会找到专业的F#程序员写的代码还是我滥用这个功能?

注意: test具体是我指的是什么.

type State = { input:string; index:int; succeeded:bool }
type Matcher = State -> State

let term (cs:char Set)  =
    fun s ->
        if s.succeeded && s.index < s.input.Length && cs.Contains s.input.[s.index] then  
            { input = s.input; index = s.index + 1; succeeded = true }
        else 
            { input = s.input; index = s.index; succeeded = false }

let quantify (term, min, max) =
    let rec inner (s:State, count) =
        if s.succeeded && s.index < s.input.Length && count <= max then
            inner (term { input = s.input; index = s.index + 1; succeeded = true }, count + 1) 
        elif count >= min && count <= max then
            { input = s.input; index = s.index - 1; succeeded = true }    
        else 
            s         
    fun s -> inner (s, 0) 

let disjunction leftTerm rightTerm =
    fun s ->
        let left = leftTerm s
        if not left.succeeded then
            let right = rightTerm s  
            if not right.succeeded then
                { input = s.input; index = s.index; succeeded = false }
            else
                right
        else
            left 

let matcher input terms =
    let r = terms  { input = input; index = 0; succeeded = true } 
    if r.succeeded then r.input.Substring (0, r.index) else null

let test = // (abc|xyz)a{2,3}bc
    disjunction // (abc|xyz)
        (term (set "a") >> term (set "b") >> term (set "c"))
        (term (set "x") >> term (set "y") >> term (set "z"))  
    >> quantify (term (set "a"), 2, 3) // (a{2,3})
    >> term (set "b") // b  
    >> term (set "c") // c

let main () : unit =
    printfn "%s" (matcher "xyzaabc" test)
    System.Console.ReadKey true |> ignore

main()
Run Code Online (Sandbox Code Playgroud)

Tom*_*cek 8

代码看起来对我很好.

我不确定这是你的意图还是巧合,但是你实现了与"解析器组合器"非常类似的东西,这是许多学术论文的主题:-).我认为Monadic Parser Combinators非常易读(它在Haskell中有例子,但你应该能够将它们翻译成F#).

关于功能组合运算符.我通常不太喜欢使用运算符,因为它经常混淆代码.但是,在您的示例中,它很有意义,因为您可以轻松地想象这>>意味着"该组应该跟随该组",这很容易解释.

我要做的唯一一个小改动是为操作选择一些不错的自定义操作符disjunction并定义一些更原始的操作,以便您可以编写例如:

// Test against several terms in sequence
let sequence terms = (fun state -> terms |> Seq.fold (>>) state)
// Test for a substring
let substring s = sequence [ for c in s -> term (set [c]) ]

let test = // (abc|xyz)a{2,3}bc 
  ( substring "abc" <|> substring "xyz" )
  >> quantify 2 3 (term (set "a")) // (a{2,3}) 
  >> substring "bc" // bc
Run Code Online (Sandbox Code Playgroud)

这是更高级别的描述,因此它删除了一些>>操作符,支持更具描述性(和封装>>)的函数.我也改为quantify采取多个参数而不是三重奏(这是一个小改动)

如果你想进一步使用它,那么你可以看一下这篇文章,并尝试编写允许你使用parser { .. }语法的F#计算表达式构建器.