F# 这能变得更实用吗?
从f#开始,我来到OO C#背景,我有以下代码读取英国postscodes的文本文件,然后用post代码到达api端点,我测试结果以查看post是否有效:F# 这能变得更实用吗?,f#,F#,从f#开始,我来到OO C#背景,我有以下代码读取英国postscodes的文本文件,然后用post代码到达api端点,我测试结果以查看post是否有效: let postCodeFile = "c:\\tmp\\randomPostCodes.txt" let readLines filePath = System.IO.File.ReadLines(filePath) let lines = readLines postCodeFile let postCodeValidDaterUr
let postCodeFile = "c:\\tmp\\randomPostCodes.txt"
let readLines filePath = System.IO.File.ReadLines(filePath)
let lines = readLines postCodeFile
let postCodeValidDaterUrl = "https://api.postcodes.io/postcodes/"
let validatePostCode postCode =
Request.createUrl Get (postCodeValidDaterUrl + postCode)
|> getResponse
|> run
let translateResponse response =
match response.statusCode with
| 200 -> true
| _ -> false
let validPostCode = validatePostCode >> translateResponse
lines |> Seq.iter(fun x -> validPostCode(x) |> printfn "%s-%b" x)
有什么建议让它更实用吗 评论/代码审查
你已经让它尽可能地发挥作用了。我将仔细阅读您的代码,并解释为什么您的决定是好的,在一些情况下,您可以做一些小的改进
let postCodeFile = "c:\\tmp\\randomPostCodes.txt"
将其作为命名变量很好;在实际代码中,这当然是脚本的参数或函数参数。因此,将其作为命名变量非常有用
let readLines filePath = System.IO.File.ReadLines(filePath)
这个功能不是严格必要的;由于System.IO.File.ReadLines
只接受一个参数,因此您可以通过管道将其导入(例如,postCodeFile |>System.IO.File.ReadLines |>Seq.iter(…)
),但我喜欢较短的名称,因此我可能也会这样写
let lines = readLines postCodeFile
我可能会停止创建行
名称,而改为创建postCodeFile |>readLines |>Seq.iter(…)
在代码的最后一行。您的操作方式没有本质上的错误,但是您没有在其他任何地方使用行
变量,因此没有真正的理由给它命名。F#的管道允许您跳过中间步骤的命名
let postCodeValidDaterUrl = "https://api.postcodes.io/postcodes/"
同样,给它起个名字很好,这样你以后就可以把它变成参数或配置文件变量。我在这里看到的唯一可以改进的是拼写:ValidDater
应该是Validator
let validatePostCode postCode =
Request.createUrl Get (postCodeValidDaterUrl + postCode)
|> getResponse
|> run
看起来不错
let translateResponse response =
match response.statusCode with
| 200 -> true
| _ -> false
可以更简单:let translateResponse response=(response.statusCode=200)
。但是match
表达式允许您在以后扩展它,如果您有一个可以返回其他状态代码(如204)的API,以指示成功。我可能会在这里使用更简单的比较,并仅在需要时添加match
语句
let validPostCode = validatePostCode >> translateResponse
很好
正如我前面提到的,行
是一个中间步骤,因此我可能会将其更改为postCodeFile |>readLines |>Seq.iter(…)
,因为这允许您跳过为中间步骤命名
let postCodeValidDaterUrl = "https://api.postcodes.io/postcodes/"
为什么这是好的
有两件事你在这里做得很好:
validatePostCode
只发送一个请求,另一个函数决定响应是否指示有效代码。这很好我认为这里的目标不应该是使代码“更具功能性”。功能性不是一种固有的价值。在F#中,保持逻辑核心的功能性是有意义的,但如果你做了大量的I/O,那么遵循更命令式的风格是有意义的 我的代码版本如下所示(与@rmunn的一些建议有些重叠): 我的改变是:
- 我删除了
帮助程序,只需直接调用readLines
。如果.NET方法没有更好的用途,比如提供一个在多个地方重用的更为F友好的API,那么就不需要为它引入F别名File.readLines
- 像@rmunn一样,我用
替换了response.statusCode=200
。我只在需要绑定新变量作为匹配的一部分时使用match
。在测试布尔条件时,我认为match
更好if
- 我用一个普通的
循环替换了你的组合函数和for
。无论如何,代码是必需的,所以我不明白你为什么不想使用内置语言构造。我取消了Seq.iter
,因为你只在一个地方使用组合函数,所以引入它不会简化代码validPostCode
- 这只是我的风格,不一定更实用或更好:
open System.IO
let postCodeFile = "c:\\tmp\\randomPostCodes.txt"
let postCodeValidDaterUrl = "https://api.postcodes.io/postcodes/"
let validatePostCode postCode =
Request.createUrl Get (postCodeValidDaterUrl + postCode)
|> getResponse
|> run
|> fun response -> response.statusCode = 200
File.ReadLines postCodeFile
|> Seq.iter (fun code -> validatePostCode code |> printfn "%s-%b" code )
副作用进来,副作用出去。真的有什么好的理由让它更“实用”吗考虑到它本质上是程序性的?啊,这是一个很好的观点,正如我刚才说的,刚刚开始并在那里试验一些有用的外卖。非常感谢,我目前正在使用f#进行编程,并使域建模功能化。需要开始做一些更复杂的事情。
open System.IO
let postCodeFile = "c:\\tmp\\randomPostCodes.txt"
let postCodeValidDaterUrl = "https://api.postcodes.io/postcodes/"
let validatePostCode postCode =
Request.createUrl Get (postCodeValidDaterUrl + postCode)
|> getResponse
|> run
|> fun response -> response.statusCode = 200
File.ReadLines postCodeFile
|> Seq.iter (fun code -> validatePostCode code |> printfn "%s-%b" code )