IHaskell/ihaskell-display/ihaskell-widgets/Examples/00 Introduction to Widgets.ipynb
2024-10-21 15:32:20 -04:00

1067 lines
26 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# The IPython widgets, now in IHaskell !!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is highly recommended that users new to jupyter/ipython take the *User Interface Tour* from the toolbar above (Help -> User Interface Tour)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> This notebook introduces the [IPython widgets](https://github.com/ipython/ipywidgets), as implemented in [IHaskell](https://github.com/gibiansky/IHaskell). The `Button` widget is also demonstrated as a live action example."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### The Widget Hierarchy\n",
"\n",
"These are all the widgets available from IPython/Jupyter."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Uncategorized Widgets\n",
"\n",
"+ Button\n",
"+ Image*Widget*\n",
"+ Output*Widget*\n",
"\n",
"#### Box Widgets\n",
"\n",
"+ Box\n",
"+ FlexBox\n",
"+ Accordion\n",
"+ Tab*Widget*\n",
"\n",
"#### Boolean Widgets\n",
"\n",
"+ CheckBox\n",
"+ ToggleButton\n",
"\n",
"#### Integer Widgets\n",
"\n",
"+ IntText\n",
"+ BoundedIntText\n",
"+ IntProgress\n",
"+ IntSlider\n",
"+ IntRangeSlider\n",
"\n",
"#### Float Widgets\n",
"\n",
"+ FloatText\n",
"+ BoundedFloatText\n",
"+ FloatProgress\n",
"+ FloatSlider\n",
"+ FloatRangeSlider\n",
"\n",
"#### Selection Widgets\n",
"\n",
"+ Selection\n",
"+ Dropdown\n",
"+ RadioButtons\n",
"+ Select\n",
"+ SelectMultiple\n",
"+ ToggleButtons\n",
"\n",
"#### String Widgets\n",
"\n",
"+ HTML*Widget*\n",
"+ Latex*Widget*\n",
"+ TextArea\n",
"+ Text*Widget*"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Using Widgets"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Necessary Extensions and Imports\n",
"\n",
"All the widgets and related functions are available from a single module, `IHaskell.Display.Widgets`. It is strongly recommended that users use the `OverloadedStrings` extension, as widgets make extensive use of `Text`."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"{-# LANGUAGE OverloadedStrings #-}\n",
"import IHaskell.Display.Widgets"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The module can be imported unqualified. Widgets with common names, such as `Text`, `Image` etc. have a `-Widget` suffix to prevent name collisions."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Widget interface\n",
"\n",
"Each widget has different properties, but the surface level API is the same.\n",
"\n",
"Every widget has:\n",
"\n",
"1. A constructor:\n",
" An `IO <widget>` value/function of the form `mk<widget_name>`.\n",
"2. A set of properties, which can be manipulated using `setField` and `getField`.\n",
"\n",
"The `setField` and `getField` functions have nasty type signatures, but they can be used by just intuitively understanding them."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
"\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
"\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
"\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"\n",
"</style><span class='get-type'>setField :: forall f w. (RElemOf f (WidgetFields w), ToKey f, IHaskellWidget (IPythonWidget w), ToPairs (Attr f)) => IPythonWidget w -> FieldType f -> IO ()</span>"
],
"text/plain": [
"setField :: forall f w. (RElemOf f (WidgetFields w), ToKey f, IHaskellWidget (IPythonWidget w), ToPairs (Attr f)) => IPythonWidget w -> FieldType f -> IO ()"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
":t setField"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `setField` function takes three arguments, the first of which is a typelevel argument:\n",
"\n",
"1. A type level `Field`\n",
"2. A widget\n",
"3. A value for the `Field`"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
"\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
"\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
"\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"\n",
"</style><span class='get-type'>getField :: forall f w. RElemOf f (WidgetFields w) => IPythonWidget w -> IO (FieldType f)</span>"
],
"text/plain": [
"getField :: forall f w. RElemOf f (WidgetFields w) => IPythonWidget w -> IO (FieldType f)"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
":t getField"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `getField` function takes a type-level `Field` and a `Widget` value and returns the value of that `Field` for the `Widget`."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Another utility function is `properties`, which shows all properties of a widget."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
"\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
"\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
"\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"\n",
"</style><span class='get-type'>properties :: forall w. IPythonWidget w -> IO ()</span>"
],
"text/plain": [
"properties :: forall w. IPythonWidget w -> IO ()"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
":t properties"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Displaying Widgets\n",
"\n",
"IHaskell automatically displays anything *displayable* given to it directly."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"\"abc\""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- Showables\n",
"1 + 2\n",
"\"abc\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Widgets can either be displayed this way, or explicitly using the `display` function from `IHaskell.Display`."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
"\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
"\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
"\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"\n",
"</style><span class='get-type'>display :: forall a. IHaskellDisplay a => a -> IO Display</span>"
],
"text/plain": [
"display :: forall a. IHaskellDisplay a => a -> IO Display"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import IHaskell.Display\n",
":t display"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Multiple displays\n",
"\n",
"A widget can be displayed multiple times. All these *views* are representations of a single object, and thus are linked.\n",
"\n",
"When a widget is created, a model representing it is created in the frontend. This model is used by all the views, and any modification to it propagates to all of them."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Closing widgets\n",
"\n",
"Widgets can be closed using the `closeWidget` function."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
"\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
"\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
"\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"\n",
"</style><span class='get-type'>closeWidget :: forall w. IHaskellWidget w => w -> IO ()</span>"
],
"text/plain": [
"closeWidget :: forall w. IHaskellWidget w => w -> IO ()"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
":t closeWidget"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Our first widget: `Button`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's play with buttons as a starting example:\n",
"\n",
"As noted before, all widgets have a constructor of the form `mk<Widget>`. Thus, to create a `Button`, we use `mkButton`."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>/* Styles used for the Hoogle display in the pager */\n",
".hoogle-doc {\n",
"display: block;\n",
"padding-bottom: 1.3em;\n",
"padding-left: 0.4em;\n",
"}\n",
".hoogle-code {\n",
"display: block;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"}\n",
".hoogle-text {\n",
"display: block;\n",
"}\n",
".hoogle-name {\n",
"color: green;\n",
"font-weight: bold;\n",
"}\n",
".hoogle-head {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-sub {\n",
"display: block;\n",
"margin-left: 0.4em;\n",
"}\n",
".hoogle-package {\n",
"font-weight: bold;\n",
"font-style: italic;\n",
"}\n",
".hoogle-module {\n",
"font-weight: bold;\n",
"}\n",
".hoogle-class {\n",
"font-weight: bold;\n",
"}\n",
"\n",
".get-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"display: block;\n",
"white-space: pre-wrap;\n",
"}\n",
".show-type {\n",
"color: green;\n",
"font-weight: bold;\n",
"font-family: monospace;\n",
"margin-left: 1em;\n",
"}\n",
".mono {\n",
"font-family: monospace;\n",
"display: block;\n",
"}\n",
".err-msg {\n",
"color: red;\n",
"font-style: italic;\n",
"font-family: monospace;\n",
"white-space: pre;\n",
"display: block;\n",
"}\n",
"#unshowable {\n",
"color: red;\n",
"font-weight: bold;\n",
"}\n",
".err-msg.in.collapse {\n",
"padding-top: 0.7em;\n",
"}\n",
"\n",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\n",
"}\n",
"\n",
".suggestion-warning { \n",
"font-weight: bold;\n",
"color: rgb(200, 130, 0);\n",
"}\n",
".suggestion-error { \n",
"font-weight: bold;\n",
"color: red;\n",
"}\n",
".suggestion-name {\n",
"font-weight: bold;\n",
"}\n",
"\n",
"</style><span class='get-type'>button :: Button</span>"
],
"text/plain": [
"button :: Button"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"button <- mkButton -- Construct a Button\n",
":t button"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Widgets can be displayed by just entering them into a cell."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "5e8125e2-4d0a-4ce4-902d-aad1922ce61b",
"version_major": 2,
"version_minor": 0
}
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"button -- Display the button"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To view a widget's properties, we use the `properties` function. It also shows the type represented by the `Field`, which generally are not visible in type signatures due to high levels of type-hackery."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"ViewModule ::: Text\n",
"ViewModuleVersion ::: Text\n",
"ModelModule ::: Text\n",
"ModelModuleVersion ::: Text\n",
"ModelName ::: Text\n",
"ViewName ::: Text\n",
"DOMClasses ::: [Text]\n",
"Tabbable ::: Maybe Bool\n",
"Tooltip ::: Maybe Text\n",
"Layout ::: IPythonWidget LayoutType\n",
"DisplayHandler ::: IO ()\n",
"Description ::: Text\n",
"DescriptionAllowHtml ::: Maybe Bool\n",
"Style ::: StyleWidget\n",
"Disabled ::: Bool\n",
"Icon ::: Text\n",
"ButtonStyleField ::: ButtonStyleValue\n",
"ClickHandler ::: IO ()"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- The button widget has many properties.\n",
"properties button"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's try making the button widget wider."
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"import qualified IHaskell.Display.Widgets.Layout as L\n",
"btnLayout <- getField @Layout button\n",
"setField @L.Width btnLayout $ Just \"100%\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There is a lot that can be customized. For example:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"setField @Description button \"Click Me (._.\\\")\"\n",
"setField @ButtonStyleField button SuccessButton\n",
"setField @L.BorderTop btnLayout $ Just \"ridge 2px\"\n",
"setField @L.Padding btnLayout $ Just \"10\"\n",
"setField @L.Height btnLayout $ Just \"7em\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The button widget also provides a click handler. We can make it do anything, except console input. Universally, no widget event can trigger console input."
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "5e8125e2-4d0a-4ce4-902d-aad1922ce61b",
"version_major": 2,
"version_minor": 0
}
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"setField @ClickHandler button $ putStrLn \"fO_o\"\n",
"button -- Displaying again for convenience"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now try clicking the button, and see the output.\n",
"\n",
"> Note: If you display to stdout using Jupyter Lab, it will be displayed in a log entry, not as the cell output.\n",
"\n",
"We can't do console input, though, but you can always use another widget! See the other notebooks with examples for more information"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"setField @ClickHandler button $ getLine >>= putStrLn"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Haskell",
"language": "haskell",
"name": "haskell"
},
"language_info": {
"codemirror_mode": "ihaskell",
"file_extension": ".hs",
"mimetype": "text/x-haskell",
"name": "haskell",
"pygments_lexer": "Haskell",
"version": "9.8.2"
}
},
"nbformat": 4,
"nbformat_minor": 4
}