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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/72.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
F# 我该如何使它更地道?_F#_Refactoring_Idioms - Fatal编程技术网

F# 我该如何使它更地道?

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

这里有一个我从另一种语言(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 =
        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#了。我在大学里学过这个计划,但在课外并没有真正使用它。