如何使用顺序记忆

时间:2018-12-09 00:41:00

标签: functional-programming

let memoize (sequence: seq<'a>) =
    let cache = Dictionary()
    seq {for i in sequence -> 
         match cache.TryGetValue i with
         | true, v -> printf "cached"
         | false,_ -> cache.Add(i ,i)
    }

我将在此函数内调用我的备忘录函数:

let isCached (input:seq<'a>) : seq<'a> = memoize input

如果已缓存给定序列项,则应打印已缓存,否则它将继续向缓存添加序列值。

现在我在类型方面遇到了问题。

当我尝试这样调用我的函数时:

let seq1 = seq { 1 .. 10 }
isCached seq1

它引发错误

"The type int does not match the type unit"

即使返回printfn,我也希望我的函数能正常工作。有可能实现这一目标吗?并且在向缓存中添加值时,是否应该为元组赋予相同的值?

例如:

| false,_ -> cache.Add(i ,i)

2 个答案:

答案 0 :(得分:5)

我认为问题在于您的memoize函数实际上并未将源序列中的项目作为返回序列的下一个元素返回。您的版本仅将项目添加到缓存中,但随后返回unit。您可以通过以下方式解决此问题:

let memoize (sequence: seq<'a>) =
    let cache = Dictionary()
    seq {for i in sequence do
           match cache.TryGetValue i with
           | true, v -> printf "cached"
           | false,_ -> cache.Add(i ,i)
           yield i }

我使用显式yield而不是->,因为我认为这使代码更具可读性。进行此更改后,代码将按我的预期运行。

答案 1 :(得分:0)

Tomas P击败了我,但无论如何我都会把它发布出来,以防万一。

我不太确定您要在这里实现什么,但是我会说一些我认为可能有帮助的事情。

首先,类型错误。您的isCached函数定义为采用类型'a的序列,并返回类型'a的序列。正如您在问题中所写,现在它需要一个'a类型的序列,并返回一个单位类型的序列。如果您尝试将输出规范修改为seq <'b>(或者实际上完全省略了它并让类型推断执行了此操作),则应该克服类型错误。由于您实际上并没有从该函数返回缓存(您可以只添加cache作为最后一行来返回它),这可能仍然无法满足您的要求。因此,请尝试以下操作:

let memoize (sequence: seq<'a>) =
    let cache = Dictionary()
    for i in sequence do 
         match cache.TryGetValue i with
         | true, v -> printf "cached"
         | false,_ -> cache.Add(i ,i)

    cache

let isCached (input:seq<'a>) : seq<'b> = memoize input

所有这些,如果您希望对同一序列进行很多迭代,那么最好只使用库函数Seq.cache

最后,关于在字典中使用值作为键的问题……没有什么阻止您这样做的,但这的确是毫无意义的。如果您已经有一个值,则无需在字典中查找它。如果您只是想记住序列,请使用给定元素的索引作为键。或使用特定的输入作为键,并使用该输入的输出作为值。