F# 生活质量问题
F# Quality of Life Questions
我大约 2 个月前开始使用 F# 编写代码。
我非常喜欢这门编程语言。我是C#出身,每次要转回C#,都觉得又笨又臃肿。
但我认为 F# 中仍有一些问题,这就是我的问题:
没有像 VS 那样的 C# 自动完成功能,对吧?例如。在一个接受参数 aParameter 的函数中,如果我写 aPara,则不会出现自动完成。 VS 中是否有可以解决此问题但我不知道的功能?
调试至少可以说是乏味的。由于 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
这只是我完成的整个链接的四分之一。每当我在这些链中弄乱某些东西时,我发现很难调试哪里出了问题。
我是不是做错了这个链接(滥用它)?从我的角度来看,这种链接中的任何中介都没有意义原子地存在,因此没有理由具有中介值。但是由于这种语义观点,我也失去了拥有帮助我调试的中间值的力量。所以我必须将它们插入代码中,调试,然后再次删除它们。但这是徒劳的。有什么解决办法吗?
此外,调试链中的 List.map 匿名函数再次感觉尴尬和困难。一个 for 循环。
我确信我遗漏了一些东西,而且我目前的调试方式可能不是最佳的 - 远不是 - 所以欢迎任何建议。
1.There is no auto complete like VS has for C# right
F# 有自动完成功能。但是,当您开始输入时它不会自动触发。如果您在 Visual Studio 并键入 aPara
然后按 Ctrl+Space,它应该如果在范围内,则自动完成为 aParameter
。同样,您可以在顶级范围内执行此操作以查看可用的类型和命名空间。当您键入 .
时,自动完成也会自动触发
2.Debugging is tedious to say the least
我同意这一点 - 调试管道(尤其是惰性序列)很棘手。即使在使用 C# 时,这也有点令人困惑,但 C# 在这方面做得非常好。有两种处理方法:
更多地使用 F# Interactive。我首先在 F# 脚本文件中编写大部分代码,您可以在其中 运行 部分完整的解决方案并立即查看结果。对我来说,这几乎取代了调试,因为当我的代码完成时,我知道它可以工作。
您可以定义一个函数 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
这会给管道增加一些噪音,但您可以在完成调试后再次将其删除。
提高F#调试体验的问题有很多方面,值得写一篇大文章。所以我担心这个问题会被关闭。
不过,这里有两个巧妙的技巧我正在使用。我必须指出,我也是管道方法的忠实拥护者,所以我面临着完全相同的问题。
了解你的类型。
让一个值通过许多转换链串联起来可能会很快导致难以记住每一步的确切类型。诀窍是:
value
|> transformation1
|> fun x -> x
|> transformation2
这让您:
- 在设计时查看
x
的确切类型;
- 设置断点(将光标置于函数体)并查看调试时的值;
- 即使在完成后忘记在代码中,这也会留下最小的足迹。
有条件地将值转储到控制台。
对于复杂的 lambda 表达式,断点可能帮不上什么忙。这是另一个技巧,与@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
使用代码如下所示:
value
|> transformation1
|> fun x -> x
|> debug
|> transformation2
想法是:
- 您在
debug
调用之前设置了一个断点,就像上面描述的那样;
- 打开大写锁定
- 和 Step Over 或只让应用程序 运行
如果您有多个地方 debug
调用 sit,它们不会破坏输出。
关于调试 |> 管道问题 - 尝试制定个人编码标准,即在此类管道中不超过三行或最多四行。当它们变得更长时,重构。这就是我所做的,它帮助很大。
我大约 2 个月前开始使用 F# 编写代码。
我非常喜欢这门编程语言。我是C#出身,每次要转回C#,都觉得又笨又臃肿。
但我认为 F# 中仍有一些问题,这就是我的问题:
没有像 VS 那样的 C# 自动完成功能,对吧?例如。在一个接受参数 aParameter 的函数中,如果我写 aPara,则不会出现自动完成。 VS 中是否有可以解决此问题但我不知道的功能?
调试至少可以说是乏味的。由于 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
这只是我完成的整个链接的四分之一。每当我在这些链中弄乱某些东西时,我发现很难调试哪里出了问题。
我是不是做错了这个链接(滥用它)?从我的角度来看,这种链接中的任何中介都没有意义原子地存在,因此没有理由具有中介值。但是由于这种语义观点,我也失去了拥有帮助我调试的中间值的力量。所以我必须将它们插入代码中,调试,然后再次删除它们。但这是徒劳的。有什么解决办法吗?
此外,调试链中的 List.map 匿名函数再次感觉尴尬和困难。一个 for 循环。
我确信我遗漏了一些东西,而且我目前的调试方式可能不是最佳的 - 远不是 - 所以欢迎任何建议。
1.There is no auto complete like VS has for C# right
F# 有自动完成功能。但是,当您开始输入时它不会自动触发。如果您在 Visual Studio 并键入 aPara
然后按 Ctrl+Space,它应该如果在范围内,则自动完成为 aParameter
。同样,您可以在顶级范围内执行此操作以查看可用的类型和命名空间。当您键入 .
2.Debugging is tedious to say the least
我同意这一点 - 调试管道(尤其是惰性序列)很棘手。即使在使用 C# 时,这也有点令人困惑,但 C# 在这方面做得非常好。有两种处理方法:
更多地使用 F# Interactive。我首先在 F# 脚本文件中编写大部分代码,您可以在其中 运行 部分完整的解决方案并立即查看结果。对我来说,这几乎取代了调试,因为当我的代码完成时,我知道它可以工作。
您可以定义一个函数
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
这会给管道增加一些噪音,但您可以在完成调试后再次将其删除。
提高F#调试体验的问题有很多方面,值得写一篇大文章。所以我担心这个问题会被关闭。
不过,这里有两个巧妙的技巧我正在使用。我必须指出,我也是管道方法的忠实拥护者,所以我面临着完全相同的问题。
了解你的类型。
让一个值通过许多转换链串联起来可能会很快导致难以记住每一步的确切类型。诀窍是:
value
|> transformation1
|> fun x -> x
|> transformation2
这让您:
- 在设计时查看
x
的确切类型; - 设置断点(将光标置于函数体)并查看调试时的值;
- 即使在完成后忘记在代码中,这也会留下最小的足迹。
有条件地将值转储到控制台。
对于复杂的 lambda 表达式,断点可能帮不上什么忙。这是另一个技巧,与@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
使用代码如下所示:
value
|> transformation1
|> fun x -> x
|> debug
|> transformation2
想法是:
- 您在
debug
调用之前设置了一个断点,就像上面描述的那样; - 打开大写锁定
- 和 Step Over 或只让应用程序 运行
如果您有多个地方 debug
调用 sit,它们不会破坏输出。
关于调试 |> 管道问题 - 尝试制定个人编码标准,即在此类管道中不超过三行或最多四行。当它们变得更长时,重构。这就是我所做的,它帮助很大。