Swiftional introduces some functional primitives that complement the Swift standard library.
Created for writing Swift code with a slight touch of functional programming.
1.x.x – Swift 5.8
2.x.x – Swift 5.9
curry
Converts an uncurried function to a curried function.
Example:
(A, B) -> R
becomes
(A) -> (B) -> R
uncurry
Converts a curried function into an uncurried function.
Example:
(A) -> (B) -> R
becomes
(A, B) -> R
partial
Partial application. Applies an argument to a function.
Example:
(A, B) -> R
with applied first argument becomes
(B) -> R
identity
Identity combinator function. Returns the input without changing it.
constant
The constant combinator function. Ignores the function arguments and always returns the provided value.
flip
Flips the arguments of a function.
Example:
(A, B) -> R
becomes
(B, A) -> R
with
It calls the specified closure with the given attribute as its receiver and returns its result.
ignored
Ignores the function return and always returns Void
.
weakify
Weakifying function.
Example:
// Instead of this:
someObject.onActionClosure = otherObject.someFunc // `otherObject` captured by strong reference
// Use operator:
someObject.onActionClosure = weakify(otherObject) { $0.someFunc() } // `otherObject` is weakified, not captured by strong reference
memoize
Memoization function. Memoize wrapper intercepts calls you send to the function and attempts to reply with results from its internal cache. If it fails to find a cached result, it calls the work function and records the result of the computation in memory. Subsequent calls to the function with the same arguments can then be satisfied by fetching the result from memory, avoiding redundant computations. Memoization is one of the oldest and simplest tricks in computer science, trading memory for CPU cycles.
Example:
let memoizedSomeFunc = memoize(f: someFunc(_:))
print(memoizedSomeFunc(2))
print(memoizedSomeFunc(3))
print(memoizedSomeFunc(2)) // result fetched from memory
rmemoize
Standard memoization is not very good at memoizing recursive functions. Here is the recursive memoization function. It is represented as a primitive recursive function, where the memoization is done at each step of the recursion.
Example:
let memoizedFibonacci = rmemoize { fibonacci, n in n < 2 ? 1 : fibonacci(n - 1) + fibonacci(n - 2) }
print(memoizedFibonacci(42))
Bool
-
fold
Case analysis for theBool
type. Applies the provided closures based on the value. -
foldRun
Runs the provided closures based on the content of this value. -
foldEither
Case analysis for theBool
type. Applies the provided closures based on the value and returnEither
.
Optional
fold
Case analysis for theOptional
type. Applies the provided closures based on the content of thisOptional
value.
Applyable
-
apply
Calls the specified closure with theSelf
value as its receiver and returns theSelf
value. -
applied
Calls the specified closure with theSelf
value as its receiver and returns a copy of theSelf
value.
>>>
Composes functions and returns a function that is the result of applying g
to the output of f
.
<<<
Composes functions and returns a function that is the result of applying g
to the output of f
.
|>
Pipe forward. Applies an argument to a function.
Example. This:
let result = h(parameter: g(parameter: f(parameter: a)))
Can also be written as:
let result = a |> f |> g |> h
<|
Pipe backward. Applies an argument to a function.
Example. This:
let result = h(parameter: g(parameter: f(parameter: a)))
Can also be written as:
let result = h <| g <| f <| a
|>>
Applies a function to an argument and returns a callable function.
Example. This:
let result = { a in f(parameter: a) }
Can also be written as:
let result = a |>> f
<<|
Applies a function to an argument and returns a callable function.
Example. This:
let result = { a in f(parameter: a) }
Can also be written as:
let result = f <<| a
~~>
Asynchronous function composition
>=>
Effectful function composition
?>
Weakifying function.
Example:
// Instead of this:
someObject.onActionClosure = otherObject.someFunc // `otherObject` captured by strong reference
// Use operator:
someObject.onActionClosure = otherObject ?> { $0.someFunc() } // `otherObject` is weakified, not captured by strong reference
?>>
Weakifying function.
Example:
// Instead of this:
someObject.onActionClosure = otherObject.someFunc // `otherObject` captured by strong reference
// Use operator:
someObject.onActionClosure = otherObject ?>> { $0.someFunc } // `otherObject` is weakified, not captured by strong reference
Either
The type Either
represents a value of one of these types, but not both: .left(Left)
or .right(Right)
.
The Either
type is shifted to the right by convention.
That is, the .left
constructor is usually used to hold errors or secondary data,
while .right
is used to store a "correct", primary value - one that can be worked on further.
Wordplay: "Right" also means "Correct".
Volodymyr Andriienko, [email protected]
VANavigator is available under the MIT license. See the LICENSE file for more info.