Javascript 具有扩展参数的无点组合函数

Javascript 具有扩展参数的无点组合函数,javascript,ramda.js,pointfree,Javascript,Ramda.js,Pointfree,我试图弄清楚,当参数应该在curried composition函数中传播时,是否存在编写无点组合函数的模式 i、 e(与拉姆达一起): 如何以无点风格编写加法和乘法 我不确定是否可以轻松地将无点样式和非一元算术结合起来。 首先考虑结果函数和组合函数的类型: // Compose: (B -> C) -> (A -> B) -> A -> C const compose = f => g => x => f(g(x))

我试图弄清楚,当参数应该在curried composition函数中传播时,是否存在编写无点组合函数的模式
i、 e(与拉姆达一起):


如何以无点风格编写
加法和乘法

我不确定是否可以轻松地将无点样式和非一元算术结合起来。 首先考虑结果函数和组合函数的类型:

// Compose:         (B  ->  C) -> (A  ->  B) ->  A  ->  C
const compose = f => g => x => f(g(x))
// Add:              A  ->  A  ->  A
const add = x => y => x + y
// Mul:              A  ->  A  ->  A
const mul = x => y => x * y

// Add1:             A  ->  A
const add1 = add(1)

// Add1AndMul:       A  ->         A  ->  A
//   because:
//     Add1:         A  ->  A
//     Mul:                 A  ->  A  ->  A
const add_1_and_mul = compose(mul)(add1)

// Mul4:             A  ->  A
const mul_4 = add_1_and_mul(3)
const result = mul_4(5) //> 20

Ramda具有
uncurryN
,因此您可以将其包装在
compose
中,并避免对结果函数进行currying

const add_1_and_multiply = R.uncurryN(2, R.compose(R.multiply, R.add(1)))
let result2 = add_1_and_multiply(3, 5) //> 20
// Add1AndMul:          A -> A -> A
const add1_mul = compose(mul)(add1)

要将另一个函数添加到“链”,您需要将其与前一个函数组合

const add_1_and_multiply = R.uncurryN(2, R.compose(R.multiply, R.add(1)))
let result2 = add_1_and_multiply(3, 5) //> 20
// Add1AndMul:          A -> A -> A
const add1_mul = compose(mul)(add1)
这是我们想要的签名

//                      1         2         3
// Add1AndMulAndAdd:    A ->      A ->      A -> A
//  which is:           |         |         |
//      Add1:           A -> A    |         |
//      Mul:                 A -> A -> A    |
//      Add:                           A -> A -> A
所以我们必须在没有任何“分数”的情况下通过A2和A3。 让我们尝试一下简单的构图并进行分析:

let add1_mul_add = compose(add)(add1_mul)
记住撰写的签名:
(E->F)->(D->E)->D->F
! 分步骤进行分析:

  • 我们提供我们的
    add
    函数签名,而不是
    (E->F)

    我们的结论是

     E = A
     F = A -> A
    
     D = A
     E = A -> A
    
  • 我们对
    (D->E)
    add1\u mul

     (D -> E     )
     (A -> A -> A)
    
    我们的结论是

     E = A
     F = A -> A
    
     D = A
     E = A -> A
    
  • 但我们已经看到了一个矛盾! 步骤2中的结论与步骤1中的结论相矛盾:
    E
    不能同时是
    A
    A->A

    因此,我们无法编写
    add
    add1\u mul
    ,我们的
    add1\u mul\u add
    将抛出一个错误

    让我们试着绕过这个问题并修复它,打破我们对无点风格的承诺

    const add1_mul_add = x => compose(add)(add1_mul(x))
    
    我将打破一些规则,将签名与代码结合起来,以说明我的观点:

    x -> (A -> A -> A) -> (x -> A -> A) -> A -> A -> A
                           ||
                           \/
    x -> (A -> A -> A) -> (A -> A) -> A -> A -> A
         (E -> F     ) -> (D -> E) -> D -> F
    
    所以我们得到了正确的签名!如何去掉
    x
    变量以返回无点状态? 我们可以尝试寻找明显的模式,例如。。。我们古老的函数组合

    f(g(x)) => compose(f)(g)
    
    我们在新的
    add1\u mul\u add
    -

    f = compose(add)
    g = add1_mul
    f(g(x)) = compose(add)(add1_mul(x))
    
    我们将其简化为无点,得到了新的
    add1\u mul\u add
    函数:

    const add1_mul_add = compose(compose(add))(add1_mul)
    
    但是,嘿,我们可以减少更多

    const add1_mul_add = compose(compose)(compose)(add)(add1_mul)
    
    在那里我们发现了一些已经存在于haskell的东西,名字是

    我们可以在Javascript中简单地将其定义为:

    const owl = compose(compose)(compose)
    
    但是现在,对于链中的每个新函数,您必须创建一个更高阶的owl操作符

    const owl2 = compose(compose)(owl)
    const add1_mul_add_mul = owl2(mul)(add1_mul_add)
    
    const owl3 = compose(compose)(owl2)
    const add1_mul_add_mul_add = owl3(add)(add1_mul_add_mul)
    
    因此,我真的建议您使用无点风格的一元函数。或使用其他结构,如列表:

    const actions = [ add, mul, add, mul ]
    const values  = [ 1,   2,   3,   4   ]
    const add_mul_add_mul = (...values) => zip(actions, values).reduce((acc, [action, value]) => action(acc, value), 0)
    

    试着用构图来表示乘法(加(1,x,y)
    而不是乘法(y,加(1,x)):
    R.compose(R.multiply,R.add(1))
    @Bergi这正是我在回答中得出的结论。哇,这很有效。。但是它只使用两个函数来组合,如果需要更多的函数来组合相同的模式,则应该嵌套,例如:
    add\u 1\u和\u multiply\u和\u add=R.uncurryN(2,R.compose(R.add,R.uncurryN)(2,R.compose(R.multiply,R.add(1ЮЮ)'))
    ->
    add\u 1\u和\u multiply\u和\u-add(3,5,6)/>26,似乎可以实现一个
    spread\u compose
    函数,该函数可以处理任意数量的函数。该函数只能处理两个函数,因为理论上
    compose
    是一个二进制函数。因此,如果您想在“链”中添加另一个函数,则必须使用已组合的函数组合它。我会相应地更新答案。