Skip to content

Instantly share code, notes, and snippets.

@daveyostcom
Last active March 17, 2020 23:41
Show Gist options
  • Save daveyostcom/307aedf294042d0aba596cda9cc480ea to your computer and use it in GitHub Desktop.
Save daveyostcom/307aedf294042d0aba596cda9cc480ea to your computer and use it in GitHub Desktop.
partial function application vs currying – exploded view
using System;
namespace PartialFunctionApplicationVsCurrying {
// Consider this heavily-aligned source code as a kind of exploded view to aid understanding.
// Func<> documentation https://docs.microsoft.com/en-us/dotnet/api/system.func-4
// 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 {
// This ordinary function is our starting point.
static string SampleFunction(int a1, bool a2, char a3)
=> string.Format("Result a1={0} a2={1} a3={2}", a1, a2, a3);
internal static void Main(string[] args) {
// Call the function directly. No tricks. ----- print this -----
Func<int, bool, char, string> function = SampleFunction;
Console.WriteLine("{0} – normal call", function(1, true, '3'));
// Call via partial application, binding one arg at a time.
Func< bool, char, string> partial1 = ApplyPartial1__(function, 1);
Func< char, string> partial2 = ApplyPartial12_(partial1, true);
Func< string> partial3 = ApplyPartial123(partial2, '3');
Console.WriteLine("{0} – partial application, binding a1", partial1( true, '3'));
Console.WriteLine("{0} – partial application, binding a1,a2", partial2( '3'));
Console.WriteLine("{0} – partial application, binding a1,a2,a3", partial3( ));
// Call via partial application, binding a1,a2 then a3.
Func< char, string> partial4 = ApplyPartial12(function, 1, true);
Func< string> partial5 = ApplyPartial123(partial4, '3');
Console.WriteLine("{0} – partial application, binding a1,a2 at once", partial4( '3'));
Console.WriteLine("{0} – partial application, binding a1,a2,a3", partial5( ));
// Call via currying, one arg at a time.
Func<int, Func<bool, Func<char, string>>> curried1 = Curry3(function);
Func<bool, Func<char, string>> curried2 = curried1(1) ;
Func<char, string> curried3 = curried2 (true) ;
string curried4 = curried3 ('3');
Console.WriteLine("{0} – currying, stage 1", curried1(1)(true)('3'));
Console.WriteLine("{0} – currying, stage 2", curried2 (true)('3'));
Console.WriteLine("{0} – currying, stage 3", curried3 ('3'));
Console.WriteLine("{0} – currying, complete", curried4);
// Call all stages at once.
string curried5 = curried1(1)(true)('3');
Console.WriteLine("{0} – currying, all at once", curried5);
// Or, currying the first two arguments together.
Func<int, bool, Func<char, string>> curried6 = Curry2(function);
Func<char, string> curried7 = curried6(1, true);
string curried8 = curried7 ('3');
Console.WriteLine("{0} – currying, in two stages", curried8);
// Call all stages at once.
string curried9 = curried6(1, true)('3');
Console.WriteLine("{0} – currying, all at once", curried9);
}
// Partial application
static Func< T2, T3, TResult> // return type
ApplyPartial1__<T1, T2, T3, TResult> // invocation name & types
(Func<T1, T2, T3, TResult> f, T1 a1) // arguments
=> ( p2, p3) // resulting
=> f(a1, p2, p3); // function
static Func< T3, TResult>
ApplyPartial12_< T2, T3, TResult>
(Func< T2, T3, TResult> f, T2 a1)
=> ( p2 )
=> f(a1, p2 );
static Func< TResult>
ApplyPartial123< T3, TResult>
(Func< T3, TResult> f, T3 a1)
=> ( )
=> f(a1 );
// Or, binding the first two arguments at once.
static Func< T3, TResult>
ApplyPartial12 <T1, T2, T3, TResult>
(Func<T1, T2, T3, TResult> f, T1 a1, T2 a2)
=> ( p3)
=> f(a1, a2, p3);
// Currying
static Func<T1, Func<T2, Func<T3, TResult>>>
Curry3 <T1, T2, T3, TResult>
(Func<T1, T2, T3, TResult> f)
=> a1 => a2 => a3
=> f(a1, a2, a3);
static Func<T1, T2, Func<T3, TResult>>
Curry2 <T1, T2, T3, TResult>
(Func<T1, T2, T3, TResult> f)
=> (a1, a2) => a3
=> 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, stage 1
// Result a1=1 a2=True a3=3 – currying, stage 2
// Result a1=1 a2=True a3=3 – currying, stage 3
// Result a1=1 a2=True a3=3 – currying, complete
// 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
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment