我也对这个问题很好奇。我同意@zch的观点-传递不可变状态会起作用(初始调用将使用空状态初始化递归)。
因此,我通过实现斐波那契函数来完成我的作业:记住,我们至少需要两次斐波那契函数来计算n-1和n-2。当我们调用fib(n-2)
时,它已经被记忆化了。
这是我的实现:
const resultCombination = cache => result => (getResult = true) => getResult ? result : cache
const cacheResult = ({resultCombination}) => result => n => resultCombination({...result(false), [n]: result()})(result())
const memoize = ({resultCombination, cacheResult}) => cache => f => n => cache.hasOwnProperty(n)
? resultCombination(cache)(cache[n])
: cacheResult({resultCombination})(f(cache)(n))(n)
const fib2 = ({resultCombination, cacheResult, memoize}) => f1Result => f => n => resultCombination(f1Result(false))(f1Result() + memoize({resultCombination, cacheResult})(f1Result(false))(f)(n - 2)())
const fib = ({resultCombination, cacheResult, memoize, fib2}) => cache => n => n === 1 || n === 2
? resultCombination(cache)(1)
: fib2({resultCombination, cacheResult, memoize})(memoize({resultCombination, cacheResult})(cache)(fib({resultCombination, cacheResult, memoize, fib2}))(n - 1))(fib({resultCombination, cacheResult, memoize, fib2}))(n)
console.log('THE RESULT: ' + fib({
resultCombination,
cacheResult: ({resultCombination}) => result => n => {
console.log(`Caching result: f(${n})=${result()}`)
return cacheResult({resultCombination})(result)(n)
},
memoize: ({resultCombination, cacheResult}) => cache => f => n => {
console.log(cache.hasOwnProperty(n) ? `Cache hit for n=${n}` : `Calculating value for f(${n})`)
return memoize({resultCombination, cacheResult})(cache)(f)(n)
},
fib2
})({})(8)(true))
为了更好地理解正在发生的事情,
cacheResult
和
memoize
函数被注入了日志包装器。如您所见,所有函数都是纯函数,仅接受一个参数(除了依赖注入)。
请注意,
resultCombination(cache)(result)
只是替换
{cache, result}
数据结构。
附言:我不是Haskell迷(甚至根本不知道Haskell或Lisp语法),但我热衷于函数式编程。