IHaskell/notebooks/IHaskell.ipynb
2019-01-01 02:53:14 -05:00

3499 lines
162 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"![](https://camo.githubusercontent.com/f6540337202bb3b0c2545d90de0791c9196f9510/68747470733a2f2f7261772e6769746875622e636f6d2f67696269616e736b792f494861736b656c6c2f6d61737465722f68746d6c2f6c6f676f2d36347836342e706e67)\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 [Jupyter](https://jupyter.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",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"8"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"\"Hello, World!\""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- First of all, we can evaluate simple expressions.\n",
"3 + 5\n",
"\"Hello, \" ++ \"World!\""
]
},
{
"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",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\"Hello, World!\""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"it1"
]
},
{
"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",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\"Hello, World!\""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- Unlike in GHCi, we can have multi-line expressions.\n",
"concat [\n",
" \"Hello\",\n",
" \", \",\n",
" \"World!\"\n",
" ] :: String"
]
},
{
"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",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"100"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"12"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"thing :: String -> Int -> Int\n",
"thing \"no\" _ = 100\n",
"thing str int = int + length str\n",
"\n",
"thing \"no\" 10\n",
"thing \"ah\" 10"
]
},
{
"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",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"\"What's going on?\""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"print \"What's going on?\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"IHaskell supports most GHC extensions via the `:extension` directive (or any shorthand thereof)."
]
},
{
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><span class='err-msg'>&lt;interactive&gt;:1:1: error:<br/> • Thing has no constructors (EmptyDataDecls permits this)<br/> • In the data declaration for Thing</span>"
],
"text/plain": [
"<interactive>:1:1: error:\n",
" • Thing has no constructors (EmptyDataDecls permits this)\n",
" • In the data declaration for Thing"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- We can disable extensions.\n",
":ext NoEmptyDataDecls\n",
"data Thing"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"-- And enable extensions.\n",
":ext EmptyDataDecls\n",
"data Thing"
]
},
{
"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",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[A \"Hello\",B 10]"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- Various data declarations work fine.\n",
"data One\n",
" = A String\n",
" | B Int\n",
" deriving Show\n",
"\n",
"print [A \"Hello\", B 10]"
]
},
{
"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",
"execution_count": 9,
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><span class='get-type'>3 + 3 :: forall a. Num a => a</span>"
],
"text/plain": [
"3 + 3 :: forall a. Num a => a"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- We can look at types like in GHCi.\n",
":ty 3 + 3"
]
},
{
"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",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- What is the Integral typeclass?\n",
":info Integral"
]
},
{
"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 that pops up after this is evaluated. However, you can disable the interactive pager, and instead just show the output below the cell:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"-- Only takes effect on later cells, so stick it in its own cell.\n",
":opt no-pager"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><div style='background: rgb(247, 247, 247);'><form><textarea id='code'>class (Real a, Enum a) => Integral a where\n",
" quot :: a -> a -> a\n",
" rem :: a -> a -> a\n",
" div :: a -> a -> a\n",
" mod :: a -> a -> a\n",
" quotRem :: a -> a -> (a, a)\n",
" divMod :: a -> a -> (a, a)\n",
" toInteger :: a -> Integer\n",
" {-# MINIMAL quotRem, toInteger #-}\n",
" \t-- Defined in GHC.Real\n",
"instance Integral Word -- Defined in GHC.Real\n",
"instance Integral Integer -- Defined in GHC.Real\n",
"instance Integral Int -- Defined in GHC.Real\n",
"</textarea></form></div><script>CodeMirror.fromTextArea(document.getElementById('code'), {mode: 'haskell', readOnly: 'nocursor'});</script>"
],
"text/plain": [
"class (Real a, Enum a) => Integral a where\n",
" quot :: a -> a -> a\n",
" rem :: a -> a -> a\n",
" div :: a -> a -> a\n",
" mod :: a -> a -> a\n",
" quotRem :: a -> a -> (a, a)\n",
" divMod :: a -> a -> (a, a)\n",
" toInteger :: a -> Integer\n",
" {-# MINIMAL quotRem, toInteger #-}\n",
" \t-- Defined in GHC.Real\n",
"instance Integral Word -- Defined in GHC.Real\n",
"instance Integral Integer -- Defined in GHC.Real\n",
"instance Integral Int -- Defined in GHC.Real"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
":info Integral"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now write slightly more complicated scripts."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1\n",
"2\n",
"3\n",
"4\n",
"5"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- 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"
]
},
{
"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",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"data Color = Red | Green | Blue"
]
},
{
"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",
"execution_count": 15,
"metadata": {},
"outputs": [],
"source": [
"import IHaskell.Display\n",
"\n",
"instance IHaskellDisplay Color where\n",
" display color = return $ Display [html code]\n",
" where\n",
" code = concat [\"<div style='font-weight: bold; color:\"\n",
" , css color\n",
" , \"'>Look!</div>\"]\n",
" css Red = \"red\"\n",
" css Blue = \"blue\"\n",
" css Green = \"green\""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Once we define a custom `display :: a -> IO Display` function, we can simply output a `Color`:"
]
},
{
"cell_type": "code",
"execution_count": 16,
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><div style='font-weight: bold; color:red'>Look!</div>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><div style='font-weight: bold; color:green'>Look!</div>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><div style='font-weight: bold; color:blue'>Look!</div>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"Red\n",
"Green\n",
"Blue"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `DisplayData` type has several constructors which let you display your data as plain text, HTML, images (SVG, PNG, JPG), or even as LaTeX code.\n",
"\n",
"In order to ship an extension for IHaskell, simply create a package named `ihaskell-thing` with a module named `IHaskell.Display.Thing`. As long as `ihaskell-thing` is installed, IHaskell will detect and use it automatically.\n",
"\n",
"A number of packages already exist, which we can briefly look at."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `ihaskell-aeson` package adds a display for [Aeson](http://hackage.haskell.org/package/aeson) JSON `Value` types. These are automatically formatted as JSON, rather than as Haskell values:"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"null"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"true"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"{\n",
" \"x\": 3,\n",
" \"y\": 2\n",
"}"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- Aeson JSON data types are displayed nicely.\n",
":ext OverloadedStrings\n",
"\n",
"import Data.Aeson\n",
"\n",
"data Coord = Coord { x :: Double, y :: Double }\n",
"instance ToJSON Coord where\n",
" toJSON (Coord x y) = object [\"x\" .= x, \"y\" .= y]\n",
"\n",
"Null\n",
"Bool True\n",
"toJSON (Coord 3 2)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [],
"source": [
"-- Turn off SVG output\n",
":option no-svg"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `ihaskell-blaze` package lets you play around with HTML straight from within IHaskell using the [Blaze](http://jaspervdj.be/blaze/tutorial.html) library."
]
},
{
"cell_type": "code",
"execution_count": 19,
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><div style=\"color: red\">\n",
" <p>\n",
" This is an example of BlazeMarkup syntax.\n",
" </p>\n",
" <b>\n",
" Hello\n",
" </b>\n",
"</div>\n"
],
"text/plain": [
"<div style=\"color: red\">\n",
" <p>\n",
" This is an example of BlazeMarkup syntax.\n",
" </p>\n",
" <b>\n",
" Hello\n",
" </b>\n",
"</div>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><img src=\"https://www.google.com/images/srpr/logo11w.png\" width=\"70\">\n",
"<img src=\"https://www.google.com/images/srpr/logo11w.png\" width=\"140\">\n",
"<img src=\"https://www.google.com/images/srpr/logo11w.png\" width=\"210\">\n",
"<img src=\"https://www.google.com/images/srpr/logo11w.png\" width=\"280\">\n",
"<img src=\"https://www.google.com/images/srpr/logo11w.png\" width=\"350\">\n"
],
"text/plain": [
"<img src=\"https://www.google.com/images/srpr/logo11w.png\" width=\"70\">\n",
"<img src=\"https://www.google.com/images/srpr/logo11w.png\" width=\"140\">\n",
"<img src=\"https://www.google.com/images/srpr/logo11w.png\" width=\"210\">\n",
"<img src=\"https://www.google.com/images/srpr/logo11w.png\" width=\"280\">\n",
"<img src=\"https://www.google.com/images/srpr/logo11w.png\" width=\"350\">"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- Small bits of HTML generated via Blaze are displayed.\n",
"\n",
"import Prelude hiding (div, id)\n",
"import Text.Blaze.Html4.Strict hiding (map, style)\n",
"import Text.Blaze.Html4.Strict.Attributes\n",
"\n",
"div ! style \"color: red\" $ do\n",
" p \"This is an example of BlazeMarkup syntax.\"\n",
" b \"Hello\"\n",
" \n",
"forM [1..5] $ \\size -> do\n",
" let s = toValue $ size * 70\n",
" img ! src \"https://www.google.com/images/srpr/logo11w.png\" ! width s"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `ihaskell-diagrams` package allows you to experiment with the [diagrams](http://projects.haskell.org/diagrams/) package. It requires the Cairo backend."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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"
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- We can draw diagrams, right in the notebook.\n",
":extension NoMonomorphismRestriction FlexibleContexts TypeFamilies\n",
"import Diagrams.Prelude\n",
"\n",
"-- By Brent Yorgey\n",
"-- Draw a Sierpinski triangle!\n",
"sierpinski 1 = eqTriangle 1\n",
"sierpinski n = s\n",
" ===\n",
" (s ||| s) # centerX\n",
" where s = sierpinski (n-1)\n",
"\n",
"-- The `diagram` function is used to display them in the notebook.\n",
"diagram $ sierpinski 4\n",
" # centerXY\n",
" # fc black\n",
" `atop` square 10\n",
" # fc white"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Just like with Diagrams, `ihaskell-charts` allows you to use the [Chart](https://github.com/timbod7/haskell-chart/wiki) library for plotting from within IHaskell. (You will need to install `cairo` as well, which may be a bit of a hassle.)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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"
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- We can draw small charts in the notebook.\n",
"-- This example is taken from the haskell-chart documentation.\n",
"import Graphics.Rendering.Chart \n",
"import Data.Default.Class\n",
"import Control.Lens\n",
"\n",
"let values = [\n",
" (\"Mexico City\" , 19.2, 0),\n",
" (\"Mumbai\" , 12.9, 10), \n",
" (\"Sydney\" , 4.3, 0),\n",
" (\"London\" , 8.3, 0), \n",
" (\"New York\" , 8.2, 25)]\n",
" \n",
"pitem (s, v, o) = pitem_value .~ v\n",
" $ pitem_label .~ s\n",
" $ pitem_offset .~ o\n",
" $ def \n",
"\n",
"-- Convert to a renderable in order to display it.\n",
"toRenderable \n",
" $ pie_title .~ \"Relative Population\"\n",
" $ pie_plot . pie_data .~ map pitem values\n",
" $ def"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In addition to displaying outputs in a rich format, IHaskell has a bunch of useful features.\n",
"\n",
"For instance, the popular linting tool `hlint` is integrated and turned on by default. Let's write some ugly code, and see what it tells us:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><div class=\"suggestion-name\" style=\"clear:both;\">Redundant $</div><div class=\"suggestion-row\" style=\"float: left;\"><div class=\"suggestion-warning\">Found:</div><div class=\"highlight-code\" id=\"haskell\">f $ 3</div></div><div class=\"suggestion-row\" style=\"float: left;\"><div class=\"suggestion-warning\">Why Not:</div><div class=\"highlight-code\" id=\"haskell\">f 3</div></div><div class=\"suggestion-name\" style=\"clear:both;\">Redundant do</div><div class=\"suggestion-row\" style=\"float: left;\"><div class=\"suggestion-warning\">Found:</div><div class=\"highlight-code\" id=\"haskell\">do return 3</div></div><div class=\"suggestion-row\" style=\"float: left;\"><div class=\"suggestion-warning\">Why Not:</div><div class=\"highlight-code\" id=\"haskell\">return 3</div></div>"
],
"text/plain": [
"Line 1: Redundant $\n",
"Found:\n",
"f $ 3\n",
"Why not:\n",
"f 3Line 1: Redundant do\n",
"Found:\n",
"do return 3\n",
"Why not:\n",
"return 3"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"4"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"3"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- There is also hlint integration enabled by default.\n",
"-- If you write sketchy code, it will tell you:\n",
"f :: Int -> Int\n",
"f x = x + 1\n",
"\n",
"-- Most warnings are orange...\n",
"f $ 3\n",
"\n",
"do\n",
" return 3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you're an experienced Haskeller, though, and don't want `hlint` telling you what to do, you can easily turn it off:"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [],
"source": [
"-- If hlint annoys you, though, you can turn it off.\n",
"-- Note that this only takes effect in the next cell execution.\n",
":opt no-lint"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"4"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- You could similarly use `:opt lint` to turn it back on.\n",
"f $ 3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In addition to `hlint` integration, IHaskell also integrates **Hoogle** for documentation searches. IHaskell provides two directives for searching Hoogle. The first of these, `:document` (or shorthands), looks for exact matches."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><span class='err-msg'>No result: no matching identifiers found.</span>\n"
],
"text/plain": [
"No response available: no matching identifiers found."
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
":doc filterM"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The other provided command is `:hoogle`. This does a normal Hoogle search, and thus lets you use imperfect matching and searching by type signature. This will show you documentation for things that match the desired type signature, as demonstrated below. It automatically formats inline Haskell code and hyperlinks the identifiers to their respective Haddock documentations."
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {},
"metadata": {},
"output_type": "display_data"
},
{
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/base/docs/Prelude.html#v:zip'><s0>zip</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/base/docs/Data-List.html#v:zip'><s0>zip</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/base/docs/GHC-List.html#v:zip'><s0>zip</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/base/docs/GHC-OldList.html#v:zip'><s0>zip</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/hspec/docs/Test-Hspec-Discover.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/Cabal/docs/Distribution-Compat-Prelude-Internal.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/safe/docs/Safe-Exact.html#v:zipExact'><s0>zipExact</s0></a> &#x2237; Partial &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><pre>\n",
"zipExact xs ys =\n",
"| length xs == length ys = zip xs ys\n",
"| otherwise = error \"some message\"\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/base-compat/docs/Prelude-Compat.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/protolude/docs/Protolude.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/numeric-prelude/docs/NumericPrelude.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/numeric-prelude/docs/NumericPrelude-Base.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/rio/docs/RIO.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/rio/docs/RIO-List.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/fay-base/docs/Prelude.html#v:zip'><s0>zip</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/rebase/docs/Rebase-Prelude.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/universe-base/docs/Data-Universe-Helpers.html#v:-43--42--43-'>(<s0>+*+</s0>)</a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'>Slightly unfair 2-way Cartesian product: given two (possibly infinite)\n",
"lists, produce a single list such that whenever <tt>v</tt> and\n",
"<tt>w</tt> have finite indices in the input lists, <tt>(v,w)</tt> has\n",
"finite index in the output list. Lower indices occur as the\n",
"<tt>fst</tt> part of the tuple more frequently, but not exponentially\n",
"so.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/universe-base/docs/Data-Universe-Helpers.html#v:unfairCartesianProduct'><s0>unfairCartesianProduct</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'>Very unfair 2-way Cartesian product: same guarantee as the slightly\n",
"unfair one, except that lower indices may occur as the <tt>fst</tt>\n",
"part of the tuple exponentially more frequently. This mainly exists as\n",
"a specification to test against.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/universum/docs/Universum-List-Reexport.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/llvm-hs-pure/docs/LLVM-Prelude.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/haxl/docs/Haxl-Prelude.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/prelude-compat/docs/Data-List2010.html#v:zip'><s0>zip</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/prelude-compat/docs/Prelude2010.html#v:zip'><s0>zip</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/stack/docs/Stack-Prelude.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/EdisonAPI/docs/Data-Edison-Seq-ListSeq.html#v:zip'><s0>zip</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/LambdaHack/docs/Game-LambdaHack-Common-Prelude.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/LambdaHack/docs/Game-LambdaHack-Common-Prelude.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/mixed-types-num/docs/Numeric-MixedTypes-PreludeHiding.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/intro/docs/Intro.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/relude/docs/Relude-List-Reexport.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/yesod-paginator/docs/Yesod-Paginator-Prelude.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/hledger-web/docs/Hledger-Web-Import.html#v:zip'><s0>zip</s0></a> &#x2237; () &#x21D2; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/ghc/docs/Util.html#v:zipLazy'><s0>zipLazy</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; [(a, b)]</span><div class='hoogle-doc'><a>zipLazy</a> is a kind of <a>zip</a> that is lazy in the second list\n",
"(observe the ~)\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/lifted-async/docs/Control-Concurrent-Async-Lifted.html#v:concurrently'><s0>concurrently</s0></a> &#x2237; MonadBaseControl IO m &#x21D2; m a &#x2192; m b &#x2192; m (a, b)</span><div class='hoogle-doc'>Generalized version of <a>concurrently</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/lifted-async/docs/Control-Concurrent-Async-Lifted-Safe.html#v:concurrently'><s0>concurrently</s0></a> &#x2237; &#x2200; m a b . (MonadBaseControl IO m, Forall (Pure m)) &#x21D2; m a &#x2192; m b &#x2192; m (a, b)</span><div class='hoogle-doc'>Generalized version of <a>concurrently</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/invertible/docs/Control-Invertible-Monoidal.html#v:pairADefault'><s0>pairADefault</s0></a> &#x2237; Applicative f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'>Default '&gt;*&lt; implementation for non-invertible\n",
"<a>Applicative</a>s.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/unliftio/docs/UnliftIO-Async.html#v:concurrently'><s0>concurrently</s0></a> &#x2237; MonadUnliftIO m &#x21D2; m a &#x2192; m b &#x2192; m (a, b)</span><div class='hoogle-doc'>Unlifted <a>concurrently</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/unliftio/docs/UnliftIO-Internals-Async.html#v:concurrently'><s0>concurrently</s0></a> &#x2237; MonadUnliftIO m &#x21D2; m a &#x2192; m b &#x2192; m (a, b)</span><div class='hoogle-doc'>Unlifted <a>concurrently</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/stack/docs/Stack-Prelude.html#v:concurrently'><s0>concurrently</s0></a> &#x2237; MonadUnliftIO m &#x21D2; m a &#x2192; m b &#x2192; m (a, b)</span><div class='hoogle-doc'>Unlifted <a>concurrently</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/yesod-websockets/docs/Yesod-WebSockets.html#v:concurrently'><s0>concurrently</s0></a> &#x2237; MonadUnliftIO m &#x21D2; m a &#x2192; m b &#x2192; m (a, b)</span><div class='hoogle-doc'>Unlifted <a>concurrently</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/EdisonAPI/docs/Data-Edison-Seq.html#v:zip'><s0>zip</s0></a> &#x2237; Sequence s &#x21D2; s a &#x2192; s b &#x2192; s (a, b)</span><div class='hoogle-doc'>Combine two sequences into a sequence of pairs. If the sequences are\n",
"different lengths, the excess elements of the longer sequence is\n",
"discarded.\n",
"\n",
"<pre>\n",
"zip &lt;x0,...,xn-1&gt; &lt;y0,...,ym-1&gt; = &lt;(x0,y0),...,(xj-1,yj-1)&gt;\n",
"where j = min {n,m}\n",
"</pre>\n",
"\n",
"<i>Axioms:</i>\n",
"\n",
"<ul>\n",
"<li><pre>zip xs ys = zipWith (,) xs ys</pre></li>\n",
"</ul>\n",
"\n",
"This function is always <i>unambiguous</i>.\n",
"\n",
"Default running time: <tt>O( min( n1, n2 ) )</tt>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/EdisonCore/docs/Data-Edison-Seq-Defaults.html#v:zipUsingLview'><s0>zipUsingLview</s0></a> &#x2237; Sequence s &#x21D2; s a &#x2192; s b &#x2192; s (a, b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/EdisonCore/docs/Data-Edison-Seq-Defaults.html#v:zipUsingLists'><s0>zipUsingLists</s0></a> &#x2237; Sequence s &#x21D2; s a &#x2192; s b &#x2192; s (a, b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/adjunctions/docs/Data-Functor-Rep.html#v:mzipRep'><s0>mzipRep</s0></a> &#x2237; Representable f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/concurrency/docs/Control-Concurrent-Classy-Async.html#v:concurrently'><s0>concurrently</s0></a> &#x2237; MonadConc m &#x21D2; m a &#x2192; m b &#x2192; m (a, b)</span><div class='hoogle-doc'>Run two <tt>MonadConc</tt> actions concurrently, and return both\n",
"results. If either action throws an exception at any time, then the\n",
"other action is <a>cancel</a>led, and the exception is re-thrown by\n",
"<a>concurrently</a>.\n",
"\n",
"<pre>\n",
"concurrently left right =\n",
"withAsync left $ \\a -&gt;\n",
"withAsync right $ \\b -&gt;\n",
"waitBoth a b\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/contravariant/docs/Data-Functor-Contravariant-Divisible.html#v:divided'><s0>divided</s0></a> &#x2237; Divisible f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'><pre>\n",
"<a>divided</a> = <a>divide</a> <a>id</a>\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/dhall/docs/Dhall.html#v:-62--42--60-'>(<s0>>*<</s0>)</a> &#x2237; Divisible f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'>The <a>RecordInputType</a> divisible (contravariant) functor allows\n",
"you to build an <a>InputType</a> injector for a Dhall record.\n",
"\n",
"For example, let's take the following Haskell data type:\n",
"\n",
"<pre>\n",
"data Project = Project\n",
"{ projectName :: Text\n",
", projectDescription :: Text\n",
", projectStars :: Natural\n",
"}\n",
"</pre>\n",
"\n",
"And assume that we have the following Dhall record that we would like\n",
"to parse as a <tt>Project</tt>:\n",
"\n",
"<pre>\n",
"{ name =\n",
"\"dhall-haskell\"\n",
", description =\n",
"\"A configuration language guaranteed to terminate\"\n",
", stars =\n",
"289\n",
"}\n",
"</pre>\n",
"\n",
"Our injector has type <a>InputType</a> <tt>Project</tt>, but we can't\n",
"build that out of any smaller injectors, as <a>InputType</a>s cannot\n",
"be combined (they are only <a>Contravariant</a>s). However, we can use\n",
"an <tt>InputRecordType</tt> to build an <a>InputType</a> for\n",
"<tt>Project</tt>:\n",
"\n",
"<pre>\n",
"injectProject :: InputType Project\n",
"injectProject =\n",
"inputRecord\n",
"( adapt &gt;$&lt; inputFieldWith \"name\" inject\n",
"&gt;*&lt; inputFieldWith \"description\" inject\n",
"&gt;*&lt; inputFieldWith \"stars\" inject\n",
")\n",
"where\n",
"adapt (Project{..}) = (projectName, (projectDescription, projectStars))\n",
"</pre>\n",
"\n",
"Or, since we are simply using the <a>Inject</a> instance to inject\n",
"each field, we could write\n",
"\n",
"<pre>\n",
"injectProject :: InputType Project\n",
"injectProject =\n",
"inputRecord\n",
"( adapt &gt;$&lt; inputField \"name\"\n",
"&gt;*&lt; inputField \"description\"\n",
"&gt;*&lt; inputField \"stars\"\n",
")\n",
"where\n",
"adapt (Project{..}) = (projectName, (projectDescription, projectStars))\n",
"</pre>\n",
"\n",
"Infix <a>divided</a>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/rebase/docs/Rebase-Prelude.html#v:divided'><s0>divided</s0></a> &#x2237; Divisible f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'><pre>\n",
"<a>divided</a> = <a>divide</a> <a>id</a>\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/rebase/docs/Rebase-Prelude.html#v:-62--42--60-'>(<s0>>*<</s0>)</a> &#x2237; Divisible f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'>An alias to <a>divided</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/contravariant-extras/docs/Contravariant-Extras.html#v:-62--42--60-'>(<s0>>*<</s0>)</a> &#x2237; Divisible f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'>An alias to <a>divided</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/rebase/docs/Rebase-Prelude.html#v:contrazip2'><s0>contrazip2</s0></a> &#x2237; Divisible f &#x21D2; f a1 &#x2192; f a2 &#x2192; f (a1, a2)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/contravariant-extras/docs/Contravariant-Extras-Contrazip.html#v:contrazip2'><s0>contrazip2</s0></a> &#x2237; &#x2200; f a1 a2 . Divisible f &#x21D2; f a1 &#x2192; f a2 &#x2192; f (a1, a2)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/vector/docs/Data-Vector-Generic.html#v:zip'><s0>zip</s0></a> &#x2237; (Vector v a, Vector v b, Vector v (a, b)) &#x21D2; v a &#x2192; v b &#x2192; v (a, b)</span><div class='hoogle-doc'><i>O(min(m,n))</i> Zip two vectors\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/statistics/docs/Statistics-Sample.html#v:pair'><s0>pair</s0></a> &#x2237; (Vector v a, Vector v b, Vector v (a, b)) &#x21D2; v a &#x2192; v b &#x2192; v (a, b)</span><div class='hoogle-doc'>Pair two samples. It's like <a>zip</a> but requires that both samples\n",
"have equal size.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/rio/docs/RIO-Vector.html#v:zip'><s0>zip</s0></a> &#x2237; (Vector v a, Vector v b, Vector v (a, b)) &#x21D2; v a &#x2192; v b &#x2192; v (a, b)</span><div class='hoogle-doc'><i>O(min(m,n))</i> Zip two vectors\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/size-based/docs/Control-Sized.html#v:pair'><s0>pair</s0></a> &#x2237; Sized f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'>Default: <tt>pair a b = (,) <a>$</a> a <a>*</a> b</tt>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/bytestring/docs/Data-ByteString-Builder-Prim.html#v:-62--42--60-'>(<s0>>*<</s0>)</a> &#x2237; Monoidal f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'>A pairing/concatenation operator for builder primitives, both bounded\n",
"and fixed size.\n",
"\n",
"For example,\n",
"\n",
"<pre>\n",
"toLazyByteString (primFixed (char7 &gt;*&lt; char7) ('x','y')) = \"xy\"\n",
"</pre>\n",
"\n",
"We can combine multiple primitives using <a>&gt;*&lt;</a> multiple\n",
"times.\n",
"\n",
"<pre>\n",
"toLazyByteString (primFixed (char7 &gt;*&lt; char7 &gt;*&lt; char7) ('x',('y','z'))) = \"xyz\"\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/invertible/docs/Control-Invertible-Monoidal.html#v:-62--42--60-'>(<s0>>*<</s0>)</a> &#x2237; Monoidal f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'>Merge two functors into a tuple, analogous to <tt><a>liftA2</a>\n",
"(,)</tt>. (Sometimes known as <tt>**</tt>.)\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/List/docs/Data-List-Class.html#v:zip'><s0>zip</s0></a> &#x2237; List l &#x21D2; l a &#x2192; l b &#x2192; l (a, b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/classy-prelude/docs/ClassyPrelude.html#v:zip'><s0>zip</s0></a> &#x2237; Zip f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/non-empty/docs/Data-NonEmpty-Class.html#v:zip'><s0>zip</s0></a> &#x2237; (Zip f) &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/keys/docs/Data-Key.html#v:zip'><s0>zip</s0></a> &#x2237; Zip f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/chunked-data/docs/Data-ChunkedZip.html#v:zip'><s0>zip</s0></a> &#x2237; Zip f &#x21D2; f a &#x2192; f b &#x2192; f (a, b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/base/docs/Control-Monad-Zip.html#v:mzip'><s0>mzip</s0></a> &#x2237; MonadZip m &#x21D2; m a &#x2192; m b &#x2192; m (a, b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/relational-query/docs/Database-Relational-Arrow.html#v:projectZip'><s0>projectZip</s0></a> &#x2237; ProductIsoApplicative p &#x21D2; p a &#x2192; p b &#x2192; p (a, b)</span><div class='hoogle-doc'>Zipping projections.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/relational-query/docs/Database-Relational-Arrow.html#v:-62--60-'>(<s0>><</s0>)</a> &#x2237; ProductIsoApplicative p &#x21D2; p a &#x2192; p b &#x2192; p (a, b)</span><div class='hoogle-doc'>Binary operator the same as <a>projectZip</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/relational-query/docs/Database-Relational-Projectable.html#v:projectZip'><s0>projectZip</s0></a> &#x2237; ProductIsoApplicative p &#x21D2; p a &#x2192; p b &#x2192; p (a, b)</span><div class='hoogle-doc'>Zipping projections.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/relational-query/docs/Database-Relational-Projectable.html#v:-62--60-'>(<s0>><</s0>)</a> &#x2237; ProductIsoApplicative p &#x21D2; p a &#x2192; p b &#x2192; p (a, b)</span><div class='hoogle-doc'>Binary operator the same as <a>projectZip</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/relational-record/docs/Database-Relational-Documentation.html#v:-62--60-'>(<s0>><</s0>)</a> &#x2237; ProductIsoApplicative p &#x21D2; p a &#x2192; p b &#x2192; p (a, b)</span><div class='hoogle-doc'>Binary operator the same as <a>projectZip</a>.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/unfoldable/docs/Data-Biunfoldable.html#v:biunfold'><s0>biunfold</s0></a> &#x2237; (Biunfoldable t, Unfolder f) &#x21D2; f a &#x2192; f b &#x2192; f (t a b)</span><div class='hoogle-doc'>Given a way to generate elements, return a way to generate structures\n",
"containing those elements.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/unfoldable/docs/Data-Biunfoldable.html#v:biunfoldBF'><s0>biunfoldBF</s0></a> &#x2237; (Biunfoldable t, Unfolder f) &#x21D2; f a &#x2192; f b &#x2192; f (t a b)</span><div class='hoogle-doc'>Breadth-first unfold, which orders the result by the number of\n",
"<a>choose</a> calls.\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/bytes/docs/Data-Bytes-Serial.html#v:deserializeWith2'><s0>deserializeWith2</s0></a> &#x2237; (Serial2 f, MonadGet m) &#x21D2; m a &#x2192; m b &#x2192; m (f a b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/unfoldable-restricted/docs/Data-Unfoldable-Restricted.html#v:biunfoldRestrict'><s0>biunfoldRestrict</s0></a> &#x2237; (BiunfoldableR predA predB t, predA a, predB b, Unfolder f) &#x21D2; f a &#x2192; f b &#x2192; f (t a b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/unfoldable-restricted/docs/Data-Unfoldable-Restricted.html#v:biunfoldRestrictBF'><s0>biunfoldRestrictBF</s0></a> &#x2237; (BiunfoldableR p q t, Unfolder f, p a, q b) &#x21D2; f a &#x2192; f b &#x2192; f (t a b)</span><div class='hoogle-doc'></div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-HigherKinded-Class.html#v:mesh'><s0>mesh</s0></a> &#x2237; Graph g &#x21D2; [a] &#x2192; [b] &#x2192; g (a, b)</span><div class='hoogle-doc'>Construct a <i>mesh graph</i> from two lists of vertices. Complexity:\n",
"<i>O(L1 * L2)</i> time, memory and size, where <i>L1</i> and <i>L2</i>\n",
"are the lengths of the given lists.\n",
"\n",
"<pre>\n",
"mesh xs [] == <a>empty</a>\n",
"mesh [] ys == <a>empty</a>\n",
"mesh [x] [y] == <a>vertex</a> (x, y)\n",
"mesh xs ys == <tt>box</tt> (<a>path</a> xs) (<a>path</a> ys)\n",
"mesh [1..3] \"ab\" == <a>edges</a> [ ((1,'a'),(1,'b')), ((1,'a'),(2,'a')), ((1,'b'),(2,'b')), ((2,'a'),(2,'b'))\n",
", ((2,'a'),(3,'a')), ((2,'b'),(3,'b')), ((3,'a'),(3,'b')) ]\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-HigherKinded-Class.html#v:torus'><s0>torus</s0></a> &#x2237; Graph g &#x21D2; [a] &#x2192; [b] &#x2192; g (a, b)</span><div class='hoogle-doc'>Construct a <i>torus graph</i> from two lists of vertices. Complexity:\n",
"<i>O(L1 * L2)</i> time, memory and size, where <i>L1</i> and <i>L2</i>\n",
"are the lengths of the given lists.\n",
"\n",
"<pre>\n",
"torus xs [] == <a>empty</a>\n",
"torus [] ys == <a>empty</a>\n",
"torus [x] [y] == <a>edge</a> (x,y) (x,y)\n",
"torus xs ys == <tt>box</tt> (<a>circuit</a> xs) (<a>circuit</a> ys)\n",
"torus [1,2] \"ab\" == <a>edges</a> [ ((1,'a'),(1,'b')), ((1,'a'),(2,'a')), ((1,'b'),(1,'a')), ((1,'b'),(2,'b'))\n",
", ((2,'a'),(1,'a')), ((2,'a'),(2,'b')), ((2,'b'),(1,'b')), ((2,'b'),(2,'a')) ]\n",
"</pre>\n",
"</div>\n",
"<span class='hoogle-name'><a target='_blank' href='https://hackage.haskell.org/package/safe/docs/Safe-Exact.html#v:zipExactMay'><s0>zipExactMay</s0></a> &#x2237; [a] &#x2192; [b] &#x2192; Maybe [(a, b)]</span><div class='hoogle-doc'></div>\n"
],
"text/plain": [
"<s0>zip</s0> :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/base/docs/Prelude.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/base/docs/Data-List.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/base/docs/GHC-List.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/base/docs/GHC-OldList.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/hspec/docs/Test-Hspec-Discover.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/Cabal/docs/Distribution-Compat-Prelude-Internal.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zipExact</s0> :: Partial => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/safe/docs/Safe-Exact.html#v:zipExact\n",
"<pre>\n",
"zipExact xs ys =\n",
"| length xs == length ys = zip xs ys\n",
"| otherwise = error \"some message\"\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/base-compat/docs/Prelude-Compat.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/protolude/docs/Protolude.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/numeric-prelude/docs/NumericPrelude.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/numeric-prelude/docs/NumericPrelude-Base.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/rio/docs/RIO.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/rio/docs/RIO-List.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/fay-base/docs/Prelude.html#v:zip\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/rebase/docs/Rebase-Prelude.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"\n",
"(<s0>+*+</s0>) :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/universe-base/docs/Data-Universe-Helpers.html#v:-43--42--43-\n",
"Slightly unfair 2-way Cartesian product: given two (possibly infinite)\n",
"lists, produce a single list such that whenever <tt>v</tt> and\n",
"<tt>w</tt> have finite indices in the input lists, <tt>(v,w)</tt> has\n",
"finite index in the output list. Lower indices occur as the\n",
"<tt>fst</tt> part of the tuple more frequently, but not exponentially\n",
"so.\n",
"\n",
"<s0>unfairCartesianProduct</s0> :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/universe-base/docs/Data-Universe-Helpers.html#v:unfairCartesianProduct\n",
"Very unfair 2-way Cartesian product: same guarantee as the slightly\n",
"unfair one, except that lower indices may occur as the <tt>fst</tt>\n",
"part of the tuple exponentially more frequently. This mainly exists as\n",
"a specification to test against.\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/universum/docs/Universum-List-Reexport.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/llvm-hs-pure/docs/LLVM-Prelude.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/haxl/docs/Haxl-Prelude.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/prelude-compat/docs/Data-List2010.html#v:zip\n",
"\n",
"<s0>zip</s0> :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/prelude-compat/docs/Prelude2010.html#v:zip\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/stack/docs/Stack-Prelude.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/EdisonAPI/docs/Data-Edison-Seq-ListSeq.html#v:zip\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/LambdaHack/docs/Game-LambdaHack-Common-Prelude.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/LambdaHack/docs/Game-LambdaHack-Common-Prelude.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/mixed-types-num/docs/Numeric-MixedTypes-PreludeHiding.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/intro/docs/Intro.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/relude/docs/Relude-List-Reexport.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/yesod-paginator/docs/Yesod-Paginator-Prelude.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded.\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"</pre>\n",
"\n",
"<s0>zip</s0> :: () => [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/hledger-web/docs/Hledger-Web-Import.html#v:zip\n",
"<a>zip</a> takes two lists and returns a list of corresponding pairs.\n",
"\n",
"<pre>\n",
"zip [1, 2] ['a', 'b'] = [(1, 'a'), (2, 'b')]\n",
"</pre>\n",
"\n",
"If one input list is short, excess elements of the longer list are\n",
"discarded:\n",
"\n",
"<pre>\n",
"zip [1] ['a', 'b'] = [(1, 'a')]\n",
"zip [1, 2] ['a'] = [(1, 'a')]\n",
"</pre>\n",
"\n",
"<a>zip</a> is right-lazy:\n",
"\n",
"<pre>\n",
"zip [] _|_ = []\n",
"zip _|_ [] = _|_\n",
"</pre>\n",
"\n",
"<s0>zipLazy</s0> :: [a] -> [b] -> [(a, b)]\n",
"URL: https://hackage.haskell.org/package/ghc/docs/Util.html#v:zipLazy\n",
"<a>zipLazy</a> is a kind of <a>zip</a> that is lazy in the second list\n",
"(observe the ~)\n",
"\n",
"<s0>concurrently</s0> :: MonadBaseControl IO m => m a -> m b -> m (a, b)\n",
"URL: https://hackage.haskell.org/package/lifted-async/docs/Control-Concurrent-Async-Lifted.html#v:concurrently\n",
"Generalized version of <a>concurrently</a>.\n",
"\n",
"<s0>concurrently</s0> :: forall m a b . (MonadBaseControl IO m, Forall (Pure m)) => m a -> m b -> m (a, b)\n",
"URL: https://hackage.haskell.org/package/lifted-async/docs/Control-Concurrent-Async-Lifted-Safe.html#v:concurrently\n",
"Generalized version of <a>concurrently</a>.\n",
"\n",
"<s0>pairADefault</s0> :: Applicative f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/invertible/docs/Control-Invertible-Monoidal.html#v:pairADefault\n",
"Default '&gt;*&lt; implementation for non-invertible\n",
"<a>Applicative</a>s.\n",
"\n",
"<s0>concurrently</s0> :: MonadUnliftIO m => m a -> m b -> m (a, b)\n",
"URL: https://hackage.haskell.org/package/unliftio/docs/UnliftIO-Async.html#v:concurrently\n",
"Unlifted <a>concurrently</a>.\n",
"\n",
"<s0>concurrently</s0> :: MonadUnliftIO m => m a -> m b -> m (a, b)\n",
"URL: https://hackage.haskell.org/package/unliftio/docs/UnliftIO-Internals-Async.html#v:concurrently\n",
"Unlifted <a>concurrently</a>.\n",
"\n",
"<s0>concurrently</s0> :: MonadUnliftIO m => m a -> m b -> m (a, b)\n",
"URL: https://hackage.haskell.org/package/stack/docs/Stack-Prelude.html#v:concurrently\n",
"Unlifted <a>concurrently</a>.\n",
"\n",
"<s0>concurrently</s0> :: MonadUnliftIO m => m a -> m b -> m (a, b)\n",
"URL: https://hackage.haskell.org/package/yesod-websockets/docs/Yesod-WebSockets.html#v:concurrently\n",
"Unlifted <a>concurrently</a>.\n",
"\n",
"<s0>zip</s0> :: Sequence s => s a -> s b -> s (a, b)\n",
"URL: https://hackage.haskell.org/package/EdisonAPI/docs/Data-Edison-Seq.html#v:zip\n",
"Combine two sequences into a sequence of pairs. If the sequences are\n",
"different lengths, the excess elements of the longer sequence is\n",
"discarded.\n",
"\n",
"<pre>\n",
"zip &lt;x0,...,xn-1&gt; &lt;y0,...,ym-1&gt; = &lt;(x0,y0),...,(xj-1,yj-1)&gt;\n",
"where j = min {n,m}\n",
"</pre>\n",
"\n",
"<i>Axioms:</i>\n",
"\n",
"<ul>\n",
"<li><pre>zip xs ys = zipWith (,) xs ys</pre></li>\n",
"</ul>\n",
"\n",
"This function is always <i>unambiguous</i>.\n",
"\n",
"Default running time: <tt>O( min( n1, n2 ) )</tt>\n",
"\n",
"<s0>zipUsingLview</s0> :: Sequence s => s a -> s b -> s (a, b)\n",
"URL: https://hackage.haskell.org/package/EdisonCore/docs/Data-Edison-Seq-Defaults.html#v:zipUsingLview\n",
"\n",
"<s0>zipUsingLists</s0> :: Sequence s => s a -> s b -> s (a, b)\n",
"URL: https://hackage.haskell.org/package/EdisonCore/docs/Data-Edison-Seq-Defaults.html#v:zipUsingLists\n",
"\n",
"<s0>mzipRep</s0> :: Representable f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/adjunctions/docs/Data-Functor-Rep.html#v:mzipRep\n",
"\n",
"<s0>concurrently</s0> :: MonadConc m => m a -> m b -> m (a, b)\n",
"URL: https://hackage.haskell.org/package/concurrency/docs/Control-Concurrent-Classy-Async.html#v:concurrently\n",
"Run two <tt>MonadConc</tt> actions concurrently, and return both\n",
"results. If either action throws an exception at any time, then the\n",
"other action is <a>cancel</a>led, and the exception is re-thrown by\n",
"<a>concurrently</a>.\n",
"\n",
"<pre>\n",
"concurrently left right =\n",
"withAsync left $ \\a -&gt;\n",
"withAsync right $ \\b -&gt;\n",
"waitBoth a b\n",
"</pre>\n",
"\n",
"<s0>divided</s0> :: Divisible f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/contravariant/docs/Data-Functor-Contravariant-Divisible.html#v:divided\n",
"<pre>\n",
"<a>divided</a> = <a>divide</a> <a>id</a>\n",
"</pre>\n",
"\n",
"(<s0>>*<</s0>) :: Divisible f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/dhall/docs/Dhall.html#v:-62--42--60-\n",
"The <a>RecordInputType</a> divisible (contravariant) functor allows\n",
"you to build an <a>InputType</a> injector for a Dhall record.\n",
"\n",
"For example, let's take the following Haskell data type:\n",
"\n",
"<pre>\n",
"data Project = Project\n",
"{ projectName :: Text\n",
", projectDescription :: Text\n",
", projectStars :: Natural\n",
"}\n",
"</pre>\n",
"\n",
"And assume that we have the following Dhall record that we would like\n",
"to parse as a <tt>Project</tt>:\n",
"\n",
"<pre>\n",
"{ name =\n",
"\"dhall-haskell\"\n",
", description =\n",
"\"A configuration language guaranteed to terminate\"\n",
", stars =\n",
"289\n",
"}\n",
"</pre>\n",
"\n",
"Our injector has type <a>InputType</a> <tt>Project</tt>, but we can't\n",
"build that out of any smaller injectors, as <a>InputType</a>s cannot\n",
"be combined (they are only <a>Contravariant</a>s). However, we can use\n",
"an <tt>InputRecordType</tt> to build an <a>InputType</a> for\n",
"<tt>Project</tt>:\n",
"\n",
"<pre>\n",
"injectProject :: InputType Project\n",
"injectProject =\n",
"inputRecord\n",
"( adapt &gt;$&lt; inputFieldWith \"name\" inject\n",
"&gt;*&lt; inputFieldWith \"description\" inject\n",
"&gt;*&lt; inputFieldWith \"stars\" inject\n",
")\n",
"where\n",
"adapt (Project{..}) = (projectName, (projectDescription, projectStars))\n",
"</pre>\n",
"\n",
"Or, since we are simply using the <a>Inject</a> instance to inject\n",
"each field, we could write\n",
"\n",
"<pre>\n",
"injectProject :: InputType Project\n",
"injectProject =\n",
"inputRecord\n",
"( adapt &gt;$&lt; inputField \"name\"\n",
"&gt;*&lt; inputField \"description\"\n",
"&gt;*&lt; inputField \"stars\"\n",
")\n",
"where\n",
"adapt (Project{..}) = (projectName, (projectDescription, projectStars))\n",
"</pre>\n",
"\n",
"Infix <a>divided</a>\n",
"\n",
"<s0>divided</s0> :: Divisible f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/rebase/docs/Rebase-Prelude.html#v:divided\n",
"<pre>\n",
"<a>divided</a> = <a>divide</a> <a>id</a>\n",
"</pre>\n",
"\n",
"(<s0>>*<</s0>) :: Divisible f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/rebase/docs/Rebase-Prelude.html#v:-62--42--60-\n",
"An alias to <a>divided</a>.\n",
"\n",
"(<s0>>*<</s0>) :: Divisible f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/contravariant-extras/docs/Contravariant-Extras.html#v:-62--42--60-\n",
"An alias to <a>divided</a>.\n",
"\n",
"<s0>contrazip2</s0> :: Divisible f => f a1 -> f a2 -> f (a1, a2)\n",
"URL: https://hackage.haskell.org/package/rebase/docs/Rebase-Prelude.html#v:contrazip2\n",
"\n",
"<s0>contrazip2</s0> :: forall f a1 a2 . Divisible f => f a1 -> f a2 -> f (a1, a2)\n",
"URL: https://hackage.haskell.org/package/contravariant-extras/docs/Contravariant-Extras-Contrazip.html#v:contrazip2\n",
"\n",
"<s0>zip</s0> :: (Vector v a, Vector v b, Vector v (a, b)) => v a -> v b -> v (a, b)\n",
"URL: https://hackage.haskell.org/package/vector/docs/Data-Vector-Generic.html#v:zip\n",
"<i>O(min(m,n))</i> Zip two vectors\n",
"\n",
"<s0>pair</s0> :: (Vector v a, Vector v b, Vector v (a, b)) => v a -> v b -> v (a, b)\n",
"URL: https://hackage.haskell.org/package/statistics/docs/Statistics-Sample.html#v:pair\n",
"Pair two samples. It's like <a>zip</a> but requires that both samples\n",
"have equal size.\n",
"\n",
"<s0>zip</s0> :: (Vector v a, Vector v b, Vector v (a, b)) => v a -> v b -> v (a, b)\n",
"URL: https://hackage.haskell.org/package/rio/docs/RIO-Vector.html#v:zip\n",
"<i>O(min(m,n))</i> Zip two vectors\n",
"\n",
"<s0>pair</s0> :: Sized f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/size-based/docs/Control-Sized.html#v:pair\n",
"Default: <tt>pair a b = (,) <a>$</a> a <a>*</a> b</tt>.\n",
"\n",
"(<s0>>*<</s0>) :: Monoidal f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/bytestring/docs/Data-ByteString-Builder-Prim.html#v:-62--42--60-\n",
"A pairing/concatenation operator for builder primitives, both bounded\n",
"and fixed size.\n",
"\n",
"For example,\n",
"\n",
"<pre>\n",
"toLazyByteString (primFixed (char7 &gt;*&lt; char7) ('x','y')) = \"xy\"\n",
"</pre>\n",
"\n",
"We can combine multiple primitives using <a>&gt;*&lt;</a> multiple\n",
"times.\n",
"\n",
"<pre>\n",
"toLazyByteString (primFixed (char7 &gt;*&lt; char7 &gt;*&lt; char7) ('x',('y','z'))) = \"xyz\"\n",
"</pre>\n",
"\n",
"(<s0>>*<</s0>) :: Monoidal f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/invertible/docs/Control-Invertible-Monoidal.html#v:-62--42--60-\n",
"Merge two functors into a tuple, analogous to <tt><a>liftA2</a>\n",
"(,)</tt>. (Sometimes known as <tt>**</tt>.)\n",
"\n",
"<s0>zip</s0> :: List l => l a -> l b -> l (a, b)\n",
"URL: https://hackage.haskell.org/package/List/docs/Data-List-Class.html#v:zip\n",
"\n",
"<s0>zip</s0> :: Zip f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/classy-prelude/docs/ClassyPrelude.html#v:zip\n",
"\n",
"<s0>zip</s0> :: (Zip f) => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/non-empty/docs/Data-NonEmpty-Class.html#v:zip\n",
"\n",
"<s0>zip</s0> :: Zip f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/keys/docs/Data-Key.html#v:zip\n",
"\n",
"<s0>zip</s0> :: Zip f => f a -> f b -> f (a, b)\n",
"URL: https://hackage.haskell.org/package/chunked-data/docs/Data-ChunkedZip.html#v:zip\n",
"\n",
"<s0>mzip</s0> :: MonadZip m => m a -> m b -> m (a, b)\n",
"URL: https://hackage.haskell.org/package/base/docs/Control-Monad-Zip.html#v:mzip\n",
"\n",
"<s0>projectZip</s0> :: ProductIsoApplicative p => p a -> p b -> p (a, b)\n",
"URL: https://hackage.haskell.org/package/relational-query/docs/Database-Relational-Arrow.html#v:projectZip\n",
"Zipping projections.\n",
"\n",
"(<s0>><</s0>) :: ProductIsoApplicative p => p a -> p b -> p (a, b)\n",
"URL: https://hackage.haskell.org/package/relational-query/docs/Database-Relational-Arrow.html#v:-62--60-\n",
"Binary operator the same as <a>projectZip</a>.\n",
"\n",
"<s0>projectZip</s0> :: ProductIsoApplicative p => p a -> p b -> p (a, b)\n",
"URL: https://hackage.haskell.org/package/relational-query/docs/Database-Relational-Projectable.html#v:projectZip\n",
"Zipping projections.\n",
"\n",
"(<s0>><</s0>) :: ProductIsoApplicative p => p a -> p b -> p (a, b)\n",
"URL: https://hackage.haskell.org/package/relational-query/docs/Database-Relational-Projectable.html#v:-62--60-\n",
"Binary operator the same as <a>projectZip</a>.\n",
"\n",
"(<s0>><</s0>) :: ProductIsoApplicative p => p a -> p b -> p (a, b)\n",
"URL: https://hackage.haskell.org/package/relational-record/docs/Database-Relational-Documentation.html#v:-62--60-\n",
"Binary operator the same as <a>projectZip</a>.\n",
"\n",
"<s0>biunfold</s0> :: (Biunfoldable t, Unfolder f) => f a -> f b -> f (t a b)\n",
"URL: https://hackage.haskell.org/package/unfoldable/docs/Data-Biunfoldable.html#v:biunfold\n",
"Given a way to generate elements, return a way to generate structures\n",
"containing those elements.\n",
"\n",
"<s0>biunfoldBF</s0> :: (Biunfoldable t, Unfolder f) => f a -> f b -> f (t a b)\n",
"URL: https://hackage.haskell.org/package/unfoldable/docs/Data-Biunfoldable.html#v:biunfoldBF\n",
"Breadth-first unfold, which orders the result by the number of\n",
"<a>choose</a> calls.\n",
"\n",
"<s0>deserializeWith2</s0> :: (Serial2 f, MonadGet m) => m a -> m b -> m (f a b)\n",
"URL: https://hackage.haskell.org/package/bytes/docs/Data-Bytes-Serial.html#v:deserializeWith2\n",
"\n",
"<s0>biunfoldRestrict</s0> :: (BiunfoldableR predA predB t, predA a, predB b, Unfolder f) => f a -> f b -> f (t a b)\n",
"URL: https://hackage.haskell.org/package/unfoldable-restricted/docs/Data-Unfoldable-Restricted.html#v:biunfoldRestrict\n",
"\n",
"<s0>biunfoldRestrictBF</s0> :: (BiunfoldableR p q t, Unfolder f, p a, q b) => f a -> f b -> f (t a b)\n",
"URL: https://hackage.haskell.org/package/unfoldable-restricted/docs/Data-Unfoldable-Restricted.html#v:biunfoldRestrictBF\n",
"\n",
"<s0>mesh</s0> :: Graph g => [a] -> [b] -> g (a, b)\n",
"URL: https://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-HigherKinded-Class.html#v:mesh\n",
"Construct a <i>mesh graph</i> from two lists of vertices. Complexity:\n",
"<i>O(L1 * L2)</i> time, memory and size, where <i>L1</i> and <i>L2</i>\n",
"are the lengths of the given lists.\n",
"\n",
"<pre>\n",
"mesh xs [] == <a>empty</a>\n",
"mesh [] ys == <a>empty</a>\n",
"mesh [x] [y] == <a>vertex</a> (x, y)\n",
"mesh xs ys == <tt>box</tt> (<a>path</a> xs) (<a>path</a> ys)\n",
"mesh [1..3] \"ab\" == <a>edges</a> [ ((1,'a'),(1,'b')), ((1,'a'),(2,'a')), ((1,'b'),(2,'b')), ((2,'a'),(2,'b'))\n",
", ((2,'a'),(3,'a')), ((2,'b'),(3,'b')), ((3,'a'),(3,'b')) ]\n",
"</pre>\n",
"\n",
"<s0>torus</s0> :: Graph g => [a] -> [b] -> g (a, b)\n",
"URL: https://hackage.haskell.org/package/algebraic-graphs/docs/Algebra-Graph-HigherKinded-Class.html#v:torus\n",
"Construct a <i>torus graph</i> from two lists of vertices. Complexity:\n",
"<i>O(L1 * L2)</i> time, memory and size, where <i>L1</i> and <i>L2</i>\n",
"are the lengths of the given lists.\n",
"\n",
"<pre>\n",
"torus xs [] == <a>empty</a>\n",
"torus [] ys == <a>empty</a>\n",
"torus [x] [y] == <a>edge</a> (x,y) (x,y)\n",
"torus xs ys == <tt>box</tt> (<a>circuit</a> xs) (<a>circuit</a> ys)\n",
"torus [1,2] \"ab\" == <a>edges</a> [ ((1,'a'),(1,'b')), ((1,'a'),(2,'a')), ((1,'b'),(1,'a')), ((1,'b'),(2,'b'))\n",
", ((2,'a'),(1,'a')), ((2,'a'),(2,'b')), ((2,'b'),(1,'b')), ((2,'b'),(2,'a')) ]\n",
"</pre>\n",
"\n",
"<s0>zipExactMay</s0> :: [a] -> [b] -> Maybe [(a, b)]\n",
"URL: https://hackage.haskell.org/package/safe/docs/Safe-Exact.html#v:zipExactMay"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
":hoogle :: [a] -> [b] -> [(a, b)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you need a refresher on all of the options, you can just use `:help`:"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"The following commands are available:\n",
" :extension <Extension> - Enable a GHC extension.\n",
" :extension No<Extension> - Disable a GHC extension.\n",
" :type <expression> - Print expression type.\n",
" :info <name> - Print all info for a name.\n",
" :hoogle <query> - Search for a query on Hoogle.\n",
" :doc <ident> - Get documentation for an identifier via Hogole.\n",
" :set -XFlag -Wall - Set an option (like ghci).\n",
" :option <opt> - Set an option.\n",
" :option no-<opt> - Unset an option.\n",
" :?, :help - Show this help text.\n",
"\n",
"Any prefix of the commands will also suffice, e.g. use :ty for :type.\n",
"\n",
"Options:\n",
" lint enable or disable linting.\n",
" svg use svg output (cannot be resized).\n",
" show-types show types of all bound names\n",
" show-errors display Show instance missing errors normally.\n",
" pager use the pager to display results of :info, :doc, :hoogle, etc."
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
":help"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All of the code you normally put into IHaskell is (like in GHCi) interpreted. However, sometimes you've perfected a function, and now need it to run faster. In that case, you can go ahead and define a module in a single cell. As long as your module has a module header along the lines of `module Name where`, IHaskell will recognize it as a module. It will create the file `A/B.hs`, compile it, and load it. "
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [],
"source": [
"-- If your code isn't running fast enough, you can just put it into a module.\n",
"module A.B where\n",
"\n",
"fib 0 = 1\n",
"fib 1 = 1\n",
"fib n = fib (n-1) + fib (n-2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that the module is by default imported unqualified, as though you had typed `import A.B`."
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"10946"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"10946"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"-- The module is automatically imported unqualified.\n",
"print $ A.B.fib 20\n",
"print $ fib 20"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that since a new module is imported, all previous bound identifiers are now unbound. For instance, we no longer have access to the `f` function from before:"
]
},
{
"cell_type": "code",
"execution_count": 30,
"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",
".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",
".highlight-code {\n",
"white-space: pre;\n",
"font-family: monospace;\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",
"</style><span class='err-msg'>&lt;interactive&gt;:1:1: error: Variable not in scope: f :: Integer -&gt; t</span>"
],
"text/plain": [
"<interactive>:1:1: error: Variable not in scope: f :: Integer -> t"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"f 3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"However, if you re-import this module with another import statement, the original implicit import goes away."
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"10946"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"10946"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import qualified A.B as Fib\n",
"\n",
"Fib.fib 20\n",
"fib 20"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Thanks!\n",
"---\n",
"\n",
"That's it for now! I hope you've enjoyed this little demo of **IHaskell**! There are still a few features that I haven't covered, such as the `show-types` and `show-errors` options, as well as the relatively intelligent autocompletion mechanism and inline type info popups.\n",
"\n",
"I hope you find IHaskell useful, and please report any bugs or features requests [on Github](https://github.com/gibiansky/IHaskell/issues). If you have any comments, want to contribute, or just want to get in touch, don't hesitate to contact me at Andrew dot Gibiansky at Gmail. Contributions are also more than welcome, and I'm happy to help you get started with IHaskell development if you'd like to contribute!\n",
"\n",
"Thank you to [Adam Vogt](https://github.com/aavogt), [Stian Håklev](http://reganmian.net/), and [@edechter](https://github.com/edechter) for their testing, bug reporting, pull requests, and general patience!"
]
}
],
"metadata": {
"hide_input": false,
"kernelspec": {
"display_name": "Haskell",
"language": "haskell",
"name": "haskell"
},
"language_info": {
"codemirror_mode": "ihaskell",
"file_extension": ".hs",
"name": "haskell",
"pygments_lexer": "Haskell",
"version": "8.4.4"
},
"latex_envs": {
"bibliofile": "biblio.bib",
"cite_by": "apalike",
"current_citInitial": 1,
"eqLabelWithNumbers": true,
"eqNumInitial": 0
},
"nav_menu": {},
"toc": {
"navigate_menu": true,
"number_sections": true,
"sideBar": true,
"threshold": 6,
"toc_cell": false,
"toc_section_display": "block",
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 1
}