javascript - 可以在 Typescript 中输入递归可变参数函数吗?

标签 javascript typescript types functional-programming variadic

我有以下通用函数,我可以从中派生出各种有用的可变参数函数:

const variadic = f => {
  const go = args =>
    Object.defineProperty(
      arg => go(args.concat([arg])),
      "runVariadic",
      {get: function() {return f(args)}, enumerable: true});

  return go([]);
};

const arrFold = alg => zero => xs =>
  xs.reduce((acc, x) => alg(acc) (x), zero);

const comp = f => g => x => f(g(x));
const id = x => x;

const varComp = variadic(arrFold(comp) (id));

const inc = x => x + 1;

const main = varComp(inc) (inc) (inc) (inc) (inc);

console.log(
  main.runVariadic(0)); // 5

这种递归可变接口(interface)允许我维护平面应用程序语法,而不依赖于方法链接。此外,我可以部分应用和组合此类函数。不幸的是,variadic 和派生的 varComp 具有无限类型。我依稀记得在 Haskell 中有一种方法可以输入此类函数,但它需要大量类型机器,即高级语言扩展。在 Typescript 中输入它们有什么技巧吗?

我是 Typescript 新手,所以我什至不知道从哪里开始。

最佳答案

这里需要注意的是,TypeScript 编译器几乎不可能按照您想要的方式推断类型;您可能经常发现自己需要手动指定类型参数,甚至 assert特定功能是通用功能。 TypeScript 不是 Haskell,而且它也没有试图成为(太多)Haskell。

话虽如此,这里有一个可能的输入 variadic :

interface Variadic<T, U> {
  (x: T): Variadic<T, U>
  runVariadic: U,
}

const variadic = <T, U>(f: (args: T[]) => U) => {
  const go = (args: T[]): Variadic<T, U> =>
    Object.defineProperty(
      (arg: T) => go(args.concat([arg])),
      "runVariadic",
      { get: function () { return f(args) }, enumerable: true });

  return go([]);
}

这个想法是 variadic接受一个函数,该函数采用 T 数组并返回 U ,并将其变成 Variadic<T, U> 。一个Variadic<T, U>是一个采用 T 的函数参数并返回 Variadic<T, U> ,它还有一个runVariadic类型属性U .


这是一个简短的测试:

const str = variadic((args: string[]) => args)("hey")("you")("guys").runVariadic; // string[]
console.log(str) // ["hey", "you", "guys"]

我经过这里variadic id函数被注释为获取并返回字符串数组。然后得到Variadic<string, string[]>可以取任意数量的 string争论纷纷,最后是runVariadic编译器将属性推断为 string[] ,如控制台日志所示。


对于您的测试代码,必须进行大量手动输入和断言:

const arrFold = <T, U>(alg: (x: T) => (y: U) => T) => (zero: T) => (xs: U[]) =>
  xs.reduce((acc, x) => alg(acc)(x), zero);
const comp = <T, U>(f: (x: T) => U) => <V>(g: (x: V) => T) => (x: V) => f(g(x));
const id = <T>(x: T) => x;

const varComp = variadic(arrFold(comp)(id)) as
  Variadic<(x: number) => number, (x: number) => number>;

const inc = (x: number) => x + 1;

const main = varComp(inc)(inc)(inc)(inc)(inc);
console.log(
  main.runVariadic(0)); // 5

arrFold 的输入, compid相当简单,但结果类型 varComp编译器推断充满了 unknown s。相反,我断言它是 Variadic<(x: number) => number, (x: number) => number> ,因为我知道我们会经过 inc到它。所以main.runVariadic推断为(x: number) => number) ,看起来也不错。


好的,希望能给您一些指导。祝你好运!

Playground link to code

关于javascript - 可以在 Typescript 中输入递归可变参数函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59821864/

相关文章:

Javascript 过滤整数

javascript - $index 对于所有使用 dir-paginate 的页面都是固定的

javascript - typescript 为keyof不工作分配值

javascript - 如何从 TypeORM 属性装饰器中获取值

java - JPA 在需要类型转换的字段上定义关系

javascript - if-image-height JavaScript 语句

javascript - array.flat() 上的链函数不起作用

typescript - 如何从 "next/app"将自定义类型属性添加到 AppProps 类型?

python - 将 python int 转换为 int16_t 类型

javascript - 为什么 Array.isArray 算法是 ES5 执行类型检查?