在我提出这个问题之前先做一点解释。我有一个序列,我想要执行多个折叠操作。但是评估序列是缓慢而昂贵的(它在数据库中迭代)和(虽然这里没有明确)我想向用户提供渐进式输出。所以我真的很想一次性做所有的折叠。类似的东西:
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)
问题在于它希望基于line
和'T
来通用'State
,这意味着我上面显示的两条线彼此不兼容,即使它们都没有公开acc
的类型。
我已经尝试了其他几种方法(例如,将行划分为有区别的联合,将行划分为抽象基类等等),并且在每种情况下我都会遇到原始问题的其他一些表现形式。我真的不知道接下来要去哪儿。
这不觉得它应该是一个难题,但我想我在某个地方有一个盲点。任何提示感激不尽。
由于
答案 0 :(得分:1)
请注意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
如果你想获得哲学,问题的根源在 complecting $http.post(url, _.omit($scope.toBeSaved, ['someAttributeTobeFiltered', 'foo', 'bar']))
和generateWSSecurityHeader
,将它们捆绑在一起,当它们显然不必是。一般来说,这是一个很好的经验法则:尽可能保持小而且分开。
如果你仔细观察,你会发现“类”(或“对象”)就是这样的:用多个函数来收集多个数据的方法。尽量避免尽可能多地使用类。