Recursion F#:使用对象表达式和判别并集
我有一个递归函数,它包含一系列匹配项,这些匹配项要么对函数进行递归调用,要么对failwith进行调用 这基本上是Don Syme的Expert F#book(第180页)中描述的递归下降解析器和此处显示的解析示例的混合实现: 下面是我自己的代码片段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 ->
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#计算表达式动物园论文时,我注意到是你回答了这个问题。这让我很开心。谢谢你,伙计!我发现了一篇关于这个主题的很棒的博客文章: