public static class Disposable {
public static TResult Using<TDisposable,TResult>(
Func<TDisposable> factory,
Func<TDisposable, TResult> map)
where TDisposable : IDisposable
{
using (var disposable = factory()){
return map(disposable);
}
}
}
void Main()
{
var currentTime = EpochTime.AddSeconds(Disposable
.Using(() => new HttpClient(),
client => JsonDocument.Parse(client.GetStringAsync(@"http://worldtimeapi.org/api/timezone/europe/oslo").Result))
.RootElement
.GetProperty("unixtime")
.GetInt64()).ToLocalTime(); //list of time zones available here: http://worldtimeapi.org/api/timezone
currentTime.Dump("CurrentTime");
}
public static DateTime EpochTime => new DateTime(1970, 1, 1);
The Disposable is abstracted away in the helper method called Using accepting a factory function to create a TDisposable that accepts an IDisposable.
We look up the current time using the WorldTimeApi and make use of extracting the UnixTime which is measured from Epoch as the number of seconds elapsed from 1st January 1970.
We make use of System.Text.Json here, which is part of .NET to parse the json retrieved.
Saturday, 9 March 2024
Functional programming - looking up current time and encapsulating usings
I looked at encapsulating Using statements today for functional programming and how to look up the current time with API available on the Internet.
Thursday, 7 March 2024
Currying functions in C#
This article will look into helper methods for currying functions in C#. The definition of Currying consists of splitting up a function with multiple arguments
into multiple functions accepting one argument. But you can also have some of the arguments provided via smaller functions, so be aware also of this alternative.
What is in the name currying? The name has nothing to do with cooking from India, but comes from the mathematician Haskell Brooks Curry (!)
https://en.wikipedia.org/wiki/Haskell_Curry
A reason for introducing support for currying is that you can build complex functions from simpler functions as building blocks. Currying is explained great here:
https://www.c-sharpcorner.com/UploadFile/rmcochran/functional-programming-in-C-Sharp-currying/
We will see in the examples that we can provide multiple arguments at once and the syntax will look a bit special compared to other C# code. Curryings benefits is to allow a more flexible way to call a method. You can store into variables calls to a function providing a subset of argument and use that variable to either specify an intermediate other call or get the final result. Note - The function will be called when ALL arguments are provided ONCE ! This helps a lot of avoiding surprising side effects. Let's first look at a sample set of methods we want to support currying.
f(x,g(y,z)) or f(x,g(y,h(z))) - there more arguments you get there is more variations of number of parameters and methods you can pass in. Here is another example how you can build up a calculation uing simpler methods.
https://en.wikipedia.org/wiki/Haskell_Curry
A reason for introducing support for currying is that you can build complex functions from simpler functions as building blocks. Currying is explained great here:
https://www.c-sharpcorner.com/UploadFile/rmcochran/functional-programming-in-C-Sharp-currying/
We will see in the examples that we can provide multiple arguments at once and the syntax will look a bit special compared to other C# code. Curryings benefits is to allow a more flexible way to call a method. You can store into variables calls to a function providing a subset of argument and use that variable to either specify an intermediate other call or get the final result. Note - The function will be called when ALL arguments are provided ONCE ! This helps a lot of avoiding surprising side effects. Let's first look at a sample set of methods we want to support currying.
int FooFourArgs(string st, float x, int j, int k)
{
Console.WriteLine($"Inside method FooFourArgs. Got parameters: st={st}, x={x}, j={j}, k={k}");
return 42;
}
int FooThreeArgs(string st, float x, int j)
{
Console.WriteLine($"Inside method FooThreeArgs. Got parameters: st={st}, x={x}, j={j}");
return 42;
}
int FooTwoArgs(string st, float x)
{
Console.WriteLine($"Inside method FooTwoArgs. Got parameters: st={st}, x={x}");
return 41;
}
int FooOneArgs(string st)
{
Console.WriteLine($"Inside method FooOneArgs. Got parameters: st={st}");
return 40;
}
We want to call the sample methods above in a more flexible way by splitting the number of arguments we provide.
Let's see the extension methods to call up to four arguments to a function. Note the use of chaining the lambda operator (=>) to provide
the support for currying.
public static class FunctionExtensions
{
public static Func<T1, TResult> Curried<T1, TResult>(this Func<T1, TResult> func)
{
return x1 => func(x1);
}
public static Func<T1, Func<T2, TResult>> Curried<T1, T2, TResult>(this Func<T1, T2, TResult> func)
{
return x1 => x2 => func(x1, x2);
}
public static Func<T1, Func<T2, Func<T3, TResult>>> Curried<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> func)
{
return x1 => x2 => x3 => func(x1, x2, x3);
}
public static Func<T1, Func<T2, Func<T3, Func<T4, TResult>>>> Curried<T1, T2, T3, T4, TResult>(this Func<T1, T2, T3, T4, TResult> func)
{
return x1 => x2 => x3 => x4 => func(x1, x2, x3,x4);
}
}
The following main method shows how to use these curry helper methods:
void Main()
{
var curryOneArgsDelegate = new Func<string, int>((st) => FooOneArgs(st)).Curried();
var curryOneArgsPhaseOne = curryOneArgsDelegate("hello");
var curryTwoArgsDelegate = new Func<string, float, int>((st, x) => FooTwoArgs(st,x)).Curried();
var curryTwoArgsPhaseOne = curryTwoArgsDelegate("hello");
var curryTwoArgsPhaseTwo = curryTwoArgsPhaseOne(3.14f);
var curryThreeArgsDelegate = new Func<string, float, int, int>((st, x, j) => FooThreeArgs(st, x, j)).Curried();
var curryThreeArgsPhaseOne = curryThreeArgsDelegate("hello");
var curryThreeArgsPhaseTwo = curryThreeArgsPhaseOne(3.14f);
var curryThreeArgsPhaseThree = curryThreeArgsPhaseTwo(123);
//Or call currying in a single call passing in two or more parametres
var curryThreeArgsPhaseOneToThree = curryThreeArgsDelegate("hello")(3.14f)(123);
var curryFourArgsDelegate = new Func<string, float, int, int, int>((st, x, j, k) => FooFourArgs(st, x, j, k)).Curried();
var curryFourArgsPhaseOne = curryFourArgsDelegate("hello");
var curryFourArgsNextPhases = curryFourArgsPhaseOne(3.14f)(123)(456); //just pass in the last arguments if they are known at this stage
curryFourArgsDelegate("hello")(3.14f)(123)(456); //you can pass in 1-4 parameters to FooFourArgs method - all in a single call for example or one by one
}
The output we get is this. Note that we only call the methods we defined when all parameters are sent in. The function call which had partial argument list provided did not result into a function call.
Inside method FooOneArgs. Got parameters: st=hello
Inside method FooTwoArgs. Got parameters: st=hello, x=3,14
Inside method FooThreeArgs. Got parameters: st=hello, x=3,14, j=123
Inside method FooThreeArgs. Got parameters: st=hello, x=3,14, j=123
Inside method FooFourArgs. Got parameters: st=hello, x=3,14, j=123, k=456
So from a higher level, currying a function f(x,y,z) means adding support that you could call the function like this:f(x,g(y,z)) or f(x,g(y,h(z))) - there more arguments you get there is more variations of number of parameters and methods you can pass in. Here is another example how you can build up a calculation uing simpler methods.
void Main()
{
Func Area = (x,y) => x*y;
Func CubicArea = (x,y,z) => Area.Curried()(Area(x,y))(z);
CubicArea(3,2,4); //supplying all arguments manully is okay
}
CubicArea expects THREE arguments. The implementation allows us to use the Area function and via currying we can use that method and provide the last third argument avoiding compilation error.
Currying makes your functions allow more flexible ways of being called.
Saturday, 24 February 2024
Using IronPython to execute Python code from .NET
Let's look at some code showing how to execute Python code from .NET using IronPython!
IronPython provides support for Python scripts to run inside .NET and utilizes the Dynamic Language Runtime - DLR.
The DLR together allows the caller to get dynamic typing and dynamic method dispatch, which is central in the dynamic languages such as Python.
IronPython was first released in 2004, some 20 years ago. It has continued to evolve slowly and provides seamless integration into .NET ecosystem for Python developers.
In this article, I will present some simple code that shows how you can run Python code inside a .NET 8 console application.
We will load up some tuples in an array in some simple Python code, using IronPython.
Tuples in Python
Tuples in Python are immutable (such as in C#) and are defined using parentheses and comma-separated. This is the same as in C#, but Python had tuple support over 20 years before C#.
We will have to add one Nuget package, the IronPython package, in a net8.0 application.
HelloIronPythonDemo1.csproj
customers.py
https://docs.python.org/release/1.4/tut/node37.html#SECTION00630000000000000000.
Bear in mind, this is way back in 1996, C# was over 20 years later with its tuple support. If you install IronPython, you get a terminal where you can enter Python code (plus more functionality with .NET) such as shown below, where tuples are created and tuples may be composed or 'packed' and also 'unpacked', which is called deconstructed in .NET tuples. To execute code to retrieve this array of tuples, first create a ScriptEngine and then create a ScriptScope, which we will use to retrieve the Python-declared variable customers. We create a ScriptSource, where we use the ScriptEngine to load up either a string or a file. A dynamic variable will be used to get the array of tuples and we can loop through this array with a foreach loop and output its content.
Program.cs
HelloIronPythonDemo1.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IronPython" Version="3.4.1" />
</ItemGroup>
<ItemGroup>
<None Update="customers.py">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
Consider the following array of tuples in Python :
customers.py
customers = [
('Jenna', 42, 165),
('Thor', 40, 174),
('Christopher', 18, 170),
('Liz', 16, 168),
]
Python code is very compact and you declare variables without specifying type such as in C#, Python uses a simple way of creating variables and while C# got support in C# 7 in 2017, Python has had support for tuples since its early days. In the Python 1.4 version, we find it documented here: https://docs.python.org/release/1.4/tut/node37.html#SECTION00630000000000000000.
Bear in mind, this is way back in 1996, C# was over 20 years later with its tuple support. If you install IronPython, you get a terminal where you can enter Python code (plus more functionality with .NET) such as shown below, where tuples are created and tuples may be composed or 'packed' and also 'unpacked', which is called deconstructed in .NET tuples. To execute code to retrieve this array of tuples, first create a ScriptEngine and then create a ScriptScope, which we will use to retrieve the Python-declared variable customers. We create a ScriptSource, where we use the ScriptEngine to load up either a string or a file. A dynamic variable will be used to get the array of tuples and we can loop through this array with a foreach loop and output its content.
Program.cs
using IronPython.Hosting;
using Microsoft.Scripting.Hosting;
using static System.Console;
IronPythonDemo1.OutputSomeExternallyLoadedTuples();
public class IronPythonDemo1
{
public static void OutputSomeExternallyLoadedTuples()
{
var engine = Python.CreateEngine();
ScriptScope scope = engine.CreateScope();
//ScriptSource source = engine.CreateScriptSourceFromString(tupleStatement);
ScriptSource source = engine.CreateScriptSourceFromFile("customers.py");
source.Execute(scope);
dynamic customers = scope.GetVariable("customers");
foreach (var customer in customers)
{
Console.WriteLine($"(Name = {StringExtensions.FixedLength(customer[0], 20)}, Age = {StringExtensions.FixedLength(customer[1].ToString(), 8)}, Height={StringExtensions.FixedLength(customer[2].ToString(), 8)})");
}
}
}
Documentation for named tuples are available here: https://docs.python.org/3/library/collections.html#collections.namedtuple
Here is sample coding showing script that although it is more verbose, shows more readability of which field is which for a named tuple. In an ordinary tuple, you use indexes to retrieve the nth field (0-based). But with named tuples, you use a field name instead.
from collections import namedtuple
Customer = namedtuple('Customer', ['Name', 'Age', 'Height'])
customers2 = [
Customer(Name = 'Jenna', Age = 42, Height = 165),
Customer(Name = 'Thor', Age = 38, Height = 174),
Customer(Name = 'Christopher', Age = 42, Height = 170),
Customer(Name = 'Liz', Age = 42, Height = 168),
]
for cust in customers2:
print(f"{cust.Name} with a height of {cust.Height}(cm)")
This outputs:
Jenna with a height of 165(cm)
Thor with a height of 174(cm)
Christopher with a height of 170(cm)
Liz with a height of 168(cm)
When your tuple gets many fields, having this readability should reduce bugs. Also, if you add more fields to your tuple, you do not have to fix up indexes in your script. So code is a bit more verbose, but it is also more open for change and readable.
The FixedLength extension method is a simple method to output text to a fixed width.
public static class StringExtensions
{
public static string FixedLength(this string input, int length, char paddingchar = ' ')
{
if (string.IsNullOrWhiteSpace(input))
{
return input;
}
if (input.Length > length)
return input.Substring(0, length);
else
return input.PadRight(length, paddingchar);
}
}
Subscribe to:
Posts (Atom)