Eri*_*son 4 theory f# functional-programming
在函数式语言中(使用F#),我正在努力在功能组合的优点与单一责任之间找到平衡,并在序列上获得单次迭代的性能.实现两者的任何代码模式建议/示例?
我没有扎实的计算理论背景,我一遍又一遍地遇到这种一般模式:迭代一个集合,想要在迭代时做副作用,以避免在同一个集合或其结果集上进一步迭代.
一个典型的例子是"减少"或"过滤"功能:过滤时有很多次我希望根据过滤器的结果采取额外的步骤,但我想避免过滤结果的第二次枚举.
我们将输入验证作为一个简单的问题陈述:
在F#中,我可能最初写道:
inputs
// how to log invalid or other side-effects without messing up isValid??
|> Seq.filter isValid
|> execution
Run Code Online (Sandbox Code Playgroud)
有了内联副作用,我需要这样的东西:
inputs
|> Seq.filter (fun (name,value) ->
let valid = isValid (name,value)
// side-effect
if not valid then
printfn "Invalid argument %s" name
valid
|> execution
Run Code Online (Sandbox Code Playgroud)
我可以使用元组进行更纯粹的关注点分离,但需要第二次迭代:
let validationResults =
inputs
// initial iteration
|> Seq.filter (fun (name,value) ->
let valid = isValid (name,value)
(name,value,valid)
|> execution
// one example of a 2nd iteration...
validationResults
|> Seq.filter (fun (_,_,valid) -> not valid)
|> Seq.map (fun (name,_,_) -> printfn "Invalid argument %s" name)
|> ignore
// another example of a 2nd iteration...
for validationResult in validationResults do
if not valid then
printfn "Invalid argument %s" name
Run Code Online (Sandbox Code Playgroud)
我用它作为答案的解决方案.模式是使用包含条件的聚合函数.可能还有更优雅简洁的表达方式......
open System
let inputs = [("name","my name");("number","123456");("invalid","")]
let isValidValue (name,value) =
not (String.IsNullOrWhiteSpace(value))
let logInvalidArg (name,value) =
printfn "Invalid argument %s" name
let execution (name,value) =
printfn "Valid argument %s: %s" name value
let inputPipeline input =
match isValidValue input with
| true -> execution input
| false -> logInvalidArg input
inputs |> Seq.iter inputPipeline
Run Code Online (Sandbox Code Playgroud)
在跟进我的其他回答有关记录和F#等副作用的成分,在这个例子中,你可以写日志记录更高级别的功能,就像这样:
let log f (name, value) =
let valid = f (name, value)
if not valid then
printfn "Invalid argument %s" name
valid
Run Code Online (Sandbox Code Playgroud)
它有这个签名:
f:(string * 'a -> bool) -> name:string * value:'a -> bool
Run Code Online (Sandbox Code Playgroud)
所以你现在可以用这样的'真实' isValid函数组合它:
inputs
|> Seq.filter (log isValid)
|> execution
Run Code Online (Sandbox Code Playgroud)
由于isValid函数具有签名,name:'a * value:int -> bool因此它适合函数的f参数log,您可以部分应用上述日志函数.