我遇到了一个非常基本的功能编程任务,我无法在JavaScript中解决:
我正在尝试编写一个(高阶(功能,该功能采用两个数组domain
和image
并返回一个函数。返回的函数应返回 image
的 n
元素,当给定该域的 n
-元素:
示例:
let f = makeFunction([a,b,c],[d,e,f]);
f(a) //returns d
f(b) //returns e
f(c) //returns f
f(x) //any other value returns undefined
首先,我试图解决这个问题,就像在功能编程中通常这样做一样。(在球拍中示例(
(define makeFunction
(lambda (domain image)
(lambda (x)
(cond
[(= x (first domain)) (first image)
[else ((makeFunction (rest domain) (rest image) x)]
)
)
)
)
但是,在JS中不可能使用类似的事情,因为功能构造函数不会创建闭合(请参见此处(。因此,我的第二次尝试是简单地将数组串起并将其包含在功能定义中(我还包括输入检查(:
function makeFunction(domain, image){
if(new Set(domain).size==domain.length&&domain.length==image.length){
return new Function("x",`return ${JSON.stringify(image)}[${JSON.stringify(domain)}.indexOf(x)]`);
}else{
throw new Error("The lists don't allow the creation of a function, because they either don't have the same length or the domain isn't unique.");
}
}
只要原始数据类型是domain
包含的唯一数据类型,此功能就起作用。但是,一旦它包含对象,甚至循环数据,我就不知道如何使此功能起作用...
//works as expected:
let f = makeFunction([1,2,3,4,"foo"],[4,3,2,1,"bar"]);
//always returns undefined:
let g = makeFunction([{foo:"bar"},{bar:"foo"}],[{bar:"foo"},{foo:"bar"}]);
//returns an error, since JSON.stringify doesn't work on cyclic data:
let cyclicData = {};
cyclicData.self = cyclicData;
let h = makeFunction([cyclicData],["foo"]);
希望您可以帮助我:(
您注意到您对new Function
遇到的痛苦,但是您可以像makeFunction
一样使用function
关键字构建功能。
以下下面的JavaScript函数在下面创建词典闭合。 [1] 我们将使用最后的语法,因为它最接近球拍
function makeFunction (param1, param2, ...) { statement1; statement2; ... }
const makeFunction = function (param1, param2, ...) { statement1; statement2; ... }
const makeFunction = (param1, param2, ...) => { statement1; statement2; ... }
const makeFunction = (param1, param2, ...) => expression
只要我们提供first
和rest
功能,您的球拍程序就可以直接转化为JavaScript。请注意,添加了isEmpty
,以便makeFunction ([], [])
仍然有效
const isEmpty = (xs = []) =>
xs.length === 0
const first = (xs = []) =>
xs [0]
const rest = (xs = []) =>
xs.slice (1)
const makeFunction = (domain = [], image = []) =>
x =>
isEmpty (domain)
? undefined
: x === first (domain)
? first (image)
: makeFunction (rest (domain), rest (image)) (x)
const f =
makeFunction ([ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ])
console.log (f ('a')) // d
console.log (f ('b')) // e
console.log (f ('c')) // f
console.log (f ('x')) // undefined
数组破坏分配和默认参数允许我们看到另一种写作函数的方式
const Empty =
Symbol ()
const isEmpty = ([ x = Empty, ...xs ]) =>
x === Empty
const first = ([ x = Empty, ...xs ]) =>
x
const rest = ([ x = Empty, ...xs ]) =>
xs
,或者我们可以跳过创建中间功能first
和rest
,并直接在makeFunction
const Empty =
Symbol ()
const makeFunction = ([ key = Empty, ...keys ], [ value = Empty, ...values ]) =>
x =>
key === Empty
? undefined
: x === key
? value
: makeFunction (keys, values) (x)
const f =
makeFunction ([ 'a', 'b', 'c' ], [ 'd', 'e', 'f' ])
console.log (f ('a')) // d
console.log (f ('b')) // e
console.log (f ('c')) // f
console.log (f ('x')) // undefined
正如 @user3297291指出的那样,您应该查看 Map
,因为它可以在对数时间中查找键 - 与 makeFunction
[1] 使用箭头(=>
(语法功能也具有词典this
值
您可以返回返回功能的函数,这将为您创建一个闭合。
示例:
makeFunction = (domain, image) => ((element) => (image[domain.findIndex(d => d === element)]))
f = makeFunction([1,2,3,4, 'foo'], [4,3,2,1, 'bar']);
f(1) // 4
f(2) // 3
...
您是否考虑使用JavaScript的Map
?它的get
方法几乎是您要实现的方法:
const makeFunction = (domain = [], image = []) => {
const m = new Map(pairs(domain, image));
return m.get.bind(m);
};
let a = { foo: "bar" };
let f = makeFunction([1,2,3,4,"foo"],[4,3,2,1,"bar"]);
let g = makeFunction([ a ]);
let h = makeFunction([ a ], [ 1 ]);
console.log(f(1));
console.log(g(a));
console.log(h(a));
// This still won't work though:
console.log(h({ foo: "bar" }));
function pairs([x, ...xs], [y, ...ys], ps = []) {
return x && y
? pairs(xs, ys, [...ps, [x, y]])
: ps;
};
然而,它的键仍会"通过参考"检查。如果需要{ foo: "bar" } == { foo: "bar" }
,则必须编写一些自定义平等比较...