记住类型() - >'a的函数

Gos*_*win 10 f# unit-type

这个memoize函数() -> 'a 在运行时使用Null-Argument-Exception在类型的任何函数上失败.

let memoize f =
    let cache = System.Collections.Generic.Dictionary()
    fun x ->
        if cache.ContainsKey(x) then 
            cache.[x]
        else 
            let res = f x
            cache.[x] <- res
            res
Run Code Online (Sandbox Code Playgroud)

有没有办法写一个memoize函数,也适用于() -> 'a

(我现在唯一的选择是使用一个Lazy类型.调用x.Force()来获取值.)

Tom*_*cek 11

函数失败的原因是F#表示()使用null类型的单位unit.字典不允许将null值作为键,因此失败.

在你的特定情况下,memoizing类型的功能没有太大意义unit -> 'a(因为它最好lazy用于此),但是在其他情况下这将是一个问题 - 例如None也表示null如此,这也失败了:

let f : int option -> int = memoize (fun a -> defaultArg a 42)
f None
Run Code Online (Sandbox Code Playgroud)

解决这个问题的简单方法是将密钥包装在另一种数据类型中以确保它永远不会null:

type Key<'K> = K of 'K
Run Code Online (Sandbox Code Playgroud)

然后你可以用K构造函数包装密钥,一切都会很好地工作:

let memoize f =
    let cache = System.Collections.Generic.Dictionary()
    fun x ->
        if cache.ContainsKey(K x) then 
            cache.[K x]
        else 
            let res = f x
            cache.[K x] <- res
            res
Run Code Online (Sandbox Code Playgroud)


Gos*_*win 5

我刚刚发现最后memoize的功能在同一网站上使用Map,而不是Dictionary用于工作'a Option -> 'b() -> 'a太:

let memoize1 f =
    let cache = ref Map.empty
    fun x ->
        match (!cache).TryFind(x) with
        | Some res -> res
        | None ->
            let res = f x
            cache := (!cache).Add(x,res)
            res
Run Code Online (Sandbox Code Playgroud)