Harps - A new general purpose language
Harps is a new programming language and accompanying framework with the following aims:
- Cross-platform - Build anywhere, run anywhere.
- Built for performance - Harps is used for F(M)ANG scale web servers.
- Memory safe - Garbage collected, you only worry about expressing intent, not managing memory.
- Type safety - Fully type safe with dynamic escape hatches.
- Extensive standard library - no random 3rd party packages to left-pad a number, plus rich IDE and debugger support.
Enough talk, what does it look like?
using System.Text.RegularExpressions;
async Task<(string html, Website website)?> GetPriceHtml(HttpClient httpClient, string url, Website website)
{
var response = await httpClient.GetAsync(url);
if (!response.IsSuccessStatusCode) return null;
return (await response.Content.ReadAsStringAsync(), website);
}
var client = new HttpClient();
client
.DefaultRequestHeaders
.UserAgent
.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36");
var tasks = new[] {
GetPriceHtml(client, "https://coinmarketcap.com/currencies/ethereum/", Website.CoinMarketCap),
GetPriceHtml(client, "https://www.coindesk.com/price/ethereum/", Website.CoinDesk),
GetPriceHtml(client, "https://ethereumprice.org/", Website.EthPrice) };
var defaultRegexOptions = RegexOptions.Singleline | RegexOptions.IgnoreCase;
var result = (await Task.WhenAll(tasks))
.Select(x =>
{
if (!x.HasValue) return null;
// Summon Tony the Pony
var regex = x.Value.website switch
{
Website.CoinDesk => new Regex(@"href=""/price/ethereum/"">.*?\$(?<price>[\d,.]+).*?/div", defaultRegexOptions),
Website.CoinMarketCap => new Regex(@"class=""\s?pricevalue\s?""\s?>\s?<span>\s?\$(?<price>[\d,.]+)<", defaultRegexOptions),
Website.EthPrice => new Regex(@"id=""coin-price"">.*?(?<price>[\d,.]+).*?/div", defaultRegexOptions),
_ => null
};
if (regex == null) return null;
var match = regex.Match(x.Value.html);
if (match.Success && match.Groups["price"].Success)
{
var priceStr = match.Groups["price"].Value;
if (decimal.TryParse(priceStr, out var price)) return (decimal?)price;
}
return null;
}).Where(x => x.HasValue);
Console.WriteLine(string.Join(Environment.NewLine, result));
enum Website
{
CoinMarketCap = 0,
CoinDesk = 1,
EthPrice = 2
}
This sample concurrently loads 3 web pages giving the current price of Ethereum in US dollars, parses the HTML and extracts the prices where available.
This shows off many of the features of Harps:
- Many functions in the standard library by default including HTTP clients, Regex, HTTP calls, parsing and many more.
- Simple and easy to read support for concurrency, async and generics.
- Functional concepts like switch expressions, map/filter on sequences, lambdas.
- Null safety, you can opt-in to null safe programming, no more billion dollar mistakes.
- Unicode strings by default, strings in Harps are UTF-16.
Multi-paradigm, multi-language
In fact, Harps is not just one language, it is 2! The following code is also a valid Harps command line program in Harps' functional dialect:
let fibonacci =
Seq.unfold (fun (a, b) -> Some(a + b, (b, a + b))) (0, 1)
let nth = Seq.item 23 fibonacci
printfn "The 24th fibonacci is %A" nth
This finds and prints out the 24th Fibonacci number.
The 2 dialects of Harps can interoperate (though they can't be mixed in the same module/library or 'project' in Harps terminology).
Simple, scalable web servers
Any old language can be used to build a command line program, show us a web server! Gladly, this is a minimal web server in Harps:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Welcome to the register of names");
app.MapGet("/names", async () =>
{
if (!File.Exists("file-cache.txt")) return Array.Empty();
var names = await File.ReadAllLinesAsync("file-cache.txt");
return names;
});
app.MapPost("/name", async (string name) =>
{
await File.AppendAllTextAsync("file-cache.txt", name + "\r\n");
});
app.Run();
This starts a web server locally and has an endpoint that will write and read strings to a flat file store. This is the simplest starting point, Harps supports dependency registration and injection out of the box.
Harps is built for performance, we're in the top 25 TechEmpower benchmarks for single query performance:
Easy packaging and deploy
What good is code if you can't deploy it? Harps comes with a rich CLI which has commands to build targeting multiple flavors of Linux, MacOS and Windows:
$ harps publish -c Release -r linux-x64 --no-self-contained
You can even build a single file executable which contains all of Harps' dependencies:
$ harps publish -c Release -r linux-x64 --sc -p:PublishSingleFile=true
Rich Ecosystem
Harps' package manager, gentu, provides access to over 1,000 packages for all your needs including logging, database connections, UI testing, file parsing, cryptography and many more.
Adding a package from gentu is as simple as calling the Harps CLI:
$ harps add package Bonsai.Harp