不可变记忆——这可能吗?
Immutable Memoization - is it possible?
我正在努力使我的前端堆栈在功能上尽可能纯净和不变,并为这个项目创造奇迹。
据说所有可以可变实现的算法都可以不可变实现,所以在javascript中我将如何实现一个不可变函数记忆器?因为为了 return 通过函数中的不同路径,函数内部或外部的某些状态必须更改。
使用以下函数,如何在 javascript 中进行不可变记忆?
function once(fn){
let returnValue;
let canRun = true;
return function runOnce(){
if(canRun) {
returnValue = fn.apply(this, arguments);
canRun = false;
}
return returnValue;
}
}
var processonce = once(process);
processonce(); //process
processonce(); //
我也很好奇这个问题。我同意@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))
// Calculating value for f(7)
// Calculating value for f(6)
// Calculating value for f(5)
// Calculating value for f(4)
// Calculating value for f(3)
// Calculating value for f(2)
// Caching result: f(2)=1
// Calculating value for f(1)
// Caching result: f(1)=1
// Caching result: f(3)=2
// Cache hit for n=2
// Caching result: f(4)=3
// Cache hit for n=3
// Caching result: f(5)=5
// Cache hit for n=4
// Caching result: f(6)=8
// Cache hit for n=5
// Caching result: f(7)=13
// Cache hit for n=6
// THE RESULT: 21
为了更好地理解发生了什么 - cacheResult
和 memoize
函数注入了日志包装器。如您所见,所有函数都是纯函数,只接受一个参数(依赖注入除外)。
请确定,resultCombination(cache)(result)
- 只是 {cache, result}
数据结构的替换。
P.S。我不是 Haskell 书呆子(甚至根本不知道 Haskell 或 Lisp 语法),但我对函数式编程充满热情
我提出了一个不同的 io 方法,使用生成器我们可以说它是纯粹的吗?
function* _cache() {
const value = yield null
while (true) yield value
}
const cache = _cache()
const heavyComputation = i => {
console.log(`uh oh that's some heavy computations here`)
return i++
}
cache.next().value
cache.next(heavyComputation(1))
cache.next().value
cache.next().value
然后您可以使用它在运行时缓存一个值
function* _cache() {
const value = yield null
while (true) yield value
}
const cache = _cache()
const loadMongo = uri => void console.log(`fully loaded ${uri}`)
function end(loadedMongo) {
console.log('handler called')
}
function handler() {
const mongoUri = 'salutos speculos'
const loaded = cache.next().value
if (loaded === null) {
cache.next(loadMongo(mongoUri))
end(cache.next().value)
} else end(loaded)
}
handler()
handler()
handler()
handler()
handler()
我正在努力使我的前端堆栈在功能上尽可能纯净和不变,并为这个项目创造奇迹。
据说所有可以可变实现的算法都可以不可变实现,所以在javascript中我将如何实现一个不可变函数记忆器?因为为了 return 通过函数中的不同路径,函数内部或外部的某些状态必须更改。
使用以下函数,如何在 javascript 中进行不可变记忆?
function once(fn){
let returnValue;
let canRun = true;
return function runOnce(){
if(canRun) {
returnValue = fn.apply(this, arguments);
canRun = false;
}
return returnValue;
}
}
var processonce = once(process);
processonce(); //process
processonce(); //
我也很好奇这个问题。我同意@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))
// Calculating value for f(7)
// Calculating value for f(6)
// Calculating value for f(5)
// Calculating value for f(4)
// Calculating value for f(3)
// Calculating value for f(2)
// Caching result: f(2)=1
// Calculating value for f(1)
// Caching result: f(1)=1
// Caching result: f(3)=2
// Cache hit for n=2
// Caching result: f(4)=3
// Cache hit for n=3
// Caching result: f(5)=5
// Cache hit for n=4
// Caching result: f(6)=8
// Cache hit for n=5
// Caching result: f(7)=13
// Cache hit for n=6
// THE RESULT: 21
为了更好地理解发生了什么 - cacheResult
和 memoize
函数注入了日志包装器。如您所见,所有函数都是纯函数,只接受一个参数(依赖注入除外)。
请确定,resultCombination(cache)(result)
- 只是 {cache, result}
数据结构的替换。
P.S。我不是 Haskell 书呆子(甚至根本不知道 Haskell 或 Lisp 语法),但我对函数式编程充满热情
我提出了一个不同的 io 方法,使用生成器我们可以说它是纯粹的吗?
function* _cache() {
const value = yield null
while (true) yield value
}
const cache = _cache()
const heavyComputation = i => {
console.log(`uh oh that's some heavy computations here`)
return i++
}
cache.next().value
cache.next(heavyComputation(1))
cache.next().value
cache.next().value
然后您可以使用它在运行时缓存一个值
function* _cache() {
const value = yield null
while (true) yield value
}
const cache = _cache()
const loadMongo = uri => void console.log(`fully loaded ${uri}`)
function end(loadedMongo) {
console.log('handler called')
}
function handler() {
const mongoUri = 'salutos speculos'
const loaded = cache.next().value
if (loaded === null) {
cache.next(loadMongo(mongoUri))
end(cache.next().value)
} else end(loaded)
}
handler()
handler()
handler()
handler()
handler()