F# 是否有一种不那么笨拙的方法来对无限序列执行自动编号?

F# 是否有一种不那么笨拙的方法来对无限序列执行自动编号?,f#,F#,虽然我拥有的代码满足了我的需要,但我觉得我缺少了一些编码技术,无法以更简洁的方式实现这类东西 目标是组合项目并在过程中为其提供Id值。 这里的代码,我觉得可以简化和改进在许多方面。如果我知道,怎么 type Foo = | A of int | B of int | C of int let ids startvalue = Seq.initInfinite (fun i -> i + startvalue) let makeA ids = A(Seq.head ids), Seq

虽然我拥有的代码满足了我的需要,但我觉得我缺少了一些编码技术,无法以更简洁的方式实现这类东西

目标是组合项目并在过程中为其提供Id值。 这里的代码,我觉得可以简化和改进在许多方面。如果我知道,怎么

type Foo = | A of int | B of int | C of int
let ids startvalue = Seq.initInfinite (fun i -> i + startvalue)
let makeA ids =
    A(Seq.head ids), Seq.skip 1 ids
let makeB ids =
    B(Seq.head ids), Seq.skip 1 ids
let makeC ids =
    C(Seq.head ids), Seq.skip 1 ids
let config = [makeA; makeA; makeC; makeB]
let create (ids : seq<int>) (cfg : (seq<int> -> Foo * seq<int>) list) : Foo list * seq<int> =
    let rec cre ids1 acc cl =
        match cl with
        | [] -> (acc,ids1)
        | x::xs -> 
            let v,ids2 = x ids1
            cre ids2 (acc @ [v]) xs
    cre ids [] cfg
let result : Foo list * seq<int> = create (ids 0) config
通过这样接收的生成器函数,我可以去掉所有这些元组,至少我还可以去掉
create
函数,只需编写:

let ids = idgen 0
let result =
    [
        A(ids())
        A(ids())
        C(ids())
        B(ids())
    ]

但是也应该有一种“函数式”的方法来更简单地完成它。

似乎你想要的是取两个序列,一个是函数,另一个是参数,并通过将函数应用于相应的参数来产生新的序列,其中,在特定情况下,参数是连续整数,函数是并集实例构造函数。这是正确的评估吗

如果是这样,我会这样做:

let create args funs = 
   Seq.zip args funs 
   |> Seq.map (fun (arg, fn) -> fn arg)
   |> List.ofSeq

let result = create (ids 0) [A; A; C; B]
这里有几个考虑因素:

  • A
    B
    C
    int->Foo
    类型的构造函数。您可以直接将它们用作函数,并消除重复的包装函数
  • Seq.map2
    能够处理不同长度的序列,并忽略较长序列的剩余元素
  • id
    fun f number->f number
    的快捷方式,如果您发现
    id
    不清楚,请使用较长的快捷方式
  • 您还可以将
    ids
    函数重构为
    Seq.initInfinite id |>Seq.skip startvalue
  • 最后,如果确实需要,可以将序列转换为
    列表

  • 更新了以接收keep
    i
    nextI

    正如Fyodor在回答中指出的那样,您实际上只想将构造函数应用于连续整数。您可以使用内置程序,将整个程序编写为:

    type Foo = | A of int | B of int | C of int
    let config = [A; A; B; C]
    let create offset = List.mapi (fun i f -> f (offset + i))
    create 78 config
    // val it : Foo list = [A 78; A 79; B 80; C 81]
    

    如果你的代码正在运行,而你“只是”想让它变得更好,我会在代码评审中发布这个,而不是堆栈溢出。这是堆栈溢出,而不是“FindTheBug”。老实说-这段代码的错误在于它没有按照它应该写的那样写。哈哈,这不仅仅是“找到错误”,而是SE网络上有一个更具体的站点…无论如何…@AdrianoRepetti是的,如果他们再增加50个“更具体”没有人会在任何地方提问,相反,所有人只会讨论问题属于哪个站点。@AdrianoRepetti我认为在这里要求一种简洁的方式来表示一个通用概念“添加连续ID”-非常合适。这只有在两个序列的长度相同的情况下才有效。由于合成是应用程序驱动的,而“id生成器”是一个实用程序,这通常不适用。事实上,不适用。这将适用于任何大小的序列,但当较短的序列“用完”时,它将停止,这正是您最初的代码似乎实现的。“将两个列表合并为一个成对列表。这两个列表的长度必须相等。”写在这里:。我默默地假设序列也是一样的……嗯……但事实并非如此!宾果游戏,谢谢!好东西。但和另一个答案一样,我现在想知道这种方法是否会让我“输”“序列的状态。也就是说,我无法继续编写更多这样的列表,对吗?根据您的评论更新了答案。鉴于
    List.length
    是O(N),在
    create
    中调用它真的是个好主意吗?@ildjarn是的,这当然取决于实际应用程序。另一种方法是处理序列迭代器或可变状态。OP要求提供一种简洁而实用的方法。@ildjarn我确实在寻找一种实用的解决方案,并在问题中展示了“可变”解决方案。我从所有这一切中得出结论,在这种情况下,我不会基于原则拒绝可变的解决方案。短代码通常是更好的代码,我认为我在最后概述的记忆版本确实更可取。作为旁白,我意识到这可能只是一个例子,您可能希望将id提升到受歧视的联合之外:
    type undernative=A | B | C;输入Foo=underground*int
    (请参阅)。
    type Foo = | A of int | B of int | C of int
    let ids startvalue = Seq.initInfinite (fun i -> i + startvalue)
    let config = [A; A; C; B]
    let create ids i cfg =
        let ids' = ids i
        let nextI = i + List.length cfg
        (Seq.map2 id cfg ids'), nextI
    let result, nextI = create ids 0 config
    let result2, nextI2 = create ids nextI config
    
    type Foo = | A of int | B of int | C of int
    let config = [A; A; B; C]
    let create offset = List.mapi (fun i f -> f (offset + i))
    create 78 config
    // val it : Foo list = [A 78; A 79; B 80; C 81]