David Davó's GSoC '21 Report


This is David Davó's work product submission for Google Summer of Code 2021 working with IHaskell fixing the widgets library.

View the Project @ GSoC's Site

Fixing IHaskell-Widgets

Show me the code!

The main PR with almost all the commits is #1242: Updating IHaskell-widgets, but you can find every PR I have made to the project before finishing GSoC clicking here.

I want to use it

You can test and play a bit with it and run the sample notebooks using this binder link. Warning: it may take a while to load.

I strongly recommend you to start with the Introduction to Widgets notebook, and then go try the other ones.

If you want to install it on your local machine, you can follow the installation guide at the project’s README.

Technical difficulties

Here I’ll explain some solved and unsolved problems that I stumbled upon while working on the project

The message specification

The purpose of this GSoC was to fix ihaskell-widgets, which wasn’t working properly because the widget messaging specification changed A LOT.

I had to navigate through lots of resources and do some “reverse engineering” using network inspection tools (tcpdump).

Some of these resources have been compiled to MsgSpec.md

The incredible world of dependent types

This library was written using the concept of dependent types. These are types whose definition depends on a value. In IHaskell-widgets, using dependent types allows checking properties of the widgets at compile time, using the powerful Haskell’s type system.

For example, in IHaskell-widgets, the type of a widget consists of an array of fields. Then we can check in setField if the field that we want to set is among the array of fields of the widget at compile time!

But Haskell doesn’t support dependent types (yet), so we use the next best thing: a pattern called Singleton that introduces reflection and reification and allows us to get types that depend on values at runtime.

This was the most complex library I’ve had to learn to use, and it took me a lot of reading blogs and papers. If you want to learn more you can find more info here:

Capturing the output with the Output Widget

In Python, we are able to capture the output of any function using the Output widget.

The output generated from the following lines would be captured and displayed wherever the Output widget has been displayed.

with out:
  for int i in range(10):
    print(i, "Hello World!")

What this code does is that it changes the msg_id attribute to the msg_id of the execution_request. For this to be possible, the output widget has to somehow access parts of the Kernel state to obtain that msg_id.

Now, what about implementing it in Haskell? We could do a simple interface with a custom monad. Or with a function that executes a function while capturing the output, like this:

capture :: OutputWidget -> IO () -> IO ()
capture o f = do
  startCapturing o
  endCapturing o
  where startCapturing = setField o MsgID ???
        endCapturing = setField o MsgID ""

Now, what’s the problem? Haskell is a functional language without side effects, so it’s a bit more difficult than just accessing the msg_id… In conclusion, we have two options:

I think the latest is a bit dirtier, but easier to read.

Making the Controller Widget work

The controller widget is created with empty arrays of Buttons and Axes. When a controller is connected and configured, it passes via comm its new attributes such as its name, mapping, etc. (like every widget modifiable by the frontend does). It also passes an array of Buttons and Axes widgets IDs. The problem is where do these IDs come from. Do we have to create widgets with these IDs? Are these widgets already created and on the kernel state? How do we access the kernel state?

We end with a problem similar to “getting the execution request msg_id”, because we have to access the kernel state, and get a widget given it’s ID… So we either pass some part of the kernel state in the comm function, or we create an getAxis :: String -> IO ControllerAxis function.

Things to do

If you want to continue or contribute to this project, here are some things that are still to be done as of today, 16th of August 2021. Some of them have been discussed at Technical difficulties