如何参数化f#类

时间:2022-06-01 18:19:23

The class below is a wrapper around an async MailboxProcessor that exposes a few operations to C# assemblies. However, I don't want just a few

下面的类是一个围绕异步邮箱处理器的包装器,它向c#程序集公开一些操作。然而,我不想要几个

Map<string,int>

instances, I need several different Map<'K,'V> instances where 'K and 'V vary. I hope I don't need a functor for that (it probably doesn't exist in F#).

实例,我需要几个不同的映射<'K,'V>实例,其中'K和'V变化。我希望我不需要这个函数(它可能不存在于f#中)。

module Flib.AsyncEvents
open System.Collections.Generic

type KVcoll = Map<string,int>
type Msg = Request of string * int option | Fetch of AsyncReplyChannel<KVcoll> | Clear

#nowarn "40"
type myAgent () = class
    let dictAgent = MailboxProcessor.Start(fun inbox->
        let dict = ref Map.empty
        let rec loop = async { 
            let! msg = inbox.Receive()       
            match msg with
            | Request (key, Some value) -> dict := Map.add key value !dict
            | Request (key, None) -> dict := Map.remove key !dict
            | Fetch(reply) -> reply.Reply(!dict)
            | Clear -> dict := Map.empty
            return! loop
            }
        loop)

    member this.add(key, value) = dictAgent.Post (Request (key, Some value))
    member this.del(key) = dictAgent.Post (Request(key, None))
    member this.fetch() = dictAgent.PostAndReply((fun reply -> Fetch(reply)), timeout = 9000)
    member this.lookup(key) = try 0, Map.find key (this.fetch()) // success
                              with | :? KeyNotFoundException -> -1, 0  // failure
    member this.size() = this.fetch().Count
    member this.clear() = dictAgent.Post (Clear)
    member this.print() =
           this.fetch() |> Map.iter (fun k v -> printfn "%s => %d" k v)
           printfn "done"
end

By the way, this is prototype quality code, clearly not as good as it can be.

顺便说一下,这是质量代码的原型,显然不是最好的。

1 个解决方案

#1


3  

I'm not sure I understand the question fully, but if you want to create a type that can be used with different types of values, you can define the class as generic:

我不确定我是否完全理解这个问题,但是如果您想创建一种可以与不同类型的值一起使用的类型,您可以将类定义为泛型:

type Msg<'K, 'V when 'K : comparison> = 
  | Request of 'K * 'V option 
  | Fetch of AsyncReplyChannel<Map<'K, 'V>> 
  | Clear

type MyAgent<'K, 'V when 'K : comparison> () = class
    let dictAgent = MailboxProcessor.Start(fun inbox->
        let dict : Map<'K, 'V> ref = ref Map.empty
        let rec loop = async { 
            // (same as before)
            }
        loop)

To make this work, you'll need to avoid code that restricts the type of keys and values to a particular type. In you case lookup was returning 0 as the default value and print was expecting strings. So you can replace those with something like:

要实现这一点,您需要避免将键和值的类型限制为特定类型的代码。在这种情况下,查找将返回0作为默认值,而print将等待字符串。所以你可以把它们替换成:

member this.lookup(key) = Map.tryFind key (this.fetch()) 
member this.print() =
       this.fetch() |> Map.iter (fun k v -> printfn "%A => %A" k v)
       printfn "done"

#1


3  

I'm not sure I understand the question fully, but if you want to create a type that can be used with different types of values, you can define the class as generic:

我不确定我是否完全理解这个问题,但是如果您想创建一种可以与不同类型的值一起使用的类型,您可以将类定义为泛型:

type Msg<'K, 'V when 'K : comparison> = 
  | Request of 'K * 'V option 
  | Fetch of AsyncReplyChannel<Map<'K, 'V>> 
  | Clear

type MyAgent<'K, 'V when 'K : comparison> () = class
    let dictAgent = MailboxProcessor.Start(fun inbox->
        let dict : Map<'K, 'V> ref = ref Map.empty
        let rec loop = async { 
            // (same as before)
            }
        loop)

To make this work, you'll need to avoid code that restricts the type of keys and values to a particular type. In you case lookup was returning 0 as the default value and print was expecting strings. So you can replace those with something like:

要实现这一点,您需要避免将键和值的类型限制为特定类型的代码。在这种情况下,查找将返回0作为默认值,而print将等待字符串。所以你可以把它们替换成:

member this.lookup(key) = Map.tryFind key (this.fetch()) 
member this.print() =
       this.fetch() |> Map.iter (fun k v -> printfn "%A => %A" k v)
       printfn "done"