Skip to content

Commit 38761a8

Browse files
committed
Updated Partial Application section
Rewrote last example
1 parent e164d1d commit 38761a8

File tree

1 file changed

+212
-11
lines changed

1 file changed

+212
-11
lines changed

index.ipynb

+212-11
Original file line numberDiff line numberDiff line change
@@ -1586,12 +1586,124 @@
15861586
"id": "215f5f1e",
15871587
"metadata": {},
15881588
"source": [
1589-
"This feature is called **partial application**. On its surface, it's nice for adding convenient names to helper functions. In practice, it can allow you to express complexity using simple, modular pieces:"
1589+
"This feature is called **partial application**. It can help you express complexity using simple, modular pieces:"
1590+
]
1591+
},
1592+
{
1593+
"cell_type": "markdown",
1594+
"id": "80ae388c",
1595+
"metadata": {},
1596+
"source": [
1597+
"Here we build `add` and `divide` from `combine` by passing `+` and `/` to it. This code doesn't do much anything useful though... "
15901598
]
15911599
},
15921600
{
15931601
"cell_type": "code",
1594-
"execution_count": 24,
1602+
"execution_count": 174,
1603+
"metadata": {
1604+
"dotnet_interactive": {
1605+
"language": "fsharp"
1606+
},
1607+
"polyglot_notebook": {
1608+
"kernelName": "fsharp"
1609+
}
1610+
},
1611+
"outputs": [
1612+
{
1613+
"data": {
1614+
"text/html": [
1615+
"<details open=\"open\" class=\"dni-treeview\"><summary><span class=\"dni-code-hint\"><code>(7, 2)</code></span></summary><div><table><thead><tr></tr></thead><tbody><tr><td>Item1</td><td><div class=\"dni-plaintext\"><pre>7</pre></div></td></tr><tr><td>Item2</td><td><div class=\"dni-plaintext\"><pre>2</pre></div></td></tr></tbody></table></div></details><style>\r\n",
1616+
".dni-code-hint {\r\n",
1617+
" font-style: italic;\r\n",
1618+
" overflow: hidden;\r\n",
1619+
" white-space: nowrap;\r\n",
1620+
"}\r\n",
1621+
".dni-treeview {\r\n",
1622+
" white-space: nowrap;\r\n",
1623+
"}\r\n",
1624+
".dni-treeview td {\r\n",
1625+
" vertical-align: top;\r\n",
1626+
" text-align: start;\r\n",
1627+
"}\r\n",
1628+
"details.dni-treeview {\r\n",
1629+
" padding-left: 1em;\r\n",
1630+
"}\r\n",
1631+
"table td {\r\n",
1632+
" text-align: start;\r\n",
1633+
"}\r\n",
1634+
"table tr { \r\n",
1635+
" vertical-align: top; \r\n",
1636+
" margin: 0em 0px;\r\n",
1637+
"}\r\n",
1638+
"table tr td pre \r\n",
1639+
"{ \r\n",
1640+
" vertical-align: top !important; \r\n",
1641+
" margin: 0em 0px !important;\r\n",
1642+
"} \r\n",
1643+
"table th {\r\n",
1644+
" text-align: start;\r\n",
1645+
"}\r\n",
1646+
"</style>"
1647+
]
1648+
},
1649+
"metadata": {},
1650+
"output_type": "display_data"
1651+
}
1652+
],
1653+
"source": [
1654+
"// y applied to x applied to f\n",
1655+
"let combine f x y = f x y\n",
1656+
"let add = combine (+) // a way to pass the + function\n",
1657+
"let divide = combine (/)\n",
1658+
"\n",
1659+
"add 3 4, divide 9 4"
1660+
]
1661+
},
1662+
{
1663+
"cell_type": "markdown",
1664+
"id": "2bbb29e9",
1665+
"metadata": {},
1666+
"source": [
1667+
"We can pass a `check` function to `combine` that can perform a check and decide whether we want to continue the computation or not."
1668+
]
1669+
},
1670+
{
1671+
"cell_type": "markdown",
1672+
"id": "92fbc8a2",
1673+
"metadata": {},
1674+
"source": [
1675+
"`f` comes first in the parameter list because we probably want will want to bind it first then later decide what type of check behavior we want."
1676+
]
1677+
},
1678+
{
1679+
"cell_type": "code",
1680+
"execution_count": null,
1681+
"id": "ae36a578",
1682+
"metadata": {
1683+
"dotnet_interactive": {
1684+
"language": "fsharp"
1685+
},
1686+
"polyglot_notebook": {
1687+
"kernelName": "fsharp"
1688+
}
1689+
},
1690+
"outputs": [],
1691+
"source": [
1692+
"let combine f check x y =\n",
1693+
" check f x y"
1694+
]
1695+
},
1696+
{
1697+
"cell_type": "markdown",
1698+
"id": "49329736",
1699+
"metadata": {},
1700+
"source": [
1701+
"We can build all different kinds of \"adders\" from `combine`:"
1702+
]
1703+
},
1704+
{
1705+
"cell_type": "code",
1706+
"execution_count": 213,
15951707
"id": "265d4712",
15961708
"metadata": {
15971709
"dotnet_interactive": {
@@ -1606,26 +1718,115 @@
16061718
"name": "stdout",
16071719
"output_type": "stream",
16081720
"text": [
1609-
"8\n",
1610-
"NaN\n"
1721+
"9\n",
1722+
"Adding 5 + 6...\n",
1723+
"11\n",
1724+
"8\n"
16111725
]
16121726
}
16131727
],
16141728
"source": [
1615-
"let combine f check x y =\n",
1616-
" f <|| check x y\n",
1729+
"let normalize f x y = f (abs x) (abs y)\n",
16171730
"\n",
1618-
"let id2 x y = x, y\n",
1731+
"let normalizeThenAdd = combine (+) normalize\n",
1732+
"normalizeThenAdd -4 5 |> printfn \"%d\"\n",
16191733
"\n",
1620-
"let add = combine (+) id2\n",
1621-
"add 3 5 |> printfn \"%d\"\n",
1734+
"let printThenAdd = combine (+) (fun f x y -> printfn \"Adding %d + %d...\" x y; f x y)\n",
1735+
"printThenAdd 5 6 |> printfn \"%d\"\n",
16221736
"\n",
1623-
"let divideThen check = combine (/) check\n",
1624-
"let safeDivide = divideThen (fun x y -> if y = 0 then x, nan else x, y)\n",
1737+
"let add = combine (+) id // id is a special function that means \"do nothing\" in this context\n",
1738+
"add 3 5 |> printfn \"%d\""
1739+
]
1740+
},
1741+
{
1742+
"cell_type": "markdown",
1743+
"id": "1c89cc9d",
1744+
"metadata": {},
1745+
"source": [
1746+
"We can build \"safe dividers\" that checks whether the denominator = 0."
1747+
]
1748+
},
1749+
{
1750+
"cell_type": "markdown",
1751+
"id": "1ca4528b",
1752+
"metadata": {},
1753+
"source": [
1754+
"`safeDivide` replaces `y` with `NaN` when `y = 0`:"
1755+
]
1756+
},
1757+
{
1758+
"cell_type": "code",
1759+
"execution_count": 206,
1760+
"metadata": {
1761+
"dotnet_interactive": {
1762+
"language": "fsharp"
1763+
},
1764+
"polyglot_notebook": {
1765+
"kernelName": "fsharp"
1766+
}
1767+
},
1768+
"outputs": [
1769+
{
1770+
"name": "stdout",
1771+
"output_type": "stream",
1772+
"text": [
1773+
"NaN\n"
1774+
]
1775+
}
1776+
],
1777+
"source": [
1778+
"let ``convert divBy0 to NaN`` f x y =\n",
1779+
" f x (if y = 0 then nan else y)\n",
16251780
"\n",
1781+
"let safeDivide = combine (/) ``convert divBy0 to NaN``\n",
16261782
"safeDivide 4 0 |> printfn \"%f\""
16271783
]
16281784
},
1785+
{
1786+
"cell_type": "markdown",
1787+
"id": "12c206eb",
1788+
"metadata": {},
1789+
"source": [
1790+
"`safeDivide` implicitly evaluates to a `float`, though, because `NaN` is not a valid value for `int`s. Sometimes you absolutely do want integer division, which evaluates to an `int` and ignores the remainder.\n",
1791+
"\n",
1792+
"`tryDivide` checks if `y = 0`, and if it is, it avoids doing the division altogether (by not evaluating `cont`).\n",
1793+
"> ℹ️ Note\n",
1794+
"> \n",
1795+
"> I should move this example down further to when I explain Option types, perhaps referencing this example. It is not 100% clear what is going on here without explaining option types."
1796+
]
1797+
},
1798+
{
1799+
"cell_type": "code",
1800+
"execution_count": 219,
1801+
"metadata": {
1802+
"dotnet_interactive": {
1803+
"language": "fsharp"
1804+
},
1805+
"polyglot_notebook": {
1806+
"kernelName": "fsharp"
1807+
}
1808+
},
1809+
"outputs": [
1810+
{
1811+
"name": "stdout",
1812+
"output_type": "stream",
1813+
"text": [
1814+
"Some(4)\n",
1815+
"<null>\n"
1816+
]
1817+
}
1818+
],
1819+
"source": [
1820+
"let ``convert divBy0 to None`` cont x y =\n",
1821+
" if y = 0 then None else Some(cont x y)\n",
1822+
"\n",
1823+
"// remove this example for now and reference it when teaching the Option type\n",
1824+
"let tryDivide = combine (/) ``convert divBy0 to None``\n",
1825+
"\n",
1826+
"tryDivide 4 1 |> printfn \"%O\"\n",
1827+
"tryDivide 4 0 |> printfn \"%O\""
1828+
]
1829+
},
16291830
{
16301831
"cell_type": "markdown",
16311832
"id": "7ec9b1fa",

0 commit comments

Comments
 (0)