Skip to content

Instantly share code, notes, and snippets.

@daveyostcom
Last active March 17, 2020 23:32
Show Gist options
  • Save daveyostcom/21cc630c3431026db73abd7606a59414 to your computer and use it in GitHub Desktop.
Save daveyostcom/21cc630c3431026db73abd7606a59414 to your computer and use it in GitHub Desktop.
partial function application vs currying
// Consider the heavily-aligned source code as a kind of exploded view to aid understanding.
// C# version: https://gist.github.com/daveyostcom/307aedf294042d0aba596cda9cc480ea
// Swift version: https://gist.github.com/daveyostcom/21cc630c3431026db73abd7606a59414
// Inspired by https://codeblog.jonskeet.uk/2012/01/30/currying-vs-partial-function-application/
class PartialFunctionApplicationVsCurrying {
func main() {
// Call the function directly.
print("\(function(1, true, "3")) – normal call")
// Call via partial application, binding arg by arg.
var partial1 = applyPartial(function, p1: 1)
var partial2 = applyPartial(partial1, p2: true)
var partial3 = applyPartial(partial2, p3: "3")
print("\(partial1( true, "3")) – partial application, binding a1")
print("\(partial2( "3")) – partial application, binding a1,a2")
print("\(partial3( )) – partial application, binding a1,a2,a3")
// Call via partial application, binding a1,a2 then a3.
var partial4 = applyPartial(function, p1: 1, p2: true)
var partial5 = applyPartial(partial2, p3: "3")
print("\(partial4( "3")) – partial application, binding a1,a2 at once")
print("\(partial5( )) – partial application, binding a1,a2,a3")
// Call via currying, arg by arg.
var curried1: (Int) -> (Bool) -> (Character) -> String = curry3(function)
var curried2: (Bool) -> (Character) -> String = curried1(1)
var curried3: (Character) -> String = curried2 (true)
var curried4: String = curried3 ("3")
print("\(curried4) – currying, in three stages")
// Call all stages at once.
var curried5: String = curried1(1)(true)("3")
print("\(curried5) – currying, all at once")
// Or, currying the first two arguments at once.
var curried6: (Int, Bool) -> (Character) -> String = curry2(function)
var curried7: ( Character) -> String = curried6(1, true)
var curried8: String = curried7 ("3")
var curried9: String = curried6(1, true)("3")
print("\(curried8) – currying, in two stages")
print("\(curried9) – currying, all at once")
}
func function(_ a1: Int, _ a2: Bool, _ a3: Character) -> String {
return "Result a1=\(a1) a2=\(a2) a3=\(a3)"
}
func applyPartial<T1, T2, T3, TResult>(_ f: @escaping (T1, T2, T3) -> TResult, p1: T1 ) -> (T2, T3) -> TResult {
return { (a2, a3) in f(p1, a2, a3) }
}
func applyPartial< T2, T3, TResult>(_ f: @escaping ( T2, T3) -> TResult, p2: T2 ) -> ( T3) -> TResult {
return { ( a3) in f( p2, a3) }
}
func applyPartial< T3, TResult>(_ f: @escaping ( T3) -> TResult, p3: T3 ) -> ( ) -> TResult {
return { ( ) in f( p3) }
}
func applyPartial<T1, T2, T3, TResult>(_ f: @escaping (T1, T2, T3) -> TResult, p1: T1, p2: T2) -> ( T3) -> TResult {
return { ( a3) in f(p1, p2, a3) }
}
func curry3<T1, T2, T3, TResult>(_ f: @escaping (T1, T2, T3) -> TResult) -> (T1) -> (T2) -> (T3) -> TResult {
return { a1 in { a2 in { a3 in f(a1, a2, a3) } } }
}
func curry2<T1, T2, T3, TResult>(_ f: @escaping (T1, T2, T3) -> TResult) -> (T1, T2) -> (T3) -> TResult {
return { (a1, a2) in { a3 in f(a1, a2, a3) } }
}
// Output:
// Result a1=1 a2=true a3=3 – normal call
// Result a1=1 a2=true a3=3 – partial application, binding a1
// Result a1=1 a2=true a3=3 – partial application, binding a1,a2
// Result a1=1 a2=true a3=3 – partial application, binding a1,a2,a3
// Result a1=1 a2=true a3=3 – partial application, binding a1,a2 at once
// Result a1=1 a2=true a3=3 – partial application, binding a1,a2,a3
// Result a1=1 a2=true a3=3 – currying, in three stages
// Result a1=1 a2=true a3=3 – currying, all at once
// Result a1=1 a2=true a3=3 – currying, in two stages
// Result a1=1 a2=true a3=3 – currying, all at once
}
PartialFunctionApplicationVsCurrying().main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment