我有以下通用函数,我可以从中派生出各种有用的可变参数函数:
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
的输入, comp
和id
相当简单,但结果类型 varComp
编译器推断充满了 unknown
s。相反,我断言它是 Variadic<(x: number) => number, (x: number) => number>
,因为我知道我们会经过 inc
到它。所以main.runVariadic
推断为(x: number) => number)
,看起来也不错。
好的,希望能给您一些指导。祝你好运!
关于javascript - 可以在 Typescript 中输入递归可变参数函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59821864/