来自域和JavaScript中图像数组的构造函数



我遇到了一个非常基本的功能编程任务,我无法在JavaScript中解决:

我正在尝试编写一个(高阶(功能,该功能采用两个数组domainimage并返回一个函数。返回的函数应返回 imagen元素,当给定该域的 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

只要我们提供firstrest功能,您的球拍程序就可以直接转化为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

,或者我们可以跳过创建中间功能firstrest,并直接在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" },则必须编写一些自定义平等比较...

最新更新