Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Recursion F#:使用对象表达式和判别并集_Recursion_F#_Discriminated Union - Fatal编程技术网

Recursion F#:使用对象表达式和判别并集

Recursion F#:使用对象表达式和判别并集,recursion,f#,discriminated-union,Recursion,F#,Discriminated Union,我有一个递归函数,它包含一系列匹配项,这些匹配项要么对函数进行递归调用,要么对failwith进行调用 这基本上是Don Syme的Expert F#book(第180页)中描述的递归下降解析器和此处显示的解析示例的混合实现: 下面是我自己的代码片段 let rec parseTokenListRec tokenList optionsSoFar = match tokenList with | [] -> optionsSoFar | SOURCE::t ->

我有一个递归函数,它包含一系列匹配项,这些匹配项要么对函数进行递归调用,要么对failwith进行调用

这基本上是Don Syme的Expert F#book(第180页)中描述的递归下降解析器和此处显示的解析示例的混合实现:

下面是我自己的代码片段

let rec parseTokenListRec tokenList optionsSoFar =
    match tokenList with
    | [] -> optionsSoFar
    | SOURCE::t -> 
        match t with
        | VALUE x::tt -> parseTokenListRec (returnNonValueTail t) {optionsSoFar with Source = (returnConcatHeadValues t)}
        | _ -> failwith "Expected a value after the source argument."
    | REGISTRY::t ->
...
完整的代码清单可以在

当前编写代码的方式,当函数完成对令牌列表的处理后,它将返回通过对象表达式
{optionsOfar with Source=(returnConcatHeadValues t)}
编译的optionsOfar记录,或者如果发现无效参数,它将抛出异常

我想重构它,使函数不依赖于异常,但总是返回一个可以由调用函数处理的某种类型的值。我的想法是返回一个受歧视的联盟,而不是一份记录

这个受歧视的联盟会是这样的

type Result =
    |Success of Options
    |Failure of string
当我试图重构代码时遇到的问题是,我无法弄清楚如何通过对象表达式初始化DU的成功值。这可能吗

我在MSDN()、fsharpforfunandproit()和其他地方看到的例子并没有让我完全明白这一点


我担心我在这里没有任何意义。如果需要,我很乐意澄清。

如果我理解正确,在您当前的解决方案中,
选项的类型为
选项。如果将
选项的类型更改为新定义的
结果
,代码将变得更加复杂

但是,我认为您不需要这样做-您可以保留
选项sofar:Options
,并更改函数以返回
结果
。这是因为在函数失败后,您永远不需要递归调用该函数:

let rec parseTokenListRec tokenList optionsSoFar =
    match tokenList with
    | [] -> Success optionsSoFar
    | SOURCE::t -> 
        match t with
        | VALUE x::tt -> 
            {optionsSoFar with Source = (returnConcatHeadValues t)}
            |> parseTokenListRec (returnNonValueTail t) 
        | _ -> Failure "Expected a value after the source argument."
    | REGISTRY::t -> ...
如果您确实想在
结果
值中更新
源代码
,那么我可能会编写如下内容:

module Result = 
  let map f = function
    | Success opt -> f opt
    | Failure msg -> Failure msg
然后您可以编写如下转换:

resultSoFar
|> Result.map (fun opts -> {opts with Source = returnConcatHeadValues t})
|> parseTokenListRec (returnNonValueTail t) 

当我在走廊上读你的F#计算表达式动物园论文时,我注意到是你回答了这个问题。这让我很开心。谢谢你,伙计!我发现了一篇关于这个主题的很棒的博客文章: