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

时间:2015-04-16 20:29:42

标签: 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.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

这导致非常简单:

  

val结果:Foo list * seq =([A 0; A 1; C 2; B 3],)

不知怎的,我觉得应该有一种更简单的方法来实现同样的目标。

事实上,我知道一种方法可以使它变得更简单,但这会涉及可变的状态和记忆(因此可能会被认为更糟):

let idgen startvalue =
    let v = ref startvalue
    fun () ->
        let result = !v
        v := !v + 1
        result

通过这样接收的生成器函数,我可以摆脱所有这些元组,至少我也可以摆脱create函数并简单地写:

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

但是也应该存在一种“功能性”的方式来更简单地完成它。

3 个答案:

答案 0 :(得分:4)

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

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

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]

答案 1 :(得分:0)

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

这里有几个注意事项:

  1. ABCint -> Foo类型的构造函数。您可以直接将它们用作函数并消除重复的包装函数;
  2. Seq.map2能够处理不同长度的序列,并忽略较长的序列;
  3. idfun f number -> f number的快捷方式,如果您发现id不清楚,请使用较长的
  4. 您也可以将ids功能重构为Seq.initInfinite id |> Seq.skip startvalue
  5. 最后,如果您确实需要,可以将序列转换为List
  6. 已更新以接收保留inextI

答案 2 :(得分:0)

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

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]