<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Kelson Ball</title>
    <description>The latest articles on Forem by Kelson Ball (@kelsonball).</description>
    <link>https://forem.com/kelsonball</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F69430%2F286a5db1-cb7f-4d8a-8800-b393740d60a4.png</url>
      <title>Forem: Kelson Ball</title>
      <link>https://forem.com/kelsonball</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/kelsonball"/>
    <language>en</language>
    <item>
      <title>An Example of Partial Function Application in C#</title>
      <dc:creator>Kelson Ball</dc:creator>
      <pubDate>Wed, 04 Dec 2019 03:07:38 +0000</pubDate>
      <link>https://forem.com/kelsonball/an-example-of-partial-function-application-in-c-2bed</link>
      <guid>https://forem.com/kelsonball/an-example-of-partial-function-application-in-c-2bed</guid>
      <description>&lt;p&gt;In a language like F# (the functional language most closely related to C#) a function may be called without all of its required parameters, and it will return a new function that takes the remaining required parameters. Here is an example from &lt;a href="https://fsharpforfunandprofit.com/posts/partial-application/"&gt;Fsharp for Fun and Profit&lt;/a&gt; where the binding &lt;code&gt;addWithConsoleLogger&lt;/code&gt; refers to a partial application of &lt;code&gt;adderWithPluggableLogger&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[F#]

// create an adder that supports a pluggable logging function
let adderWithPluggableLogger logger x y = 
    logger "x" x
    logger "y" y
    let result = x + y
    logger "x+y"  result 
    result 

// create a logging function that writes to the console
let consoleLogger argName argValue = 
    printfn "%s=%A" argName argValue 

//create an adder with the console logger partially applied
let addWithConsoleLogger = adderWithPluggableLogger consoleLogger 
addWithConsoleLogger  1 2 
addWithConsoleLogger  42 99
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is one case where I think the zealous type inference of F# hurts the examples ability to teach, so lets try to write out the example in C#.&lt;/p&gt;

