Skip to content

Instantly share code, notes, and snippets.

@julestburt
Created December 12, 2019 00:32
Show Gist options
  • Save julestburt/0e4cff111f5a701f587761fc75c998fc to your computer and use it in GitHub Desktop.
Save julestburt/0e4cff111f5a701f587761fc75c998fc to your computer and use it in GitHub Desktop.
Summary of Content and code from PointFree.com Functional Swift Series
//
// Functional.swift
//
import Foundation
import Then
// #1 Functions: Piping |>, Composition >>>
// #2 Side Effects: Effectful Composition >=>
//----------------------------------------------------------
// MARK: Piping
//----------------------------------------------------------
precedencegroup ForwardApplication {
associativity: left
higherThan: AssignmentPrecedence
lowerThan: NilCoalescingPrecedence
}
infix operator |> : ForwardApplication
// normal piping
func |> <A,B>(x:A, f:(A)->B) -> B {
return f(x)
}
// inout piping
func |> <A>(a: inout A, f: (inout A) -> Void) -> Void {
f(&a)
}
//----------------------------------------------------------
// MARK: Compostition
//----------------------------------------------------------
precedencegroup CompositionOrder {
associativity: left
higherThan: ForwardApplication
lowerThan: FunctionArrowPrecedence
}
infix operator >>> : CompositionOrder
// normal composition
func >>> <A,B,C>(f:@escaping (A)->B, g:@escaping (B)->C) -> ((A)->C) {
return { a in
return g(f(a))
}
}
//----------------------------------------------------------
// MARK: Composition with Effects
//----------------------------------------------------------
precedencegroup EffectfulComposition {
associativity: left
higherThan: ForwardApplication
}
infix operator >=>: EffectfulComposition
func >=> <A, B, C>( // Tuples
_ f: @escaping (A) -> (B, [String]),
_ g: @escaping (B) -> (C, [String])) -> (A) -> (C, [String]) {
return { a in
let (b, logs) = f(a)
let (c, moreLogs) = g(b)
return (c, logs + moreLogs)
}
}
func >=> <A, B, C>( //Optionals
_ f: @escaping (A) -> B?,
_ g: @escaping (B) -> C?) -> ((A) -> C?) {
return { a in
guard let b = f(a) else { return nil }
return g(b)
}
}
// Compose optionals
let composedFunc = String.init(utf8String:) >=> URL.init(string:)
func >=> <A, B, C>( //Arrays
_ f: @escaping (A) -> [B],
_ g: @escaping (B) -> [C]) -> ((A) -> [C]) {
return { a in
let bArray = f(a)
guard let cArrary = (bArray.map { b in g(b) }).first else { return [] }
return cArrary
}
}
func >=> <A, B, C>( // Promise
_ f: @escaping (A) -> Promise<B>,
_ g: @escaping (B) -> Promise<C>) -> ((A) -> Promise<C>) {
return { a in
f(a).then { b in
return g(b)
}
}
}
//----------------------------------------------------------
// MARK: Composition of reference types (A)->Void
//----------------------------------------------------------
precedencegroup SingleTypeComposition {
associativity: left
higherThan: ForwardApplication
}
infix operator <>: SingleTypeComposition
func <> <A>(f: @escaping (A) -> A, g: @escaping (A) -> A) -> (A) -> A {
return f >>> g
}
// Value InOut Mutation
func <> <A>(f: @escaping (inout A) -> Void, g: @escaping (inout A) -> Void) -> (inout A) -> Void {
return { a in
f(&a)
g(&a)
}
}
// Reference mutation
func <> <A: AnyObject>(f: @escaping (A) -> Void, g: @escaping (A) -> Void) -> (A) -> Void {
return { a in
f(a)
g(a)
}
}
//----------------------------------------------------------
// MARK: Higher Order Functions
//----------------------------------------------------------
func curry<A, B, C>(_ f: @escaping (A, B) -> C) -> (A) -> (B) -> C {
return { a in { b in f(a, b) } }
}
func curry<A, B, C, D>(_ f: @escaping (A, B, C) -> D) -> (B, C) -> (A) -> D {
return { b, c in { a in f(a, b, c) } }
}
//----------------------------------------------------------
// MARK: KeyPath Getter
//----------------------------------------------------------
prefix operator ^
prefix func ^ <Root, Value>(_ keyPath: KeyPath<Root, Value>) -> (Root) -> Value {
return { root in root[keyPath: keyPath] }
}
//----------------------------------------------------------
// MARK: Freeform & Composable Map, Filter, Reduce
//----------------------------------------------------------
//...
//----------------------------------------------------------
// MARK: Testing area
//----------------------------------------------------------
@objc class Test : NSObject {
struct NumberFormatterConfig {
var numberStyle: NumberFormatter.Style = .none
var roundingMode: NumberFormatter.RoundingMode = .up
var maximumFractionDigits: Int = 0
var formatter: NumberFormatter {
let result = NumberFormatter()
result.numberStyle = self.numberStyle
result.roundingMode = self.roundingMode
result.maximumFractionDigits = self.maximumFractionDigits
return result
}
}
func decimalStyle(_ format: inout NumberFormatterConfig) {
format.numberStyle = .decimal
format.maximumFractionDigits = 2
}
func currencyStyle(_ format: inout NumberFormatterConfig) {
format.numberStyle = .currency
format.roundingMode = .down
}
func wholeStyle(_ format: inout NumberFormatterConfig) {
format.maximumFractionDigits = 0
format.roundingMode = .up
}
@objc func inOutComposed() {
var config = NumberFormatterConfig()
config |> decimalStyle <> currencyStyle
let currency = config.formatter.string(from: 1234.6)
config |> currencyStyle <> wholeStyle
let wholeCurrency = config.formatter.string(from: 1234.6)
print("\(currency ?? "") - \(wholeCurrency ?? "")")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment