【问题标题】:How do I make this more idiomatic?我怎样才能使它更地道?
【发布时间】:2011-07-10 19:57:25
【问题描述】:

所以这是我从另一种语言 (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;原来只是用了一个列表。

【问题讨论】:

    标签: f# refactoring idioms


    【解决方案1】:

    总体而言,我认为您的解决方案看起来相当不错 - 我认为这是一种可变性使算法的表达更清晰的问题。但是,与其使用对反复更新的不可变集的可变引用,不如只使用可变集实现:

    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#。我在大学里学过 Scheme,但在课外并没有真正使用它。
    猜你喜欢
    • 1970-01-01
    • 2015-12-23
    • 2020-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-16
    • 1970-01-01
    相关资源
    最近更新 更多