Completed
Push — master ( d1fe82...d3deac )
by Amine
11s
created

functions.php ➔ curry()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 10
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 8
nc 5
nop 1
dl 0
loc 10
rs 8.8571
c 0
b 0
f 0
1
<?php namespace Tarsana\Functional;
2
3
/**
4
 * Functions dealing with functions.
5
 * @file
6
 */
7
8
/**
9
 * Returns a curried equivalent of the provided function.
10
 *
11
 * ```php
12
 * $add = F\curry(function($x, $y) {
13
 *     return $x + $y;
14
 * });
15
 *
16
 * $add(1, 2); //=> 3
17
 * $addFive = $add(5); // this is a function
18
 * $addFive(1); //=> 6
19
 *
20
 * $data = [1, 2, 3, 4, 5];
21
 * $slice = F\curry('array_slice');
22
 * $itemsFrom = $slice($data);
23
 * $itemsFrom(2); //=> [3, 4, 5]
24
 * $itemsFrom(1, 2); //=> [2, 3, 4, 5]
25
 * // Notice that optional arguments are ignored !
26
 *
27
 * $polynomial = F\curry(function($a, $b, $c, $x) {
28
 *     return $a * $x * $x + $b * $x + $c;
29
 * });
30
 * $f = $polynomial(0, 2, 1); // 2 * $x + 1
31
 * $f(5); //=> 11
32
 * ```
33
 *
34
 * @signature (* -> a) -> (* -> a)
35
 * @param  callable $fn
36
 * @return callable
37
 */
38
function curry($fn) {
39
    $n = _number_of_args($fn);
40
    switch($n) {
41
        case 0: return $fn;
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
42
        case 1: return _curry_one($fn);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
43
        case 2: return _curry_two($fn);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
44
        case 3: return _curry_three($fn);
0 ignored issues
show
Coding Style introduced by
The case body in a switch statement must start on the line following the statement.

According to the PSR-2, the body of a case statement must start on the line immediately following the case statement.

switch ($expr) {
case "A":
    doSomething(); //right
    break;
case "B":

    doSomethingElse(); //wrong
    break;

}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
Coding Style introduced by
Terminating statement must be on a line by itself

As per the PSR-2 coding standard, the break (or other terminating) statement must be on a line of its own.

switch ($expr) {
     case "A":
         doSomething();
         break; //wrong
     case "B":
         doSomething();
         break; //right
     case "C:":
         doSomething();
         return true; //right
 }

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
45
    }
46
    return _curry_n($fn, $n);
47
}
48
49
/**
50
 * Argument placeholder to use with curried functions.
51
 *
52
 * ```php
53
 * $reduce = F\curry('array_reduce');
54
 * $sum = $reduce(F\__(), F\plus());
55
 * $sum([1, 2, 3, 4], 0); //=> 10
56
 *
57
 * $polynomial = F\curry(function($a, $b, $c, $x) {
58
 *     return $a * $x * $x + $b * $x + $c;
59
 * });
60
 *
61
 * $multiplier = $polynomial(0, F\__(), 0, F\__());
62
 * $triple = $multiplier(3);
63
 * $triple(5); //=> 15
64
 * $multipleOfThree = $multiplier(F\__(), 3);
65
 * $multipleOfThree(4); //=> 12
66
 * ```
67
 *
68
 * @signature * -> Placeholder
69
 * @return Tarsana\Functional\Placeholder
70
 */
71
function __() {
72
    return Placeholder::get();
73
}
74
75
/**
76
 * Apply the provided function to the list of arguments.
77
 *
78
 * ```php
79
 * F\apply('strlen', ['Hello']); //=> 5
80
 * $replace = F\apply('str_replace');
81
 * $replace(['l', 'o', 'Hello']); //=> 'Heooo'
82
 * ```
83
 *
84
 * @signature (*... -> a) -> [*] -> a
85
 * @param  callable $fn
0 ignored issues
show
Bug introduced by
There is no parameter named $fn. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
86
 * @param  array    $args
0 ignored issues
show
Bug introduced by
There is no parameter named $args. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
87
 * @return mixed
88
 */
89
function apply() {
90
    static $apply = false;
91
    $apply = $apply ?: curry(_f('_apply'));
92
    return _apply($apply, func_get_args());
93
}
94
95
/**
96
 * Performs left-to-right function composition.
97
 *
98
 * The leftmost function may have any arity;
99
 * the remaining functions must be unary.
100
 * The result of pipe is **not curried**.
101
 * **Calling pipe() without any argument returns the `identity` function**.
102
 *
103
 * ```php
104
 * $double = function($x) { return 2 * $x; };
105
 * $addThenDouble = F\pipe(F\plus(), $double);
106
 * $addThenDouble(2, 3); //=> 10
107
 * ```
108
 *
109
 * @signature (((a, b, ...) -> o), (o -> p), ..., (y -> z)) -> ((a, b, ...) -> z)
110
 * @param  callable $fns...
0 ignored issues
show
Bug introduced by
There is no parameter named $fns.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
111
 * @return callable
112
 */
113
function pipe() {
114
    $fns = func_get_args();
115
    if(count($fns) < 1)
116
        return identity();
117
    return function () use ($fns) {
118
        $result = _apply(array_shift($fns), func_get_args());
119
        foreach ($fns as $fn) {
120
            $result = $fn($result);
121
        }
122
        return $result;
123
    };
124
}
125
126
/**
127
 * A function that takes one argument and
128
 * returns exactly the given argument.
129
 *
130
 * ```php
131
 * F\identity('Hello'); //=> 'Hello'
132
 * F\identity([1, 2, 3]); //=> [1, 2, 3]
133
 * F\identity(null); //=> null
134
 * ```
135
 *
136
 * @signature * -> *
137
 * @return mixed
138
 */
