在typescript中使用n参数的通用咖喱函数

时间:2016-09-11 02:11:51

标签: typescript generics functional-programming currying

我可以为具有一定数量参数的函数创建一个通用的currying函数。 IE)

function curry2<T1,T2,R>(func:(arg1:T1, arg2:T2) => R, param2: T2):(arg:T1) => R{
    return (param1:T1) => func(param1, param2);
};

但是,我找不到(类型安全)方法来为具有任何个参数的函数实现通用curry函数。在另一种语言中,我将所有我的currying函数(即:curry1,curry2,curry3等)命名为相同的东西(curry),然后让函数重载执行正确执行curry的工作。但是,typescript不允许像这样的函数重载。

在任何地方写curry2 / curry1 / curry3而不是咖喱的单一统一界面并不麻烦,但如果有办法做到这一点我会很高兴知道如何!

3 个答案:

答案 0 :(得分:1)

  

在任何地方写curry2 / curry1 / curry3而不是单一的咖喱统一界面并不麻烦,

您可以进行重载(文档https://basarat.gitbooks.io/typescript/content/docs/types/functions.html

更多

让你入门的东西:

function curry<T1,T2,R>(func:(arg1:T1, arg2:T2) => R, param2: T2):(arg:T1) => R;
function curry<T1,T2,T3,R>(func:(arg1:T1, arg2:T2, arg3: T3) => R, param2: T2):(arg:T1) => R;
function curry(){
    // Implement
    return undefined;
};

答案 1 :(得分:0)

basarat的例子相当不错,但第二次重载似乎不正确。 这是我在为咖喱函数编写类型签名时想出的:

interface curry {
    <T1, T2, R>(func: (p1: T1, p2: T2) => R): (p: T1) => (p: T2) => R;
    <T1, T2, T3, R>(func: (p1: T1, p2: T2, p3: T3) => R): (p: T1) => (p: T2) => (p: T3) => R;
    <T1, T2, T3, T4, R>(func: (p1: T1, p2: T2, p3: T3, p4: T4) => R): (p: T1) => (p: T2) => (p: T3) => (p: T4) => R;
    <T1, T2, T3, T4, T5, R>(func: (p1: T1, p2: T2, p3: T3, p4: T4, p5: T5) => R): (p: T1) => (p: T2) => (p: T3) => (p: T4) => (p: T5) => R;
}

当然,您可以使用更多参数重复它,直到达到安全深度:)

// the actual curry function implementation ommited
var makeCurry: curry = <any> null;

// example function that we would like to curry, with two parameters
var getInfo = (age: number, name: string) => {
    return `${name} is ${age} years old`;
}

// the previous function curried
var getInfoCurried = makeCurry<number, string, string>(getInfo);

var info = getInfoCurried(26)('Gergo');

答案 2 :(得分:-1)

curry.ts:

export interface curry1<T1, R> {
  (): curry1<T1, R>;
  (t1: T1): R;
}

export interface curry2<T1, T2, R> {
  (): curry2<T1, T2, R>;
  (t1: T1): curry1<T2, R>;
  (t1: T1, t2: T2): R;
}

export interface curry3<T1, T2, T3, R> {
  (): curry3<T1, T2, T3, R>;
  (t1: T1): curry2<T2, T3, R>;
  (t1: T1, t2: T2): curry1<T3, R>;
  (t1: T1, t2: T2, t3: T3): R;
}
// etc...

export function curry<T1, R>(fn: (t1: T1) => R): curry1<T1, R>;
export function curry<T1, T2, R>(fn: (t1: T1, t2: T2) => R): curry2<T1, T2, R>;
export function curry<T1, T2, T3, R>(fn: (t1: T1, t2: T2, t3: T3) => R): curry3<T1, T2, T3, R>;
// etc...

export function curry(fn) {
  const f = (fn, length, arr) =>
    (...args) =>
      args.length < length ?
        f(fn, length - args.length, arr.concat(args)) :
        fn(...arr.concat(args));
  return f(fn, fn.length, []);
}

tsc -v = 2.2.2