{
"metadata": {
"language": "haskell",
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"IHaskell Notebook\n",
"===\n",
"Hello, and welcome to the **IHaskell Notebook**. IHaskell Notebook is similar to an interactive shell along the lines of GHCi. However, it is much more powerful, and provides features such as syntax highlighting, autocompletion, multi-line input cells, integrated documentation, rich output visualization, and more. In this notebook, I'd like to demonstrate many of the awesome features IHaskell provides.\n",
"\n",
"IHaskell is implemented as a language kernel for the [IPython](http://ipython.org) project, which means that although the entire thing is written only in Haskell, we get a beautiful notebook interface practically for free.\n",
"\n",
"We can start with very simple Haskell expressions:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"-- First of all, we can evaluate simple expressions.\n",
"3 + 5\n",
"\"Hello, \" ++ \"World!\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"text": [
"8"
]
},
{
"metadata": {},
"output_type": "display_data",
"text": [
"\"Hello, World!\""
]
}
],
"prompt_number": 1
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As you can see, each input cell get an execution number. The first input cell is labeled `In [1]`. Just like in GHCi, the output of the last executed statement or expression is available via the `it` variable - however, in addition, the output of the $n$th cell is available via the `itN` variable. For example, if we wanted to see what the first cell printed, we can go ahead and output that:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"it1"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"text": [
"\"Hello, World!\""
]
}
],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In addition to simple code cells such as the ones you see, you can also have other types of cells. All of this inline text, for instance, is written using Markdown cells, which support the majority of Github markdown syntax. This lets you embed images and formatting and arbitrary HTML interspersed with your Haskell code. In addition, you can export these notebooks into HTML or even as presentations using `reveal.js`. \n",
"\n",
"Alright, back to code. Let's do something slightly fancier:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"-- Unlike in GHCi, we can have multi-line expressions.\n",
"concat [\n",
" \"Hello\",\n",
" \", \",\n",
" \"World!\"\n",
" ] :: String"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"text": [
"\"Hello, World!\""
]
}
],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In addition to multi-line expressions, IHaskell supports most things that you could put in a standard Haskell file. For example, we can have function bindings without the `let` that GHCi requires. (As long as you group type signatures and their corresponding declarations together, you can use pattern matching and put signatures on your top-level declarations!)"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"thing :: String -> Int -> Int\n",
"thing \"no\" _ = 100\n",
"thing str int = int + length str\n",
"\n",
"thing \"no\" 10\n",
"thing \"ah\" 10"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"text": [
"100"
]
},
{
"metadata": {},
"output_type": "display_data",
"text": [
"12"
]
}
],
"prompt_number": 4
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So far we've just looked at pure functions, but nothing is stopping us from doing IO."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print \"What's going on?\""
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"text": [
"\"What's going on?\""
]
}
],
"prompt_number": 5
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"IHaskell supports most GHC extensions via the `:extension` directive (or any shorthand thereof)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"-- We can disable extensions.\n",
":ext NoEmptyDataDecls\n",
"data Thing"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"`Thing' has no constructors (-XEmptyDataDecls permits this)
In the data declaration for `Thing'"
],
"metadata": {},
"output_type": "display_data",
"text": [
"`Thing' has no constructors (-XEmptyDataDecls permits this)\n",
"In the data declaration for `Thing'"
]
}
],
"prompt_number": 6
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"-- And enable extensions.\n",
":ext EmptyDataDecls\n",
"data Thing"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 7
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Data declarations do pretty much what you expect, and work fine on multiple lines. If a declaration turns out to be not quite what you wanted, you can just go back, edit it, and re-evaluate the code cell."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"-- Various data declarations work fine.\n",
"data One\n",
" = A String\n",
" | B Int\n",
" deriving Show\n",
"\n",
"print [A \"Hello\", B 10]"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"text": [
"[A \"Hello\",B 10]"
]
}
],
"prompt_number": 8
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Although this doesn't hold everywhere, we've tried to keep IHaskell relatively similar to GHCi in terms of naming. So, just like in GHCi, you can inspect types with `:type` (or shorthands):"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"-- We can look at types like in GHCi.\n",
":ty 3 + 3"
],
"language": "python",
"metadata": {},
"outputs": [
{
"html": [
"forall a. Num a => a"
],
"metadata": {},
"output_type": "display_data",
"text": [
"forall a. Num a => a"
]
}
],
"prompt_number": 9
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The same goes for the `:info` command. However, unlike GHCi, which simply prints info, the IHaskell notebook brings up a separate pane."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"-- What is the Integral typeclass?\n",
":info Integral"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data"
}
],
"prompt_number": 10
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you're looking at this notebook after it's been exported to HTML, you won't be able to see this interactive pane. However, it looks approximately like this:\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can use option :no-pager to force the information to appear inline instead, which is useful for including in demonstrations that you intend to share with others.\n",
"We can now write slightly more complicated scripts."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"-- Results are printed as we go, even from a single expression.\n",
"import Control.Monad\n",
"import Control.Concurrent\n",
"\n",
"forM_ [1..5] $ \\x -> do\n",
" print x\n",
" threadDelay $ 200 * 1000"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "display_data",
"text": [
"1\n",
"2\n",
"3\n",
"4\n",
"5"
]
}
],
"prompt_number": 11
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is where the similarities with GHCi end, and the particularly shiny features of IHaskell begin.\n",
"\n",
"Although looking at text outputs is often enough, there are many times where we really want a richer output. Suppose we have a custom data type for color:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"data Color = Red | Green | Blue"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 12
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we were playing around with designing GUI applications, for instance, we might want to actually *see* these colors, instead of just seeing the text \"Red\", \"Green\", and \"Blue\" when we are debugging.\n",
"\n",
"IHaskell lets you define a custom display mechanism for any data type via its `IHaskellDisplay` typeclass. Since you can use IHaskell in console mode as well as notebook mode, you can provide a list of display outputs for any data type, and the frontend will simply choose the best one. Here's how you would implement a very simple display mechanism for this `Color` data type:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import IHaskell.Display\n",
"\n",
"instance IHaskellDisplay Color where\n",
" display color = return $ Display [html code]\n",
" where\n",
" code = concat [\"