由以下原因引起的编译错误:警告:此构造导致代码比类型注释指示的更不通用。
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
本身 ,它只关心 incr
和 cb
,并且这些仅在 'T
中通用,在 'State
中不通用。所以不要给它 line
本身,只给它 incr
和 cb
.
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 ]
如果你想获得哲学,问题的根源在于完成incr
和cb
,将它们捆绑在一起,当它们显然不必须如此。总的来说,这是一个很好的经验法则:尽可能地保持小而独立。
如果你仔细观察,你会发现"classes"(或"objects")正是这样:一种complecting具有多种功能的多种数据的手段。尽量避免使用类。
提问前先解释一下。我有一个序列,我想对其执行一些折叠操作。但是评估序列是缓慢且昂贵的(它在数据库中迭代)并且(虽然这里没有明确说明)我想向用户提供渐进式输出。所以我真的很想一次性完成所有的折叠。类似于:
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
本身 ,它只关心 incr
和 cb
,并且这些仅在 'T
中通用,在 'State
中不通用。所以不要给它 line
本身,只给它 incr
和 cb
.
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 ]
如果你想获得哲学,问题的根源在于完成incr
和cb
,将它们捆绑在一起,当它们显然不必须如此。总的来说,这是一个很好的经验法则:尽可能地保持小而独立。
如果你仔细观察,你会发现"classes"(或"objects")正是这样:一种complecting具有多种功能的多种数据的手段。尽量避免使用类。