&lt;p&gt;In the simplest case without partial application the two functions might look like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[C#]

int adderWithPluggableLogger (Action&amp;lt;string, int&amp;gt; logger, int x, int y) 
{
    logger("x", x);
    logger("y", y);
    var result = x + y;
    logger("x+y", result);
    return result;
}

void consoleLogger(string argName, int argValue) =&amp;gt; WriteLine($"{argName}={argValue}");
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The trouble arises on the next line of the F# example, where the &lt;code&gt;adderWithPluggableLogger&lt;/code&gt; method is called without all of its parameters, which in C# would produce a compilation error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var addWithConsoleLogger = adderWithPluggableLogger(consoleLogger);
addWithConsoleLogger(1, 2);
addWithConsoleLogger(42, 99);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can get an idea here what we &lt;em&gt;expect&lt;/em&gt; the return type of &lt;code&gt;adderWithPluggableLogger(consoleLogger)&lt;/code&gt; might be if it were to compile and execute - it would be a function that takes two integers and returns their addition, so a &lt;code&gt;Func&amp;lt;int, int, int&amp;gt;&lt;/code&gt; or a &lt;code&gt;delegate int binop(int a, int b);&lt;/code&gt;. I'll use the delegate here for clarity, and update the &lt;code&gt;adderWithPluggableLogger&lt;/code&gt; to return that type.&lt;/p&gt;

&lt;p&gt;In local method syntax,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;delegate int binop(int a, int b);

binop adderWithPluggableLogger(Action&amp;lt;string, int&amp;gt; logger)
{
    int addWithLogger(int x, int y)
    {
        logger("x", x);
        logger("y", y);
        var result = x + y;
        logger("x+y", result);
        return result;
    }

    return addWithLogger;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Or with an anonymous lambda,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;delegate int binop(int a, int b);

binop adderWithPluggableLogger(Action&amp;lt;string, int&amp;gt; logger)
{
    return (int x, int y) =&amp;gt;
    {
        logger("x", x);
        logger("y", y);
        var result = x + y;
        logger("x+y", result);
        return result;
    };
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In both cases, a closure is being created and the returned function holds on to a reference to the passed in logger. With one more tweak to use expression bodied members the example can be brought much closer visually to how a functional developer might describe the signature of the function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// int -&amp;gt; int -&amp;gt; int
delegate int binop(int a, int b);

// (string -&amp;gt; int -&amp;gt; ()) -&amp;gt; int -&amp;gt; int -&amp;gt; int
binop adderWithPluggableLogger(Action&amp;lt;string, int&amp;gt; logger) =&amp;gt; (int x, int y) =&amp;gt; 
{
    // . . .
    return result;
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Because we want the returned type to a binary operation on two integers I've kept the x and y params together, but a more faithful interpretation of the F# example would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Func&amp;lt;int, int&amp;gt; adderWithPluggableLogger(Action&amp;lt;string, int&amp;gt; logger) =&amp;gt; (int x) =&amp;gt; (int y) =&amp;gt; 
{
    // . . .
    return result;
};
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This final rendition results in the creation of an additional closure and is not particularly useful in the example outside of satisfying my inner purist.&lt;/p&gt;

&lt;p&gt;Where this methodology and syntax becomes particularly powerful is when you combine it with map, filter, and fold - which in C# comes in the form of the System.Linq extension methods Select, Where, and Aggregate.&lt;/p&gt;

&lt;p&gt;Lets say we want to explore a course catalog from Washington State University, like wsu.xml from this &lt;a href="http://aiweb.cs.washington.edu/research/projects/xmltk/xmldata/www/repository.html#courses"&gt;example xml repository&lt;/a&gt;. I opened up LinqPad and start with something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var courses = XElement.Load(@"Path\To\wsu.xml").Elements();

Func&amp;lt;T, bool&amp;gt; Not&amp;lt;T&amp;gt;(Func&amp;lt;T, bool&amp;gt; predicate) =&amp;gt; (T value) =&amp;gt; !predicate(value);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This Not function behaves a lot like the &lt;code&gt;adderWithPluggableLogger&lt;/code&gt; above, but in this case it's a generic &lt;code&gt;inverterWithPluggablePredicate&lt;/code&gt; of sorts. After exploring the data a little more I added some more utility functions in this same style.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// for selecting days from a course element
IEnumerable&amp;lt;string&amp;gt; Days(XElement course) =&amp;gt; course.Element("days")?.Value?.Split(",") ?? Enumerable.Empty&amp;lt;string&amp;gt;();

// Check if course occurs on a day
Func&amp;lt;XElement, bool&amp;gt; IsOnDay(string day) =&amp;gt; (XElement course) =&amp;gt; Days(course).Contains(day);

// functions for checking course availability
int LimitOf(XElement course) =&amp;gt; int.Parse(course.Element("limit").Value);
int EnrolledIn(XElement course) =&amp;gt; int.Parse(course.Element("enrolled").Value);
bool IsOpen(XElement course) =&amp;gt; EnrolledIn(course) &amp;lt; LimitOf(course);

// map an element to full course code
string CourseCode(XElement course) =&amp;gt; $"{course.Element("prefix").Value} {course.Element("crs").Value}";

// map an element to its instructor
string Instructor(XElement course) =&amp;gt; course.Element("instructor")?.Value;

// check if a course is by a specific instructor
Func&amp;lt;XElement, bool&amp;gt; IsByInstructor(string instructor) =&amp;gt; (XElement course) =&amp;gt; course.Element("instructor")?.Value == instructor;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;All of these allow me to write a complex query like "all open courses taught by Miller that aren't on a monday" extremely similarly to how I'd say it in English.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;courses
    .Where(IsOpen)
    .Where(IsByInstructor("MILLER"))
    .Where(Not(IsOnDay("M")))
    .Select(CourseCode) 
    .Dump();
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;.Dump()&lt;/code&gt; is a LinqPad method for displaying the results in rich text, which with the linked exmaple data comes out to &lt;/p&gt;

&lt;p&gt;&lt;code&gt;IEnumerable&amp;lt;string&amp;gt; (12 items)&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GEOL 426 &lt;/li&gt;
&lt;li&gt;GEOL 428 &lt;/li&gt;
&lt;li&gt;GEOL 526 &lt;/li&gt;
&lt;li&gt;PSYCH 312 &lt;/li&gt;
&lt;li&gt;PSYCH 401 &lt;/li&gt;
&lt;li&gt;STAT 428 &lt;/li&gt;
&lt;li&gt;T &amp;amp; L 521 &lt;/li&gt;
&lt;li&gt;ZOOL 224 &lt;/li&gt;
&lt;li&gt;ZOOL 225 &lt;/li&gt;
&lt;li&gt;ZOOL 498 &lt;/li&gt;
&lt;li&gt;CH E 432 &lt;/li&gt;
&lt;li&gt;CH E 432 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Posted as part of the 2019 C# Advent&lt;br&gt;
&lt;a href="https://crosscuttingconcerns.com/The-Third-Annual-csharp-Advent"&gt;https://crosscuttingconcerns.com/The-Third-Annual-csharp-Advent&lt;/a&gt;&lt;/p&gt;

</description>
      <category>c</category>
      <category>functional</category>
      <category>advent</category>
    </item>
  </channel>
</rss>
