我如何使这更惯用?

时间:2011-03-08 03:51:47

标签: f# refactoring idiomatic

所以这是我从另一种语言(Lisp)翻译的函数,大部分是逐字的。但是,对我来说,这并不是很合适,使用refif没有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

编辑:也没有要求代码甚至使用Set;原来只是使用了一个清单。

1 个答案:

答案 0 :(得分:3)

总的来说,我认为你的解决方案看起来非常好 - 我认为这是一种问题,其中一些可变性使得算法的表达更清晰。但是,不是使用对重复更新的不可变集的可变引用,而是使用可变集实现可能更好:

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