139
function identity() {
140
    static $identity = false;
141
    $identity = $identity ?: curry(function($value) {
142
        return $value;
143
    });
144
    return _apply($identity, func_get_args());
145
}
146
147
/**
148
 * Returns a function which whenever called will return the specified value.
149
 *
150
 * ```php
151
 * $five = F\give(5);
152
 * $five(); //=> 5
153
 * $null = F\give(null);
154
 * $null(); //=> null
155
 * ```
156
 *
157
 * @signature a -> (* -> a)
158
 * @param  mixed $value
0 ignored issues
show
Bug introduced by
There is no parameter named $value. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
159
 * @return callable
160
 */
161
function give() {
162
    static $give = false;
163
    $give = $give ?: curry(function($value) {
164
        return function() use($value) {
165
            return $value;
166
        };
167
    });
168
    return _apply($give, func_get_args());
169
}
170
171
/**
172
 * Takes many predicates and returns a new predicate that
173
 * returns `true` only if all predicates are satisfied.
174
 *
175
 * If no predicate is given as argument, this function
176
 * will return an always passing predicate.
177
 * ```php
178
 * $betweenOneAndTen = F\all(F\lt(1), F\gt(10));
179
 * $betweenOneAndTen(5); //=> true
180
 * $betweenOneAndTen(0); //=> false
181
 * $alwaysTrue = F\all();
182
 * $alwaysTrue(1); //=> true
183
 * $alwaysTrue(null); //=> true
184
 * ```
185
 *
186
 * @signature ((a -> Boolean), ..., (a -> Boolean)) -> (a -> Boolean)
187
 * @param  callable $predicates...
0 ignored issues
show
Bug introduced by
There is no parameter named $predicates.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
188
 * @return callable
189
 */
190 View Code Duplication
function all() {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
    $predicates = func_get_args();
192
    return _curry_one(function($value) use(&$predicates) {
193
        foreach ($predicates as $predicate) {
194
            if (! $predicate($value))
195
                return false;
196
        }
197
        return true;
198
    });
199
}
200
201
/**
202
 * Takes many predicates and returns a new predicate that
203
 * returns `true` if any of the predicates is satisfied.
204
 *
205
 * If no predicate is given as argument, this function
206
 * will return an always non-passing predicate.
207
 * ```php
208
 * $startsOrEndsWith = function($text) {
209
 *     return F\any(F\startsWith($text), F\endsWith($text));
210
 * };
211
 * $test = $startsOrEndsWith('b');
212
 * $test('bar'); //=> true
213
 * $test('bob'); //=> true
214
 * $test('foo'); //=> false
215
 * $alwaysFlase = F\any();
216
 * $alwaysFlase(1); //=> false
217
 * $alwaysFlase(null); //=> false
218
 * ```
219
 *
220
 * @signature ((a -> Boolean), ..., (a -> Boolean)) -> (a -> Boolean)
221
 * @param  callable $predicates...
0 ignored issues
show
Bug introduced by
There is no parameter named $predicates.... Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
222
 * @return callable
223
 */
224 View Code Duplication
function any() {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
225
    $predicates = func_get_args();
226
    return _curry_one(function($value) use(&$predicates) {
227
        foreach ($predicates as $predicate) {
228
            if ($predicate($value))
229
                return true;
230
        }
231
        return false;
232
    });
233
}
234
235
/**
236
 * Takes a function `f` and returns a function `g` so that if `f` returns
237
 * `x` for some arguments; `g` will return `! x` for the same arguments.
238
 *
239
 * Note that `complement($fn) == pipe($fn, not())`, So the resulting function is not curried !.
240
 * ```php
241
 * $isOdd = function($number) {
242
 *     return 1 == $number % 2;
243
 * };
244
 *
245
 * $isEven = F\complement($isOdd);
246
 *
247
 * $isEven(5); //=> false
248
 * $isEven(8); //=> true
249
 * ```
250
 *
251
 * @signature (* -> ... -> *) -> (* -> ... -> Boolean)
252
 * @param  callable $fn
0 ignored issues
show
Bug introduced by
There is no parameter named $fn. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
253
 * @return callable
254
 */
255
function complement() {
256
    static $complement = false;
257
    $complement = $complement ?: curry(function($fn) {
258
        return function() use($fn) {
259
            return !_apply($fn, func_get_args());
260
        };
261
    });
262
    return _apply($complement, func_get_args());
263
}
264
265
/**
266
 * Takes a function telling if the first argument is less then the second, and return a compare function.
267
 *
268
 * A compare function returns `-1`, `0`, or `1` if the first argument is considered
269
 * to be respectively less than, equal to, or greater than the second.
270
 * ```php
271
 * $users = [
272
 *     ['name' => 'foo', 'age' => 21],
273
 *     ['name' => 'bar', 'age' => 11],
274
 *     ['name' => 'baz', 'age' => 15]
275
 * ];
276
 *
277
 * usort($users, F\comparator(function($a, $b){
278
 *     return $a['age'] < $b['age'];
279
 * }));
280
 *
281
 * F\map(F\get('name'), $users); //=> ['bar', 'baz', 'foo']
282
 * ```
283
 *
284
 * @signature (a -> a -> Boolean) -> (a -> a -> Number)
285
 * @param  callable $fn
0 ignored issues
show
Bug introduced by
There is no parameter named $fn. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
286
 * @return callable
287
 */
288
function comparator() {
289
    static $comparator = false;
290
    $comparator = $comparator ?: curry(function($fn) {
291
        return function($a, $b) use($fn) {
292
            if ($fn($a, $b)) return -1;
293
            if ($fn($b, $a)) return 1;
294
            return 0;
295
        };
296
    });
297
    return _apply($comparator, func_get_args());
298
}
299