在下面的代码中,Seq.generateUnique被限制为((Assembly -> seq<Assembly>) -> seq<Assembly> -> seq<Assembly>)类型。

open System
open System.Collections.Generic
open System.Reflection

module Seq =
  let generateUnique =
    let known = HashSet()
    fun f initial ->
      let rec loop items =
        seq {
          let cachedSeq = items |> Seq.filter known.Add |> Seq.cache
          if not (cachedSeq |> Seq.isEmpty) then
            yield! cachedSeq
            yield! loop (cachedSeq |> Seq.collect f)
        }
      loop initial

let discoverAssemblies() =
  AppDomain.CurrentDomain.GetAssemblies() :> seq<_>
  |> Seq.generateUnique (fun asm -> asm.GetReferencedAssemblies() |> Seq.map Assembly.Load)

let test() = printfn "%A" (discoverAssemblies() |> Seq.truncate 2 |> Seq.map (fun asm -> asm.GetName().Name) |> Seq.toList)
for _ in 1 .. 5 do test()
System.Console.Read() |> ignore

我希望它是通用的,但将其放入文件中而不使用会产生值限制错误:



添加显式类型参数(let generateUnique<'T> = ...)消除了该错误,但是现在它返回不同的结果。

没有类型参数的输出(期望/正确的行为):
["mscorlib"; "TEST"]
["FSharp.Core"; "System"]
["System.Core"; "System.Security"]
[]
[]

与:
["mscorlib"; "TEST"]
["mscorlib"; "TEST"]
["mscorlib"; "TEST"]
["mscorlib"; "TEST"]
["mscorlib"; "TEST"]

为什么行为会改变?如何使该函数通用并实现所需的行为?

最佳答案

generateUnique与标准memoize模式非常相似:应使用discoverAssemblies从普通函数计算记忆函数,而不是实际进行缓存。

@kvb关于此更改所需的定义更改是正确的,但是随后您需要按以下方式更改ojit_code的定义:

let discoverAssemblies =
  //"memoize"
  let generator = Seq.generateUnique (fun (asm:Assembly) -> asm.GetReferencedAssemblies() |> Seq.map Assembly.Load)

  fun () ->
      AppDomain.CurrentDomain.GetAssemblies() :> seq<_>
      |> generator

关于f# - 另一个值(value)限制问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6616078/

10-13 06:53