gpt4 book ai didi

f# - 如何避免多次迭代作为一种模式?

转载 作者:行者123 更新时间:2023-12-04 23:49:58 25 4
gpt4 key购买 nike

在函数式语言(使用 F#)中,我正在努力在具有单一职责的函数式组合的优势和获得单次迭代序列的性能之间找到平衡。实现两者的任何代码模式建议/示例?

我没有扎实的计算理论背景,我一遍又一遍地遇到这种一般模式:迭代一个集合并希望在迭代时产生副作用以避免对同一集合或其结果集进行进一步迭代。

一个典型的例子是“reduce”或“filter”函数:有很多次过滤时我想根据过滤器的结果采取额外的步骤,但我想避免对过滤结果进行第二次枚举。

让我们将输入验证作为一个简单的问题陈述:

  • 命名输入数组
  • 通过管道传送到“isValid”函数过滤器
  • 副作用:记录无效的输入名称
  • 管道有效输入以进一步执行

  • 问题示例

    在 F# 中,我最初可能会这样写:
    inputs
    // how to log invalid or other side-effects without messing up isValid??
    |> Seq.filter isValid
    |> execution

    解决方案示例#1

    有了内嵌的副作用,我需要类似的东西:
    inputs
    |> Seq.filter (fun (name,value) ->
    let valid = isValid (name,value)
    // side-effect
    if not valid then
    printfn "Invalid argument %s" name
    valid
    |> execution

    解决方案示例#2

    我可以使用元组来做更纯粹的关注点分离,但需要第二次迭代:
    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

    更新 2014-07-23 每个答案

    我将其用作每个答案的解决方案。该模式是使用包含条件的聚合函数。可能有更优雅简洁的方式来表达这一点......
    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

    最佳答案

    关注 my other answer关于 F# 中日志记录和其他副作用的组合,在本示例中,您可以编写一个更高级别的日志记录函数,如下所示:

    let log f (name, value) =
    let valid = f (name, value)
    if not valid then
    printfn "Invalid argument %s" name
    valid

    它有这个签名:
    f:(string * 'a -> bool) -> name:string * value:'a -> bool

    所以你现在可以用“真实的” isValid 组合它像这样的功能:
    inputs
    |> Seq.filter (log isValid)
    |> execution

    isValid函数具有签名 name:'a * value:int -> bool它适合 f log 的论据功能,您可以部分应用上述日志功能。

    关于f# - 如何避免多次迭代作为一种模式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24900208/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com