Created
December 12, 2019 00:32
-
-
Save julestburt/0e4cff111f5a701f587761fc75c998fc to your computer and use it in GitHub Desktop.
Summary of Content and code from PointFree.com Functional Swift Series
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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