The Haskell repl – basic commands

Haskell’s repl can be run use ghci or cabal repl. The repl using : to prefix commands, so for example :? will list the help.

I’m not going to go through all commands, but just the one’s I’ve been using regularly, check out Cabal for the full list of commands and features.

Quitting the repl

Let’s start by looking at how to quitting the repl (gracefully)

Prelude> :q

Writing code

Obviously we want to be able to execute code in the repl, in such cases we write code such as

x = 1 + 2
-- press enter
x
-- press enter

The output from this will obviously be 3.

To handle multi line input we create a block using :{ and :}, for example

:{
data Expr = Lit Integer |
            Div Expr Expr
:}

Don’t forget indention is required!

Loading existing code

In some cases we might want to load existing code into the repl, such a data definitions etc. Let’s say we have a Main.hs then run

:load Main

Display information

Assuming we added the Expr data type, to the repl, we might want to show the definition at some point, just use

:i Expr

Showing the type of an expression

Let’s assume we have something like the following in a module

eval :: Expr -> Integer

We can use the following to return the type (obviously in this instance we should see the above, but this command can ofcourse be executed against types where we want to find the type annotations/decalaractions

:t Expr

Now try

:t print

and you’ll see the following

print :: Show a => a -> IO ()

References

Using GHCi
Cabal User Guide

How to yarn link when the package is not published?

In the previous post we looked at using yarn link to work on development of a package whilst using it within our application (or other package).

There’s a problem. This only works if you’ve previously published the package to an npm compatible repository because when you run yarn in your application, it’ll see the dependency of your package and try to get it from the remote repository.

Note: this in not an issue if the package was published it’s only an issue for unpublished packages.

What we can do is change the dependency from using a version number to essentially use a local path. For example, let’s assume we have the following in our packages.json

"dependencies": {
   "@namespace/package-name": "1.0.0"
}

As stated, running yarn will result in and error no such package available. Changing this line to

"dependencies": {
   "@namespace/package-name": "link:../dev/package-name"
}

In other words, link: followed by the path to our package under development, then all will work, running yarn will no longer fail with the no such package available error.

You also needn’t run the link commands on the package or application to create a symbolic link if you use this syntax, just remember to change it back to the version number once the package is published.

yarn link

Yarn’s link functionality is really useful when developing a package and wanting to use it in your application whilst the package is in development.

Let’s assume you’ve created a package, for the sake of having an example, let’s assume it’s a cool new radio button control. You’ve created it and pushed to npm and all’s great but then you want to make some changes.

You don’t want to make those changes and push them to npm so that you can test them, yes you could take the code from the package etc. or use Yalc.

Or we can use yarn link.

In the package you’re editing, simply run

yarn link

this will result in the following command being available to run in the application using the package

yarn link "@namespace/package-name"

Note: obviously remove the namespace if non is used and replace package-name with the name of the package to link.

After you execute the above command and if you’re using Visual Code’s look at the explorer window, in the node_modules of the application using the package you’ll find the @namespace/package-name with a little symbolic link icon.

If you wish to unlink then, from your application use

yarn unlink "@namespace/package-name"

and from the package itself

yarn ulink

Haskell basics – Modules

Note: I’ve writing these Haskell blog posts whilst learning Haskell, so do not take them as expert guidance. I will amend the post(s) as I learn more.

Before we begin, let’s use cabal init to create a starter project, then we’ll add our code to this project as part of this post. This will create a Main.hs with the classic “Hello World” type of sample along with the Setup.hs and the .cabal file.

Modules

Apart from the simplest applications we would probably want to package functions, types etc. into modules. Modules exist in most languages, such as those in F#, TypeScript or similar to namespaces in C# & Java. In Haskell each module is stored within it’s own file and the file begins with the following declaration

module ModuleName where

Note: module names should be in PascalCase.

Obviously replacing the ModuleName with your module name and, similar to Java, the ModuleName should be made up of the path to the module file, ending with the module name. For example let’s assume we’re going to create a Calculator module and our application folder is HaskellBasics, let’s assume we’ve created a Modules folder off of this and within that a Calculator.hs file, hence the ModuleName should look like this

module Modules.Calculator where

We need to add the module to the .cabal build file using the other-modules key, for example

executable HaskellBasics
  main-is:             Main.hs
  other-modules:       Modules.Calculator

Note: We don’t include the file extension for the Calculator module.

If we add more modules then we simply add as comma separated values in the other-modules field in the .cabal file, i.e.

  other-modules: Modules.Calculator, Modules.Output

To import modules into our Main.hs we use the import keyword, like this (we’re importing two modules here).

import Modules.Output
import Modules.Calculator

There’s a lot more we can do in terms of importing modules, for example importing only some functions, like this

import Modules.Calculator (add, sub)

We can also import all function except for some, essentially hiding the module functions, like this

import Modules.Calculator hiding (sub)

The ability to specify the functions available and those not available is useful to help with name clashes etc. Another way to handle such name clashes is to use the module qualified names, for example

main = print (Modules.Calculator.add 10 6)

We can also enforce qualified module names for each function within a module be importing out module like this

import qualified Modules.Calculator

and hence all uses of the functions within this module must be fully qualified.

This can end up requiring a lot more verbosity than we really want, so we can import a qualified module and alias it like this

import qualified Modules.Calculator as C

meaning we can use the function like this

main = print (C.add 10 6)

Note: The alias for the module name must start with a capital letter.

Setting up a Haskel development environment on Windows 10

I wanted to try out Haskell on Windows 10 and figured I’d probably use Visual Code for writing code, here’s the steps to get everything installed and configured.

The simplest way to get everything installed seems to be using chocolatey, see Getting Started.

  1. Install chocolatey
  2. Run Powershell in admin mode and then run choco install haskell-dev
  3. Finally, from Powershell run refreshenv

If all of these steps worked, then just run ghc from the Powershell or a command prompt and you should see some output from ghc.

Let’s now set-up Visual Code (I’ll assume you’ve already got Visual Code installed). There’s a few plugins/extensions for Visual Code for use with Haskell. From Visual Code extensions option…

  • Add Haskell syntax highlighter
  • Also add Haskell-linter
  • To configure the linter, from Visual Code select, File | Preferences | Settings, switch to the code view and add the following
    "haskell.hlint.executablePath": "C:\\ProgramData\\chocolatey\\lib\\ghc\\tools\\ghc-8.10.1\\bin\\ghc.exe"
    

    Chocolatey installs the files into C:\ProgramData\chocolatey\lib, however if you’ve installed ghc by some other means of within another folder then replace the folder with your location.

Finally, let’s write a Haskell “Hello World”. Within Visual Code create the file HelloWorld.hs and add the following code

main = putStrLn "Hello, world!"

Open the Visual Code integrated terminal or open your preferred terminal/shell and from the folder that you saved your HelloWorld.hs file, run

ghc HelloWorld.hs

If all goes to plan you’ll compile the Haskell file to a HelloWorld.exe and you’re done for now.

Websockets and Kestrel

In my post Websockets with Fleck we looked at using Fleck to create a websocket based server, let’s not turn our attention to integrating websockets with an ASP.NET core application using Kestrel.

This is NOT meant to implement anything near as complete as the Fleck library, but is just an example of how we might implement websockets in a Kestrel application and we’re going to try to emulate the code we had for that Fleck example.

  • Create an ASP.NET Core Web Application
  • Select the Empty template

Let’s clean out the Properties | launchSettings.json by remove the iisExpression and IIS Express profile, so mine looks like this

{
  "profiles": {
    "YOUR_APP_NAME": {
      "commandName": "Project",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Obviously keep your application name in the YOUR_APP_NAME string.

Now in Program.cs we’ll add code to allow us to use the 8181 port, so the CreateHostBuilder method should now look like this

public static IHostBuilder CreateHostBuilder(string[] args) =>
  Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
      webBuilder.UseStartup<Startup>();
      webBuilder.UseUrls("http://*:8181");
    });

Delete everything within the Startup.cs’s Configure method and replace with

app.UseWebSockets();

this adds the websocket middleware.

We’re actually going to then create our own middleware to handle web socket requests, so
let’s create the file WebSocketManagerMiddleware.cs. Here’s the code…

public class WebSocketManagerMiddleware
{
  private readonly RequestDelegate _next;
  private readonly WebSocketConnection _connection;

  public WebSocketManagerMiddleware(
    RequestDelegate next, 
    WebSocketConnection connection)
  {
    _next = next;
    _connection = connection;
  }

  public async Task InvokeAsync(HttpContext context)
  {
    if (context.WebSockets.IsWebSocketRequest)
    {
      var socket = await context.WebSockets.AcceptWebSocketAsync();

      _connection.OnOpen(socket);

      await Receive(socket, (result, buffer) =>
      {
        switch (result.MessageType)
        {
          case WebSocketMessageType.Text:
            var s = Encoding.UTF8.GetString(buffer);
            _connection.OnMessage(socket, s.Substring(0, Math.Max(0, s.IndexOf('\0'))));
            break;
          case WebSocketMessageType.Binary:
            _connection.OnBinary(socket, buffer);
            break;
          case WebSocketMessageType.Close:
            _connection.OnClose(socket);
            break;
        }
      });
    }
    await _next(context);
  }

  private async Task Receive(
    WebSocket socket, 
    Action<WebSocketReceiveResult, 
    byte[]> handler)
  {
    var buffer = new byte[1024];

    while (socket.State == WebSocketState.Open)
    {
      var result = await socket.ReceiveAsync(buffer: 
        new ArraySegment<byte>(buffer),
        cancellationToken: CancellationToken.None);

      handler(result, buffer);
    }
  }
}

Middleware expects an Invoke or InvokeAsync method that returns a Task. In our example, we firstly ensure this is a websocket request before accepting the request. In this example we pass in a WebSocketConnection instance (we’ll have a look at that next), but basically this middleware intercepts the websockets and then calls the WebSocketConnection class in a manner similar to the way our Fleck server was implemented, i.e. using OnOpen, OnClose, OnMessage and OnBinary calls.

At the end of the code we pass the context through to the next piece of middleware in the pipeline.

The reason we have a WebSocketConnection class is to just give us an abstraction for creating our actual application websocket code.

Add the file WebScocketConnection.cs, this is going to expose OnOpen, OnClose etc. extension points as well as a SendAsync method for sending data to the connected client, here’s the code

public class WebSocketConnection
{
  public void Start(Action<WebSocketConnection> connection)
  {
    connection(this);
  }

  public Action<WebSocket> OnOpen { get; set; } = 
    webSocket => { };
  public Action<WebSocket> OnClose { get; set; } = 
    webSocket => { };
  public Action<WebSocket, string> OnMessage { get; set; } = 
    (webSocket, message) => { };
  public Action<WebSocket, byte[]> OnBinary { get; set; } = 
    (webSocket, bytes) => { };

  public async Task SendAsync(WebSocket socket, string message)
  {
    if (socket.State == WebSocketState.Open)
    {
      await socket.SendAsync(
        new ArraySegment<byte>(Encoding.ASCII.GetBytes(message),
          0,
          message.Length),
        WebSocketMessageType.Text,
        true,
        CancellationToken.None);
      }
    }
  }
}

Finally let’s return to Startup.cs and the Configure method, here’s the full code

var websocketServer = new WebSocketConnection();
websocketServer.Start(connection =>
{
  connection.OnOpen = socket => Console.WriteLine("OnOpen");
  connection.OnClose = socket => Console.WriteLine("OnClose");
  connection.OnMessage = async (socket, message) =>
  {
    Console.WriteLine($"OnMessage {message}");
    await connection.SendAsync(socket, $"Echo: {message}");
  };
  connection.OnBinary = (socket, bytes) => 
    Console.WriteLine($"OnBinary {Encoding.UTF8.GetString(bytes)}");
});

app.UseWebSockets();
app.UseMiddleware<WebSocketManagerMiddleware>(websocketServer);

References

WebSockets support in ASP.NET Core
Write custom ASP.NET Core middleware

.NET Channels

This post is based upon a Channel9 video with Stephen Toub, I recommend you go and watch it (see references) if you’re interested in threadsafe producer/consumer mechanisms.

This is the namespace you want to be looking at

using System.Threading.Channels;

There are two types of channel, bounded and unbounded.

Bounded channels have a fixed size. In this example the queue within the channel will only allow a maximum of 10 items, meaning if we try to write more than the 10 items, the write method would block until an item is removed/read from the queue

var c = Channel.CreateBounded<int>(10);

So from this, we can tell that unbounded means the queue within the channel in unlimited in size. We create an unbounded channel like this

var c = Channel.CreateUnbounded<int>();

When we want to add items to the channel we use code such as the following, obviously if the queue has reached a limit (bounded) then this will block

c.Writer.TryWrite(123);

To read a value from the channel (if one exists) we use

await c.Reader.ReadAsync()

References

Working with Channels in .NET
An Introduction to System.Threading.Channels

Websockets with Fleck

I’m going to create a .NET core console application to demonstrate using Fleck.

So create yourself a project and add the Fleck nuget package or simply add the Fleck nuget package to an existing project.

Creating a websocket server

To begin with, we simply create a websocket server, supplying the “location”, i.e.

var websocketServer = new WebSocketServer("ws://0.0.0.0:8181");

Don’t forget the using Fleck; line at the start of your code

In this example we’re using 0.0.0.0 (the non-routable meta-address) along with the port 8181 and ofcourse we prefix this with the ws protocol.

Interacting with clients

Next up we’ll want to start the server and intercept various events/messages. Fleck uses a callback function/delegate style, so we simply supply our functions for each of the connection methods that we wish to intercept, for example

websocketServer.Start(connection =>
{
  connection.OnOpen = () => 
    Console.WriteLine("OnOpen");
  connection.OnClose = () => 
    Console.WriteLine("OnClose");
  connection.OnMessage = message => 
    Console.WriteLine($"OnMessage {message}");
  connection.OnBinary = bytes => 
    Console.WriteLine($"OnBinary {Encoding.UTF8.GetString(bytes)}");
  connection.OnError = exception => 
    Console.WriteLine($"OnError {exception.Message}");
  connection.OnPing = bytes => 
    Console.WriteLine("OnPing");
  connection.OnPong = bytes => 
    Console.WriteLine("OnPong");
});

Note: if we’re handling different state for different connections to the same url, it’s our responsibility to create our own form “session state”.

In this example, we’ve listed all the OnXXX actions that we can intercept.

Obviously OnOpen occurs when a new client connects to the server (on ws://0.0.0.0:8181) and OnClose occurs if the client closes the connection.

OnMessage is called when string messages are sent over the websocket, whereas OnBinary is, ofcourse, the binary equivalent (in the example above we’re assuming the bytes represent a string, obviously change this if you’re sending raw byte data).

OnError is called with an Exception for instances where exceptions occur (as you’ll have surmised).

OnPing is used when being pinged and like wise OnPong is used when receiving a pong – ping and pong are used as ways to, in essence, check if the client or server are still running. If supported, a server might send a ping to the connected clients then mark the clients as stopped (and hence dispose of any connections) if the server does not receive a pong within a specified timeout period. Obviously one of the biggest problems for any server that is maintaining some form of state is at what point they can assume the client is no longer around. Obviously if the client closes the connection the server can handle this, but what about if they just disconnect – this is where ping and pong come into play.

Obviously we also need to be able to send data to the client, hence we use the connection’s Send method. For example let’s change the OnMessage delegate to send an “Echo” of the message back to the client

connection.OnMessage = message =>
{
  Console.WriteLine($"OnMessage {message}");
  connection.Send($"Echo: {message}");
};

Writing a client to test our server

Let’s now create a simple console app to test our server code. This will use the System.Net.WebSockets ClientWebSocket class.

We will need to actually specify a network address for the client, so we’ll use the loopback 127.0.0.1.

Below are the contents of our client console application’s Main method

var websocketClient = new ClientWebSocket();
var cancellationToken = new CancellationTokenSource();

var connection = websocketClient.ConnectAsync(
  new Uri("ws://127.0.0.1:8181"), 
  cancellationToken.Token);

connection.ContinueWith(async tsk =>
{
  // sends a string/text message causes OnMessage to be called
  await websocketClient.SendAsync(
    new ArraySegment<byte>(Encoding.UTF8.GetBytes("Hello World")),
    WebSocketMessageType.Text,
    true,
    cancellationToken.Token);

  // receives a string/text from the server
  var buffer = new byte[128];
  await websocketClient.ReceiveAsync(
    new ArraySegment<byte>(buffer), cancellationToken.Token);
  Console.WriteLine(Encoding.UTF8.GetString(buffer));

  // sends a string/text message causes OnBinary to be called
  await websocketClient.SendAsync(
    new ArraySegment<byte>(Encoding.UTF8.GetBytes("Hello World")),
    WebSocketMessageType.Binary,
    true,
    cancellationToken.Token);
  });

  Console.WriteLine("Press <enter> to exit");
  Console.Read();

  // close the connection nicely
  websocketClient.CloseAsync(
     WebSocketCloseStatus.NormalClosure, 
     String.Empty, 
     cancellationToken.Token);

  // this will cause OnError on the server if not closed first
  cancellationToken.Cancel();

Hopefully it’s fairly self explanatory what’s going on – we create a websocket client and a cancellation token (as the methods all required one). We connect to the server and when a connection is established we send and receive data (strings and then binary). Eventually we close the connection.

What and ping and pong?

At this time I don’t have any examples to implement these.

In the case of the ClientWebSocket code, if you leave the client and server running you will periodically see OnPing being called.

I almost forgot…

We can also interact with the connection’s ConnectionInfo property which gives us access to headers, cookies and whether path was specified, i.e. the client url ws://127.0.0.1:8181/somepath will result in ConnectionInfo.Path having the value /somepath.

Here’s an example of the server changes for OnOpen

connection.OnOpen = () =>
{
  Console.WriteLine("OnOpen");
  Console.WriteLine(connection.ConnectionInfo.Path);
};

From what I can tell, each connection is assigned a GUID (found in ConnectionInfo.Id), so when handling multiple different clients with different state requirements we should be able to use this Id.

References

Fleck
Writing WebSocket servers

So _ are called discards

I’ve used the _ (underscore) previously in code – particularly with F# tuples but also C#. It is used to denote a value that is intentionally unused, ignored, discarded.

It seems that the underscore used in such situations has a name (maybe it has the same name in other languages, I’ve not yet checked). It’s called a discard.

Note: With regard to its use in C#, it appeared with C# 7.0.

Let’s have a look at a very simple example

public bool IsNumber => Double.TryParse("123", out _);

This slightly contrived example (the best I could think of quickly) shows how this might be used. In this example we’re not interested in the out value so just use a discard to basically say “this is unused, ignore it”.

Note: The discard doesn’t need a var or type.

Obviously the discard comes in very useful with tuples. I guess, for C#, this became most useful when tuples became a first class language feature.

So for example we might have this code

public (string, string, int) GetPerson()
{
   return ("Scooby", "Doo", 13);
}

// in use we only want the age
var (_, _, age) = GetPerson();

Git tags using the CLI

Creating tags from the command line…

Tags allows us to store a pointer to the repository at a point in time, these are often used for “tagging” a release, but can be used for other purposes.

Note: I will use the tag name v1.0.2 here, obviously this should be replaced with the tagname you’ve used/assigned.

Listing your tags

To see what tags you currently have on a repository run

git tag

this will list all your tags.

Creating your tags

There’s a couple of ways to create your tags, the first is the annotated tag

git tag -a v1.0.2 -m "Version 1.0.2"

Here we use -a (annotate) to create a new tag and -m (add a message). When creating an annotated tag, a message is expected and so you will be prompted to enter a message if you omit -m. Annotated tags store the message (although you could specify an empty message) along with the author of the tag.

Lightweight tags are another way to tag, these tags store no data with the tag (so do not supply -a or -m), for example

git tag v1.0.2

These tags store the commit checksum and whereas you’d tend to use the annotated tag for releases (for example) the lightweight tag might be used simply to label certain commits.

We can also tag by using the commit checksum (the 6a0b83 in the example below), this example uses a lightweight tag

git tag v1.0.2 6a0b83

Pushing your tags

Ofcourse, if we’re working with others we’ll want to share our tags, so if we have a remote to push to then we can push the tag using

git push origin v1.0.2

A simple git push does not push our tags, we need to be explicit or we can use the –tags switch to push all tags.

git push origin --tags

Viewing your tag

We’ve seen that git tag will list the tags but what about showing us the annotation tag data or what the tag actually refers to, this is where we use

git show v1.0.2

If it’s an annotated tag you see the author of the tag and any message along with the last commit within that tag, for the lightweight we simply see the last commit details.

If you’ve signed your tag (see Signing tags below) you’ll also see the GPG signature attached to the tag.

Deleting your tag

To delete a tag just use the following

git tag -d v1.0.2

If you’ve pushed your tag to a remote then use the following after the local delete

git push origin :refs/tags/v1.0.2

Or use

git push origin --delete v1.0.2

Checking out a tag

We can checkout the tag just like any branch using

git checkout v1.0.2

This will put your repository into a “detached HEAD” state. You cannot commit to this tag, or to put it another way, if you commit to this tag your commits will not appear within the tag, instead they’ll only be reachab;e by the commit hash.

If you intention it to make changes to a tag then instead, you need to branch from the tag, i.e.

git checkout -b v1.0.2-branch v1.0.2

Signing tags

Tags can be signed using GPG. The purpose of this functionality is to simply ensure that the tag was created by the person we expected. I’ve not so far needed to sign a tag (or commits for that matter, which can also be signed). However there may be a time when this is useful, so let’s go through it.

To check if you have a key installed type

gpg --list-keys

If no keys exist it’ll create the folders needed for creating keys.

To generate a key key run

gpg --gen-key

This will ask for your “real name” and “email address”, followed by a pass phrase and then this will create your key. Now running gpg –list-keys should list the newly created key.

Next we need to tell git to use our key using the following

git config --global user.signingkey 123456789

where 123456789 is replaced by the pub string associated with your key (see output from gpg –list-keys).

Now we can sign our tags using

git tag -s v1.0.2 -m "Version 1.0.2"

We replace -a with -s, this is now a signed, annotated tag.

We’ll probably want to verify our tag, and we do this using

git tag -v v1.0.2

If you have the public key installed you’ll see information about the key, if not then you’ll get a verification error.