由以下原因引起的编译错误:警告:此构造导致代码比类型注释指示的更不通用。

Compile errors caused by: Warning: This construct causes code to be less generic than indicated by the type annotations.

提问前先解释一下。我有一个序列,我想对其执行一些折叠操作。但是评估序列是缓慢且昂贵的(它在数据库中迭代)并且(虽然这里没有明确说明)我想向用户提供渐进式输出。所以我真的很想一次性完成所有的折叠。类似于:

theSeq |> Seq.CoFold [
    line (folder1, initAcc1, action1)
    line (folder2, initAcc2, action2)
]

action 是折叠完成后用累加器完成的事情。我会像这样使用它:

theSeq |> Seq.CoFold [
    line ((fun acc r -> acc+1), 0, (fun d -> printfn "%A" d)) // counter
    line ((fun acc r -> acc.Add(r), Set.empty, whatever) // uniques
]

我发现无论 line 是什么,它都应该根据 theSeq 的类型进行泛型化,但不应该依赖于 initAcc 的类型,或文件夹功能本身的类型。所以,我想出了以下(不起作用):

module Seq =
    type 'T line (f:'State -> 'T -> 'State, a:'State, cb:'State->unit) =
        let s = ref a
        member x.incr (j:'T) = s := f !s j
        member x.cb = cb !s

    let CoFold (folders: 'T line list) (jj: 'T seq) =
        for j in jj do
            folders |> List.iter (fun o -> o.incr j)
        folders |> List.iter (fun o -> o.cb)

这个问题是它想要基于 'T'State 的泛型 line,这意味着我上面显示的两行与彼此,即使两者都没有公开 acc.

的类型

我尝试了其他几种方法(例如,将 line 变成一个可区分的联合,将 line 变成一个抽象基 class,等等),并且在每种情况下我 运行 变成其他一些原问题的体现。我真的不知道下一步该去哪里。

这不应该是一个难题,但我想我在某个地方有一个盲点。感谢收到任何提示。

谢谢

请注意 CoFold 并不真正关心 line 本身 ,它只关心 incrcb ,并且这些仅在 'T 中通用,在 'State 中不通用。所以不要给它 line 本身,只给它 incrcb.

type 'T line = ('T -> unit) * (unit -> unit)

let makeLine incr a cb: line<_> =
  let s = ref a
  let incr' t = s := incr !s t
  let cb' () = cb !s
  incr', cb'

let CoFold (folders: 'T line list) (jj: 'T seq) =
  for j in jj do
      folders |> List.iter (fun (incr,_) -> incr j)
  folders |> List.iter (fun (_,cb) -> cb() )

aSeq |> Seq.CoFold [
  makeLine f1 s1 a1
  makeLine f2 s2 a2 ]

如果你想获得哲学,问题的根源在于完成incrcb,将它们捆绑在一起,当它们显然不必须如此。总的来说,这是一个很好的经验法则:尽可能地保持小而独立。
如果你仔细观察,你会发现"classes"(或"objects")正是这样:一种complecting具有多种功能的多种数据的手段。尽量避免使用类。