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.
Here I’ll explain some solved and unsolved problems that I stumbled upon while working on the project
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
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:
In Python, we are able to capture the output of any function using the
The output generated from the following lines would be captured and displayed wherever
Output widget has been displayed.
with out: display(YouTubeVideo("dQw4w9WgXcQ")) 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
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 f 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:
msg_idfrom here to there as a parameter in the
commfunction of the widget (or any other function that is called between the
execution_requestand the capturing)
getExReqMsgId :: IO Stringfunction that accesses an
IORefof the kernel state and gets us the message ID.
I think the latest is a bit dirtier, but easier to read.
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.
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
Colordata type instead of using strings. (Or using one from an external library)
setFieldso it can be used with wrapper types without using the data constructor every time
setField w Index 3should just work instead of having to use
setField w Index $ Just 3
setFielddone, while ipython sends a final update message when all changes have been made.