简体   繁体   English

F#生活质量问题

[英]F# Quality of Life Questions

I started coding in F# about 2 months ago. 大约2个月前我开始在F#编码。

I am greatly enjoying this programming language. 我非常喜欢这种编程语言。 I come from a C# background, and every time I need to revert back to C#, it feels so cumbersome and bloated. 我来自C#背景,每次我需要恢复到C#时,它感觉如此繁琐和臃肿。

But there are still things I think are problematic in F#, and this is what my questions are related to: 但是我认为在F#中仍有一些问题,这就是我的问题与之相关:

  1. There is no auto complete like VS has for C# right ? 没有自动完成像VS有C#对吗? Eg inside a function that takes parameter aParameter, if I write aPara no auto complete comes up. 例如,在一个带参数aParameter的函数中,如果我写aPara,则不会出现自动完成。 Is there a functionality inside VS that can solve this issue and which I am not aware of? VS内部是否有可以解决此问题且我不知道的功能?

  2. Debugging is tedious to say the least. 调试至少可以说是乏味的。 Since F# supports piping / chaining or whatever you want to call it, I typically try to chain as many things as possible (wherever it makes sense of course). 由于F#支持管道/链接或任何你想要的东西,我通常会尝试尽可能多地链接(当然,无论哪个地方都有意义)。 Example: 例:

     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 

And this is just quarter of my whole chaining done. 这只是我整个链接的四分之一。 Whenever I mess something up in these chains, I find it very very hard to debug where it all went wrong. 每当我把这些链中的东西搞得一团糟时,我发现很难调试它出错的地方。

Am I doing this chaining wrong (abusing it)? 我这样做的链条错误(滥用它)? From my point of view, nothing intermediary from this chaining makes sense to exist atomically, thus there is no reason to have intermediary values. 从我的观点来看,这种链接的任何中介都没有理由以原子方式存在,因此没有理由拥有中间价值。 But because of this semantic point of view, I also lose the power of having intermediary values which help me debug. 但是由于这种语义观点,我也失去了使用中间值来帮助我调试的能力。 So then I have to insert them in the code, debug, then remove them again. 那么我必须在代码中插入它们,调试,然后再次删除它们。 But this is a wasted effort. 但这是一种浪费的努力。 Is there any way around this? 有没有办法解决?

Also, debugging a List.map anonymous function inside a chain feels again awkward and hard compared to eg a for loop. 此外,调整链中的List.map匿名函数与例如for循环相比再次感觉尴尬和困难。

I am sure that I am missing something, and that my current way of debugging is probably not optimal - not by a long shot - so any suggestions are welcome. 我确信我错过了一些东西,而且我目前的调试方式可能不是最佳的 - 不是长篇大论 - 所以欢迎任何建议。

1.There is no auto complete like VS has for C# right 1.对于C#,VS没有自动完成

There is auto-complete for F#. F#有自动完成功能。 It is not triggered automatically when you start typing though. 但是,当您开始输入时,它不会自动触发。 If you're in Visual Studio and type aPara and then hit Ctrl + Space , it should be auto-completed to aParameter if it is in the scope. 如果您在Visual Studio中并键入aPara然后按Ctrl + Space ,则它应自动完成到aParameter如果它在范围内)。 Similarly, you can do this in top-level scope to see available types and namespaces. 同样,您可以在顶级作用域中执行此操作以查看可用的类型和名称空间。 Auto-completion also get triggered automatically when you type . 键入时自动完成也会自动触发.

2.Debugging is tedious to say the least 至少可以说,调试很乏味

I'd agree with this - debugging pipelines (especially with lazy sequences) is tricky. 我同意这一点 - 调试管道(尤其是延迟序列)很棘手。 This is a bit confusing even when you're in C#, but C# does surprisingly good job on this one. 即使你在C#中,这也有点令人困惑,但C#在这一方面做得非常出色。 There are two ways to deal with this: 有两种方法可以解决这个问题:

  • Use F# Interactive more. 更多使用F#Interactive。 I write most of my code in an F# Script file first, where you can run your partially complete solutions and see results immediately. 我首先在F#Script文件中编写了大部分代码,您可以在其中运行部分完整的解决方案并立即查看结果。 For me, this pretty much replaces debugging, because by the time my code is complete, I know it works. 对我来说,这几乎取代了调试,因为到我的代码完成时,我知道它有效。

  • You can define a function tap that materializes the data in the pipeline and lets you see what is going through the pipe. 您可以定义一个功能tap ,它实现管道中的数据,并让您查看管道中的数据。 I don't use this very much, but I know some people like it: 我不太习惯这个,但我知道有些人喜欢它:

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

    Then you can use it in your pipeline: 然后你可以在你的管道中使用它:

     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 

    This adds some noise to the pipeline, but you can remove it again once you're done with debugging. 这会给管道增加一些噪音,但是一旦完成调试就可以再次删除它。

The question of improving debugging experience with F# has many aspects so it deserves a big article. 使用F#改善调试体验的问题涉及很多方面,因此值得一篇大文章。 So I'm afraid the question will be closed. 所以我担心这个问题会被关闭。
Nevertheless, here are two neat tricks I'm using. 不过,这里有两个我正在使用的巧妙技巧。 I must note that I'm also a big fan of pipeline approach and so I'm facing exactly the same problems. 我必须指出,我也是管道方法的忠实粉丝,因此我面临着完全相同的问题。

Know your types. 了解你的类型。

Having a value threaded through a chain of many transformations may quickly lead to difficulty remembering exact types at each step. 通过一系列转换链接一个值可能很快导致难以在每一步记住确切的类型。 The trick is: 诀窍是:

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

This lets you: 这可以让你:

  1. see the exact type of x in design time; 在设计时看到x的确切类型;
  2. set a breakpoint (place cursor at the function body ) and see the value at debug time; 设置断点 (将光标放在函数体上 )并在调试时查看值;
  3. Even if forgotten in the code after done, this leaves minimal footprint. 即使在完成后忘记了代码,这也留下了最小的占用空间。

Conditionally dump the values to console. 有条件地将值转储到控制台。

Having complicated lambdas, breakpoints may be of little help. 复杂的lambdas,断点可能没什么帮助。 Here's yet another trick, related to the one described in @Tomas' answer: write a small function, like this: 这是另一个技巧,与@Tomas答案中描述的相关:编写一个小函数,如下所示:

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

The usage code looks like this: 使用代码如下所示:

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

The idea is that: 这个想法是:

  1. you set a breakpoint just before the debug call, just as described above; debug调用之前设置一个断点,就像上面描述的那样;
  2. switch Caps Lock on 开启大写锁定
  3. and Step Over or just let the application run 和Step Over或让应用程序运行

If you have multiple places where debug call sit, they would not spoil the output. 如果您有多个debug调用位置,它们不会破坏输出。

On the debugging |> pipelines issue - try to have a personal coding standard that you don't have more than three, or at most four, lines in such a pipeline. 在调试|>管道问题上 - 尝试使用个人编码标准,在这样的管道中,您没有超过三行或最多四行。 When they get longer than that, refactor. 当它们比这更长时,重构。 This is what I do and it helps a lot. 这就是我所做的,它有很大帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM