简体   繁体   English

F#通用问题:无法笼统,因为它将逃避其范围

[英]F# Generic Problem: could not be generalized because it would escape its scope

I have this defined in a common place: 我在一个普通的地方定义了这个:

[<DataContract>]
type ResultObject = {
    [<DataMember>]
    mutable field1: string
    [<DataMember>]
    mutable field2: string
    [<DataMember>]
    mutable field3: int 
}

let createCache<'T> () =
    Dictionary<_, 'T option>(HashIdentity.Structural)  


let memoizeSingleParamWithCallback<'R, 'P when 'P : equality>  functionToMemoize =    

    let cache = createCache<'R>() 

    // return a function that takes two parameters a parameter to the functionToMemoize  and a callback 
    fun (parameter: 'P) (callback: Action<_>) ->
        // form a unique cache key the parameterValue
        let key = parameter

        // check to see if the cache contains they key
        match cache.ContainsKey(key) with
        // if so invoke the callback with the cache value (need to conver to Some)
        | true -> callback.Invoke(cache.[key])
        // if not, invoke the RPC function, store the value, and perform the callback
        | false ->
            // create an internim callback to intercept the RPC function results, 
            //     store the value, and perform the final callback
            let updateCache (results: 'R option) = 
                match results with
                // no results returned - invoke call back with None none
                | None -> 
                    cache.[key] <- None
                    callback.Invoke(None)
                // results returned - store them and invoke the call back 
                | Some result -> 
                    cache.[key] <- Some(result)
                    callback.Invoke(Some(result))
            functionToMemoize parameter  <| new Action<_>(updateCache)

And am attempting to use it as so: 并尝试按以下方式使用它:

let findTickers (partialTicker : String) (callbackUI : Action<_>) =
    let lstOfResultObjects = [{field1=""; field2=""; field3=3}]
    callbackUI.Invoke(Some(lstOfResultObjects))


let findTickersMemoize = memoizeSingleParamWithCallback<ResultObject array, string>  findTickers 

and recieve this error on the memoize function definition: 并在备忘录功能定义中收到此错误:

This code is not sufficiently generic. 该代码不够通用。 The type variable 'P when 'P : equality could not be generalized because it would escape its scope. 类型变量'P when'P:equal不能被概括,因为它将逃避其范围。

My two questions are: 我的两个问题是:

  1. What is this error telling me 这个错误告诉我什么
  2. Is there a way to overcome this error 有没有办法克服这个错误

Everythign compiles by removing by typing parameter to string: Everythign通过在字符串中键入参数来删除来进行编译:

 fun (parameter: 'P) (callback: Action<_>) ->
     ()

HOWEVER I want to be able to memoize, more than functions with a: String Action<_> signature, ideally the string could be an int, float, object - whatever... 但是,除了具有以下功能的函数外,我还希望能够记住:String Action <_>签名,理想情况下,该字符串可以是int,float,object-等等。

The issue is that you have provided a single type parameter 'T on your definition of createCache , but when you instantiate it in memoizeSingleParamWithCallback , you want to get back a Dictionary<'P, 'R option> . 问题是您在createCache的定义上提供了一个类型参数'T ,但是当在memoizeSingleParamWithCallback实例化它时,您想要获取Dictionary<'P, 'R option> You can actually just remove some of the type parameters and annotations to get your code to work: 实际上,您可以删除一些类型参数和注释以使代码正常工作:

let createCache() =
    Dictionary<_, _>(HashIdentity.Structural)  


let memoizeSingleParamWithCallback  functionToMemoize =    

    let cache = createCache() 

    // return a function that takes two parameters a parameter to the functionToMemoize  and a callback 
    fun (parameter: 'P) (callback: Action<_>) ->
        // form a unique cache key the parameterValue
        let key = parameter

        // check to see if the cache contains they key
        match cache.ContainsKey(key) with
        // if so invoke the callback with the cache value (need to conver to Some)
        | true -> callback.Invoke(cache.[key])
        // if not, invoke the RPC function, store the value, and perform the callback
        | false ->
            // create an internim callback to intercept the RPC function results, 
            //     store the value, and perform the final callback
            let updateCache (results: 'R option) = 
                match results with
                // no results returned - invoke call back with None none
                | None -> 
                    cache.[key] <- None
                    callback.Invoke(None)
                // results returned - store them and invoke the call back 
                | Some result -> 
                    cache.[key] <- Some(result)
                    callback.Invoke(Some(result))
            functionToMemoize parameter  <| new Action<_>(updateCache)

Now F# infers the most general types that are applicable, which results in createCache correctly depending on two implicit type parameters. 现在,F#推断适用的最通用类型,这取决于两个隐式类型参数正确地创建了createCache

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM