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

时间:2015-05-14 15:16:22

标签: generics f#

在我提出这个问题之前先做一点解释。我有一个序列,我想要执行多个折叠操作。但是评估序列是缓慢而昂贵的(它在数据库中迭代)和(虽然这里没有明确)我想向用户提供渐进式输出。所以我真的很想一次性做所有的折叠。类似的东西:

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的类型。

我已经尝试了其他几种方法(例如,将行划分为有区别的联合,将行划分为抽象基类等等),并且在每种情况下我都会遇到原始问题的其他一些表现形式。我真的不知道接下来要去哪儿。

这不觉得它应该是一个难题,但我想我在某个地方有一个盲点。任何提示感激不尽。

由于

1 个答案:

答案 0 :(得分:1)

请注意CoFold并不真正关心line 本身,它只关心incrcb,而这些只关注'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,将它们捆绑在一起,当它们显然不必是。一般来说,这是一个很好的经验法则:尽可能保持小而且分开。
如果你仔细观察,你会发现“类”(或“对象”)就是这样的:用多个函数来收集多个数据的方法。尽量避免尽可能多地使用类。