F#生活质量问题

时间:2015-06-25 08:38:59

标签: debugging visual-studio-2013 f#

我在2个月前开始使用F#进行编码。

我非常喜欢这种编程语言。我来自C#背景,每次我需要恢复到C#时,感觉非常麻烦和臃肿。

但是我觉得F#中还有一些问题,这就是我的问题所在:

  1. 对于C#,VS没有自动完成吗?例如。在一个带参数aParameter的函数里面,如果我写aPara,则不会出现自动完成。 VS内部是否有可以解决此问题且我不知道的功能?

  2. 调试至少可以说是乏味的。由于F#支持管道/链接或任何你想要的东西,我通常会尝试尽可能多地链接(当然,无论哪个地方都有意义)。例如:

    correctedData 
    |> List.filter (fun (_, r, _) -> r <= 3) 
    |> Seq.ofList 
    |> Seq.groupBy (fun (_, r, cti) -> (r,cti))                            
    |> Seq.map (fun ((r,cti),xs) -> (r, cti, Seq.length xs)) 
    |> Seq.toList
    
  3. 这只是我完成整个链接的四分之一。每当我把这些链中的东西搞得一团糟时,我发现很难调试它出错的地方。

    我这样做的链条错误(滥用它)?从我的观点来看,这种链接的任何中介都没有理由以原子方式存在,因此没有理由拥有中间价值。但是由于这种语义观点,我也失去了使用中间值来帮助我调试的能力。那么我必须在代码中插入它们,调试,然后再次删除它们。但这是一种浪费的努力。有没有办法解决这个问题?

    此外,调整链中的List.map匿名函数再次感到尴尬和困难,例如一个for循环。

    我确信我错过了一些东西,而且我目前的调试方式可能不是最佳的 - 不是长篇大论 - 所以欢迎任何建议。

3 个答案:

答案 0 :(得分:14)

  

1.没有自动完成,就像VS有C#右

F#有自动完成功能。但是,当您开始输入时,它不会自动触发。如果您在Visual Studio中并键入aPara,然后按 Ctrl + Space ,则应自动完成aParameter(如果是在范围内。同样,您可以在顶级作用域中执行此操作以查看可用的类型和名称空间。键入.

时,自动完成也会自动触发
  

2.至少可以说调试是非常繁琐的

我同意这一点 - 调试管道(尤其是延迟序列)很棘手。即使你在C#中,这也有点令人困惑,但C#在这一方面做得非常出色。有两种方法可以解决这个问题:

  • 更多使用F#Interactive。我首先在F#Script文件中编写了大部分代码,您可以在其中运行部分完整的解决方案并立即查看结果。对我来说,这几乎取代了调试,因为当我的代码完成时,我知道它有效。

  • 您可以定义一个函数tap,它可以实现管道中的数据,并让您查看管道中的数据。我不太习惯这个,但我知道有些人喜欢它:

    let tap data = 
      let materialized = List.ofSeq data
      materialized
    

    然后你可以在你的管道中使用它:

    correctedData 
    |> List.filter (fun (_, r, _) -> r <= 3) 
    |> tap
    |> Seq.groupBy (fun (_, r, cti) -> (r,cti))                            
    |> tap
    |> Seq.map (fun ((r,cti),xs) -> (r, cti, Seq.length xs)) 
    |> Seq.toList
    

    这会给管道增加一些噪音,但是一旦完成调试,你就可以再次删除它。

答案 1 :(得分:8)

使用F#改善调试体验的问题涉及很多方面,因此值得一篇大文章。所以我担心这个问题会被关闭 不过,这里有两个巧妙的技巧。我必须指出,我也是管道方法的忠实粉丝,因此我面临着完全相同的问题。

了解您的类型。

通过一系列转换链接的值可能很快导致难以在每一步记住确切的类型。诀窍是:

value
|> transformation1
|> fun x -> x
|> transformation2

这可以让你:

  1. 在设计时查看x的确切类型;
  2. 设置断点(将光标置于函数体)并在调试时查看值;
  3. 即使在完成后忘记了代码,这也会留下最小的占用空间。
  4. 有条件地将值转储到控制台。

    复杂的lambdas,断点可能没什么帮助。这是另一个与@ Tomas&#39;中描述的技巧相关的技巧。回答:写一个小函数,像这样:

    let inline debug x =
    #if DEBUG
        if System.Console.CapsLock then
            printfn "%A" x
            // obviously, it must not be necessarily printf;
            // it can be System.Diagnostics.Debug.WriteLine()
            // or any other logger tool that exists in the project.
    #endif
        x
    

    使用代码如下所示:

    value
    |> transformation1
    |> fun x -> x
    |> debug
    |> transformation2
    

    这个想法是:

    1. 您在debug来电之前设置断点,如上所述;
    2. 开启大写锁定
    3. 和Step Over或只是让应用程序运行
    4. 如果您有多个debug来电的地方,他们就不会破坏输出。

答案 2 :(得分:1)

关于调试|&gt;管道问题 - 尝试建立一个个人编码标准,在这样的管道中,你不能拥有超过三行,或最多四行。当它们比这更长时,重构。这就是我的工作,它有很大的帮助。