2017-10-10 3 views
1

私は引数がカレー構成する機能に広げされなければならないときpointfree構成関数を記述するためのパターンがあるかどうかを把握しようとしている
すなわち(RAMDA付き):Pointfree構成機能

add_1_and_multiply = (add, mul) => R.compose(R.multiply(mul), R.add(1))(add) 
add_1_and_multiply(3, 5) // 20 

add_1_and_multiplyをポイントフリースタイルで書くには?

+0

'multiply(y、add(1、x))'の代わりに 'multiply(add(1、x)、y)'を使用してみてください。 compose(R.multiply、R.add(1)) ' – Bergi

+0

@Bergiこれはまさに私の答えで結論づけたものです。 –

答えて

2

pointfreeスタイルとnon-unaryアリティを簡単に組み合わせることができるかどうかはわかりません。 が結果と構成機能のタイプでなければなりません最初に何を考える:

// 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はそうあなたがcomposeのまわりでそれをラップした関数のカリー化を取り除くことができuncurryNを持っています。

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 

だから何とか我々はそれらのいずれかの "ポイント" のないとを渡す必要があります。 のは、単純な構図を試してみて、それを分析してみましょう:コンの

let add1_mul_add = compose(add)(add1_mul) 

思い出してくれるの署名:(E -> F) -> (D -> E) -> D -> F! はステップでそれを分析:我々は、代わりに(E -> F)

(E -> F ) 
(A -> A -> A) 

の私達のadd関数のシグネチャを供給

  1. 我々は

    E = A 
    F = A -> A 
    
  2. 我々は(D -> E)add1_mul

    に同じことを行うと結論します
    (D -> E ) 
    (A -> A -> A) 
    

    我々は

    D = A 
    E = A -> A 
    

と結論しかし、我々はすでにそこに矛盾を見ることができます! 手順2の結論は、手順1の結論に矛盾します。 Eは、同時にAA -> Aになることはできません。

したがって、addadd1_muladd1_mul_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変数を削除してpointfreeに戻すにはどうすればよいですか? 私たちはあなたの古きよき機能の構成のような、明らかなパターンを探すことができます!

f(g(x)) => compose(f)(g) 

そして、私たちは私たちの新しいadd1_mul_addでこのパターンを見つける -

f = compose(add) 
g = add1_mul 
f(g(x)) = compose(add)(add1_mul(x)) 

そして、我々はそれがpointfreeする削減し、我々は新しいadd1_mul_add機能だ:

const add1_mul_add = compose(compose(add))(add1_mul) 

でもねえを - 私達ができますそれをさらに減らしてください!

const add1_mul_add = compose(compose)(compose)(add)(add1_mul) 

また、haskellには既にThe Owlという名前で存在するものが見つかりました。

我々は単にJavaScriptでそれを定義することができます。

const owl = compose(compose)(compose) 

しかし、今、チェーン内のすべての新機能で、あなたはフクロウのオペレータの上位を作成する必要があります。

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) 

だから私は本当にpointfreeスタイルで単項あなたの機能を有するお勧めします。または、リストのような他の構文を使用してください。

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

wowはちょうど動作しますが、2つの関数を作成するだけで動作します。同じパターンを組み込む必要がある場合は、次のように入れ子にしてください: 'add_1_and_multiply_and_add = R.uncurryN(2、R.compose(R.add、R 'add_and_multiply_and_add(3、5、6)//> 26'のように、 'spread_compose'を実装することが可能です。任意の数の関数に対してジョブを行う関数 – aleclofabbro

+0

理論的に 'compose'はバイナリ関数なので、2つの関数でのみ動作します。だから、 "チェーン"に別の機能を追加したいのであれば、すでに合成された機能でそれを構成する必要があります。私は答えに従って更新します。 –

+0

私は答えを更新しました。 –

関連する問題