我正在嘗試使用占位符支持來實作 curry(),即curriable. curriable提供了一種高性能和小尺寸的curry方法。version1 是在遞回函式中使用 map 的作業代碼。但是,我嘗試使用過濾器過濾version2中的占位符!在大多數情況下使用過濾器是好的,但是 curriedJoin(_,_,3,4)(1,_)(2,5)由于原因而失敗,Uncaught TypeError: curriedJoin(...)(...) is not a function有人能告訴我為什么嗎?
版本 1
/**
* @param { (...args: any[]) => any } fn
* @returns { (...args: any[]) => any }
*/
// function curry(fn) {
// // your code here
// }
function curry(func) {
return function curried(...args) {
const complete = args.length >= func.length && !args.slice(0, func.length).includes(curry.placeholder);
if(complete) {
args.length=3
args.sort((a,b)=>a-b)
return func.apply(this, args)
}
return function(...newArgs) {
// replace placeholders in args with values from newArgs using map
const res = args.map(arg => arg === curry.placeholder && newArgs.length ? newArgs.shift() : arg);
return curried(...res, ...newArgs);
}
}
}
const join = (a, b, c) => {
return `${a}_${b}_${c}`
}
curry.placeholder = Symbol()
const curriedJoin = curry(join)
const _ = curry.placeholder
console.log(curriedJoin(1, 2, 3)) // '1_2_3'
console.log(curriedJoin(_, 2)(1, 3)) // '1_2_3'
console.log(curriedJoin(_, _, _)(1)(_, 3)(2)) // '1_2_3'
console.log(curriedJoin(_,_,3,4)(1,_)(2,5))// '1_2_3'
版本 2
/**
* @param { (...args: any[]) => any } fn
* @returns { (...args: any[]) => any }
*/
// function curry(fn) {
// // your code here
// }
function curry(func) {
return function curried(...args) {
const complete = args.length >= func.length && !args.slice(0, func.length).includes(curry.placeholder);
if(complete) {
args.length=3
args.sort((a,b)=>a-b)
return func.apply(this, args)
}
return function(...newArgs) {
// replace placeholders in args with values from newArgs
const res = [...args].filter(element=> element!== curry.placeholder);
return curried(...res, ...newArgs);
}
}
}
const join = (a, b, c) => {
return `${a}_${b}_${c}`
}
curry.placeholder = Symbol()
const curriedJoin = curry(join)
const _ = curry.placeholder
console.log(curriedJoin(1, 2, 3)) // '1_2_3'
console.log(curriedJoin(_, 2)(1, 3)) // '1_2_3'
console.log(curriedJoin(_, _, _)(1)(_, 3)(2)) // '1_2_3'
console.log(curriedJoin(_,_,3,4)(1,_)(2,5)) //Fail, because "Uncaught TypeError: curriedJoin(...)(...) is not a function"
uj5u.com熱心網友回復:
如果你添加
console.log(curriedJoin(_,_,3,4)(1,_));
就在失敗行之前,您會看到 curriedJoin(_, _, 3, 4)(1, _) 已經決議為字串 "1_3_4" ...這不是一個函式。因此錯誤。這兩個版本的行為完全不同(在處理程序中記錄各種 arg 串列是有益的。)使用“過濾和附加”方法的問題在于它沒有將 args 置于正確的順序。對于失敗的示例,在一次迭代之后,第三個占位符最終出現在 arg 串列的末尾,超出了“完整”測驗正在檢查的位置,而不是它所屬的第二個位置。過濾時發生的情況是 (_, _, 3, 4)(1, _) 變為 (3,4,1,_),但 func 只需要 3 個好的引數,所以這看起來“完整” - 哎呀!當使用“map”演算法時,(_, _, 3, 4)(1, _) 變為 (1, _, 3,
uj5u.com熱心網友回復:
的使用.sort涉及引數值的比較,并且不會針對它們的應用位置應用引數。的使用args.length = 3將僅支持具有 3 個引數的函式。
添加引數n = f.length支持固定數量函式和可變引數函式的柯里化。添加curry.merge合理的歸納推理可以簡化合并論點并降低curry.
function curry(f, n = f.length) {
return function loop(...args) {
const a = args.slice(0, n)
return a.some(v => v === curry.placeholder)
? (...b) => loop(...curry.merge(a, b))
: f(...a)
}
}
curry.placeholder = Symbol("curry.placeholder")
curry.merge = (l, r) =>
l.length == 0 && r.length == 0
? []
: l.length == 0
? r
: r.length == 0
? l
: l[0] === curry.placeholder
? [r[0], ...curry.merge(l.slice(1), r.slice(1))]
: [l[0], ...curry.merge(l.slice(1), r)]
const _ = curry.placeholder
const add = curry((a,b,c) => a b c)
console.log(add(1, 2, 3)) // 6
console.log(add(_, 2)(1, 3)) // 6
console.log(add(_, _, _)(1)(_, 3)(2)) // 6
console.log(add(_,_,3,4)(1,_)(2,5)) // 6
const foo = curry(console.log, 3)
foo(1, 2, 3) // 1 2 3
foo(_, 2)(1, 3) // 1 2 3
foo(_, _, _)(1)(_, 3)(2) // 1 2 3
foo(_,_,3,4)(1,_)(2,5) // 1 2 3
也許更好的名稱curry是partial因為您在這里使用的技術與Partial Application更密切相關。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/434924.html
