【问题标题】:F# Seq.next - what's the correct pattern?F# Seq.next - 正确的模式是什么?
【发布时间】:2015-10-12 22:59:09
【问题描述】:

作为使用策略模式的项目的一部分,我正在尝试编写一个函数,该函数创建一个函数,该函数在每次应用时返回无限序列的下一个值。目前我正在使用这个狡猾的 GetNext 功能:

let GetNext<'T> (enumerator:System.Collections.Generic.IEnumerator<'T>) =
    let n = enumerator.MoveNext()
    enumerator.Current

let FunctionFactory<'T> =
    let s = 0.0 |> Seq.unfold (fun i -> Some(i, if 0.0 = i then 1.0 else 0.0))
    let enumerator = s.GetEnumerator()
    (fun (ignoredParam:'T) -> GetNext enumerator )

我希望 FunctionFactory 看起来像这样:

let FunctionFactory<'T> =
    let s = 0.0 |> Seq.unfold (fun i -> Some(i, if 0.0 = i then 1.0 else 0.0))
    (fun (ignoredParam:'T) -> Seq.next s )

ignoredParam 用于通过相同策略模式并依赖于它提供的上下文的其他函数。既然这看起来很糟糕,我真的有两个问题。为什么没有Seq.next?实现可以注入到这样的策略框架中的各种序列表达式的正确/优雅的方式是什么

根据 Fyodor Soikin 的回答编辑 - 序列表达式目前对我很有吸引力,因为它们帮助我思考我正在研究的问题。而不是可变的命令式代码,我想在这个模式上构建更复杂的输入序列。

【问题讨论】:

    标签: .net design-patterns architecture f# seq


    【解决方案1】:

    您是否注意到您从未处理过枚举器? 这就是为什么没有Seq.next:它的使用需要不合理的设计。

    至于第二个问题,您要实现的“this”是什么并不完全清楚。据我从代码中收集到的,您正在尝试生成一个“有状态过程”,它将产生 1.0 或 0.0,每次调用时都会切换。对吧?

    如果是这样,我会通过可变值来实现。比序列少得多的开销:

    let FunctionFactory<'T> =
        let mutable flag = true
        fun (_:'T) -> 
           flag <- not flag
           if flag then 1.0 else 0.0
    

    【讨论】:

    • 为什么需要配置枚举器?当我删除对返回函数的所有引用时,不是垃圾收集了吗?我很欣赏这种实现工厂功能的替代方式。我设计我的应用程序的目的是在这个简单示例之外定义大量的序列表达式,我将更新问题以反映这一点,它会改变你对第二部分的答案吗?
    • 在这种特殊情况下,枚举数当然会被 GC 拾取。但是如果你想使用一般的序列,你必须正确地实现契约,并且契约清楚地表明枚举器必须被确定性地销毁。
    • 谢谢,我不喜欢它,但是当我浏览库实现时它是有道理的,我现在看到有多少 Seq.* 函数就像一个范围枚举:github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/…
    • 反过来看:您要寻找的是简单的不是序列。因为您希望它遵守不是 F# 序列的合同。因此,只需制定自己的合同! :-)
    猜你喜欢
    • 2023-03-07
    • 1970-01-01
    • 1970-01-01
    • 2021-02-21
    • 2017-11-16
    • 2023-03-21
    • 1970-01-01
    • 2013-03-03
    相关资源
    最近更新 更多