另一个价值限制问题



在下面的代码中,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

我希望它是通用的,但是把它放在一个文件中,除了它的用途,会产生一个值限制错误:

值限制。的值'generateUnique'已被推断为具有泛型valgenerateUnique: (('_a -> '_b) -> '_c-> seq<"_a>)当"_b:> seq<"_a>和"_c:> seq<">要么使'generateUnique'的参数显式或者,如果你不想这样泛型,添加类型注释。

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

没有类型参数的输出(期望的/正确的行为):

["mscorlib"; "TEST"]
["FSharp.Core"; "System"]
["System.Core"; "System.Security"]
[]
[]
与:

["mscorlib"; "TEST"]
["mscorlib"; "TEST"]
["mscorlib"; "TEST"]
["mscorlib"; "TEST"]
["mscorlib"; "TEST"]

为什么行为会改变?如何使函数泛型实现所需的行为?

generateUnique很像标准的memoize模式:它应该用于从普通函数中计算记忆函数,而不是自己进行实际的缓存。

@kvb是正确的,在这个转换所需的定义的变化,但然后你需要改变discoverAssemblies的定义如下:

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

我不认为你的定义是非常正确的:在我看来,f需要是generateUnique的语法参数(也就是说,我不认为使用相同的HashSet不同的f s是有意义的)。

let generateUnique f =    
    let known = HashSet()    
    fun 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

相关内容

  • 没有找到相关文章

最新更新