F# 我是否正确使用函数合成?

F# 我是否正确使用函数合成?,f#,functional-programming,function-composition,F#,Functional Programming,Function Composition,为了理解函数式编程的功能,我将几个基本函数放在一起,您可以组合起来构建复杂的正则表达式。现在经过一些测试,我发现这是可行的,但是你可以用任何语言编写一些可怕的代码。这是你会发现专业F#程序员编写的那种代码,还是我滥用了这种功能 注意:test是我特别指的 type State = { input:string; index:int; succeeded:bool } type Matcher = State -> State let term (cs:char Set) = f

为了理解函数式编程的功能,我将几个基本函数放在一起,您可以组合起来构建复杂的正则表达式。现在经过一些测试,我发现这是可行的,但是你可以用任何语言编写一些可怕的代码。这是你会发现专业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()
type State={input:string;index:int;successed:bool}
类型匹配器=状态->状态
let项(cs:char集)=
乐趣s->
如果s.successed&&s.index
设left=lefts
如果没有离开,那么成功了
设right=rights
如果不正确,那么成功了
{input=s.input;index=s.index;successed=false}
其他的
正确的
其他的
左边
让匹配器输入术语=
设r=terms{input=input;index=0;successed=true}
如果r.successed,则r.input.Substring(0,r.index)否则为空
设test=/(abc | xyz)a{2,3}bc
析取/(abc | xyz)
(期限(a组)>>期限(b组)>>期限(c组)
(术语(集合“x”)>>术语(集合“y”)>>术语(集合“z”))
>>量化(术语(集合“a”),2,3)/(a{2,3})
>>术语(设置为“b”)//b
>>术语(设置为“c”)//c
let main():单位=
打印fn“%s”(匹配器“xyzaabc”测试)
System.Console.ReadKey true |>忽略
main()

我觉得代码很好

我不确定这是您的意图还是巧合,但您正在实现与“解析器组合器”非常相似的东西,这是许多学术论文的主题:-)。我认为这是相当可读的(它有Haskell中的示例,但您应该能够将它们转换为F#)

关于函数组合运算符。我通常不太喜欢过多地使用操作符,因为它经常混淆代码。然而,在您的示例中,这很有意义,因为您可以很容易地想象
>
意味着“这个组后面应该跟着那个组”,这很容易解释

我要做的唯一一个小改动是为
析取操作选择一些好的自定义运算符,并定义一些更基本的操作,这样您就可以编写以下示例:

// 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
//按顺序对多个术语进行测试
让序列术语=(有趣状态->术语|>Seq.fold(>>)状态)
//子字符串的测试
设子串s=sequence[s中的c->term(set[c])]
设test=/(abc | xyz)a{2,3}bc
(子字符串“abc”子字符串“xyz”)
>>量化23(术语(集合“a”)/(a{2,3})
>>子字符串“bc”//bc
这是更高层次的描述,因此它删除了一些
>
运算符,以支持更具描述性的函数(并封装
>
)。我还将
quantify
更改为采用多个参数,而不是三个参数(这是一个较小的更改)


如果您想进一步研究这一点,那么您可以看看这篇文章,并尝试编写F#computation expression builder,它允许您使用
parser{..}
语法。

这通常是一种很好的风格,但您缺少一些技巧,仍然有相当多的冗余。也许更像这样:

let valid (s: State) = s.succeeded && s.index < s.input.Length
...
let disjunction leftTerm rightTerm s =
  let left = leftTerm s
  if left.succeeded then left else
    let right = rightTerm s  
    if right.succeeded then right else
      { s with succeeded = false }
...
let test =
  let f s = set s |> term
  let (++) s t = f s >> f t
  disjunction ("a" ++ "b" ++ "c") ("x" ++ "y" ++ "z")  
  >> quantify (f "a", 2, 3)
  >> "b" ++ "c"
let valid(s:State)=s.successed&&s.index项
设(++)st=fs>>ft
析取(“a”+“b”+“c”)(“x”+“y”+“z”)
>>量化(f“a”,2,3)
>>“b”+“c”

您可能更喜欢累积表示计算的值,而不是闭包,因为它使调试更加容易。

很高兴知道我在函数编程技能方面取得了进步。您让我非常兴奋地尝试将所有内容封装到优雅的计算表达式语法中。:)不管怎样,谢谢你的建议和报纸(我是Erik Meijer的粉丝)。哇,我觉得自己有点傻,因为我没有想出有效的
函数。谢谢你的建议。