F# 我该如何使它更地道?
这里有一个我从另一种语言(Lisp)翻译过来的函数,大部分是逐字翻译的。不过,我觉得它不太合适,使用F# 我该如何使它更地道?,f#,refactoring,idioms,F#,Refactoring,Idioms,这里有一个我从另一种语言(Lisp)翻译过来的函数,大部分是逐字翻译的。不过,我觉得它不太合适,使用ref,if而不使用else,等等。您将如何重写下面的第二个函数 let directEdges node edges = List.filter (fun (a, b) -> a = node) edges let getConnected node edges = let visited = ref Set.empty let rec traverse node
ref
,if
而不使用else
,等等。您将如何重写下面的第二个函数
let directEdges node edges =
List.filter (fun (a, b) -> a = node) edges
let getConnected node edges =
let visited = ref Set.empty
let rec traverse node =
if not (Set.contains node !visited) then
visited := Set.add node !visited
directEdges node edges
|> List.iter (fun (a, b) -> traverse b)
traverse node
!visited
编辑:代码甚至不需要使用集合;原始版本只是使用了一个列表。总体而言,我认为您的解决方案看起来相当不错-我认为这是一种问题,在这种问题中,一点可变性可以使算法的表达式更清晰。但是,与其对重复更新的不可变集使用可变引用,不如只使用可变集实现:
open System.Collections.Generic
let getConnected node edges =
let visited = HashSet()
let rec traverse node =
if not (visited.Contains node) then
visited.Add node
directEdges node edges
|> List.iter (fun (a,b) -> traverse b)
traverse node
visited
如果您希望输出是一个不可变的集合,您可以在最后一行之后添加|>set
另一方面,如果您想使用功能性方法,这并不难:
let getConnected node edges =
let rec traverse node visited =
if not (Set.contains node visited) then
directEdges node edges
|> List.fold (fun nodes (a, b) -> traverse b nodes) (Set.add node visited)
else
visited
traverse node Set.empty
你的第二个解决方案相当优雅,至少对我来说,非常出色。我以前从未在折叠中使用过递归!我试过了,但没能想出这样的办法。出于好奇,你在功能上编程有多久了?@JCooper-从2007年左右开始,我就在业余时间玩F#了。我在大学里学过这个计划,但在课外并没有真正使用它。