diff --git a/_sources/chapters/basics/expressions.ipynb b/_sources/chapters/basics/expressions.ipynb index ef9a3b3e..d071f2a8 100644 --- a/_sources/chapters/basics/expressions.ipynb +++ b/_sources/chapters/basics/expressions.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "markdown", - "id": "5738c8f5", + "id": "de643309", "metadata": {}, "source": [ "# Expressions\n", @@ -50,72 +50,41 @@ }, { "cell_type": "code", - "execution_count": 1, - "id": "cb3fa0c2", + "execution_count": null, + "id": "a6689563", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : int = 1\n" - ] - }, - "execution_count": 1, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "65 / 60" ] }, { "cell_type": "code", - "execution_count": 2, - "id": "207a0f79", + "execution_count": null, + "id": "c01dd4dd", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : int = 5\n" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "65 mod 60" ] }, { "cell_type": "code", - "execution_count": 3, - "id": "223e0b29", + "execution_count": null, + "id": "78bc7260", "metadata": { "tags": [ "raises-exception" ] }, - "outputs": [ - { - "ename": "error", - "evalue": "runtime_error", - "output_type": "error", - "traceback": [ - "\u001b[31mException: Division_by_zero.\nRaised by primitive operation at unknown location\nCalled from Stdlib__Fun.protect in file \"fun.ml\", line 33, characters 8-15\nRe-raised at Stdlib__Fun.protect in file \"fun.ml\", line 38, characters 6-52\nCalled from Topeval.load_lambda in file \"toplevel/byte/topeval.ml\", line 89, characters 4-150\n\u001b[0m" - ] - } - ], + "outputs": [], "source": [ "65 / 0" ] }, { "cell_type": "markdown", - "id": "d7ba9067", + "id": "603d4266", "metadata": {}, "source": [ "OCaml integers range from $-2^{62}$ to $2^{62}-1$ on modern platforms. They are\n", @@ -139,49 +108,27 @@ }, { "cell_type": "code", - "execution_count": 4, - "id": "f0d15655", + "execution_count": null, + "id": "8dc13c88", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : float = 3.\n" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "3." ] }, { "cell_type": "code", - "execution_count": 5, - "id": "5e61e783", + "execution_count": null, + "id": "3e8ee2c3", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : int = 3\n" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "3" ] }, { "cell_type": "markdown", - "id": "e6d9e894", + "id": "d956480c", "metadata": {}, "source": [ "OCaml deliberately does not support operator overloading, Arithmetic operations\n", @@ -191,51 +138,31 @@ }, { "cell_type": "code", - "execution_count": 6, - "id": "88d82dbb", + "execution_count": null, + "id": "e2f62334", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : float = 6.28\n" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "3.14 *. 2." ] }, { "cell_type": "code", - "execution_count": 7, - "id": "255582a3", + "execution_count": null, + "id": "4e0392a2", "metadata": { "tags": [ "raises-exception" ] }, - "outputs": [ - { - "ename": "error", - "evalue": "compile_error", - "output_type": "error", - "traceback": [ - "File \"[7]\", line 1, characters 0-4:\n1 | 3.14 * 2.\n ^^^^\nError: This expression has type float but an expression was expected of type\n int\n" - ] - } - ], + "outputs": [], "source": [ "3.14 * 2." ] }, { "cell_type": "markdown", - "id": "e1293fa4", + "id": "e3addc18", "metadata": {}, "source": [ "OCaml will not automatically convert between `int` and `float`. If you want to\n", @@ -245,28 +172,17 @@ }, { "cell_type": "code", - "execution_count": 8, - "id": "a560033c", + "execution_count": null, + "id": "fac2d2fa", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : float = 6.28\n" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "3.14 *. (float_of_int 2)" ] }, { "cell_type": "markdown", - "id": "65ff8542", + "id": "b6c24f17", "metadata": {}, "source": [ "As in any language, the floating-point representation is approximate. That can\n", @@ -275,28 +191,17 @@ }, { "cell_type": "code", - "execution_count": 9, - "id": "9346b1eb", + "execution_count": null, + "id": "a5f4e26c", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : float = 0.300000000000000044\n" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "0.1 +. 0.2" ] }, { "cell_type": "markdown", - "id": "e70265cc", + "id": "8912c61f", "metadata": {}, "source": [ "The same behavior can be observed in Python and Java, too. If you haven't\n", @@ -323,28 +228,17 @@ }, { "cell_type": "code", - "execution_count": 10, - "id": "b795d1f6", + "execution_count": null, + "id": "506a9183", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : string = \"abcdef\"\n" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "\"abc\" ^ \"def\"" ] }, { "cell_type": "markdown", - "id": "68622ab1", + "id": "a07183b2", "metadata": {}, "source": [ "Object-oriented languages often provide an overridable method for converting\n", @@ -358,49 +252,27 @@ }, { "cell_type": "code", - "execution_count": 11, - "id": "bd0355ea", + "execution_count": null, + "id": "3df15416", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : string = \"42\"\n" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "string_of_int 42" ] }, { "cell_type": "code", - "execution_count": 12, - "id": "57d1407a", + "execution_count": null, + "id": "88c94182", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : string = \"z\"\n" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "String.make 1 'z'" ] }, { "cell_type": "markdown", - "id": "dfa59c90", + "id": "771543e2", "metadata": {}, "source": [ "Likewise, for the same three primitive types, there are built-in functions to\n", @@ -410,51 +282,31 @@ }, { "cell_type": "code", - "execution_count": 13, - "id": "d829b6e3", + "execution_count": null, + "id": "901b88a2", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : int = 123\n" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "int_of_string \"123\"" ] }, { "cell_type": "code", - "execution_count": 14, - "id": "bdd3d1e3", + "execution_count": null, + "id": "d53b2948", "metadata": { "tags": [ "raises-exception" ] }, - "outputs": [ - { - "ename": "error", - "evalue": "runtime_error", - "output_type": "error", - "traceback": [ - "\u001b[31mException: Failure \"int_of_string\".\nRaised by primitive operation at unknown location\nCalled from Stdlib__Fun.protect in file \"fun.ml\", line 33, characters 8-15\nRe-raised at Stdlib__Fun.protect in file \"fun.ml\", line 38, characters 6-52\nCalled from Topeval.load_lambda in file \"toplevel/byte/topeval.ml\", line 89, characters 4-150\n\u001b[0m" - ] - } - ], + "outputs": [], "source": [ "int_of_string \"not an int\"" ] }, { "cell_type": "markdown", - "id": "a9dcc2d4", + "id": "b851f9a1", "metadata": {}, "source": [ "There is no `char_of_string`, but the individual characters of a string can be\n", @@ -464,72 +316,41 @@ }, { "cell_type": "code", - "execution_count": 15, - "id": "ad79b011", + "execution_count": null, + "id": "b484274a", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : char = 'a'\n" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "\"abc\".[0]" ] }, { "cell_type": "code", - "execution_count": 16, - "id": "40a767c8", + "execution_count": null, + "id": "bf6f339b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : char = 'b'\n" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "\"abc\".[1]" ] }, { "cell_type": "code", - "execution_count": 17, - "id": "18b88212", + "execution_count": null, + "id": "4fb2dcee", "metadata": { "tags": [ "raises-exception" ] }, - "outputs": [ - { - "ename": "error", - "evalue": "runtime_error", - "output_type": "error", - "traceback": [ - "\u001b[31mException: Invalid_argument \"index out of bounds\".\nRaised by primitive operation at unknown location\nCalled from Stdlib__Fun.protect in file \"fun.ml\", line 33, characters 8-15\nRe-raised at Stdlib__Fun.protect in file \"fun.ml\", line 38, characters 6-52\nCalled from Topeval.load_lambda in file \"toplevel/byte/topeval.ml\", line 89, characters 4-150\n\u001b[0m" - ] - } - ], + "outputs": [], "source": [ "\"abc\".[3]" ] }, { "cell_type": "markdown", - "id": "f81a051b", + "id": "d5cc59da", "metadata": {}, "source": [ "## More Operators\n", @@ -559,6 +380,18 @@ "The unit value is written `()` and its type is `unit`. But if the result is\n", "`false`, an exception is raised.\n", "\n", + "One way to test a function `f` is to write a series of assertions like this:\n", + "\n", + "```ocaml\n", + "let () = assert (f input1 = output1)\n", + "let () = assert (f input2 = output2)\n", + "let () = assert (f input3 = output3)\n", + "```\n", + "\n", + "Those assert that `f input1` should be `output1`, and so forth. The\n", + "`let () = ...` part of those is used to handle the unit value returned by each\n", + "assertion.\n", + "\n", "## If Expressions\n", "\n", "{{ video_embed | replace(\"%%VID%%\", \"XJ6QPtlPD7s\")}}\n", @@ -569,28 +402,17 @@ }, { "cell_type": "code", - "execution_count": 18, - "id": "a146e149", + "execution_count": null, + "id": "b2fc8bd4", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : string = \"yay!\"\n" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "if 3 + 5 > 2 then \"yay!\" else \"boo!\"" ] }, { "cell_type": "markdown", - "id": "11c577a0", + "id": "0f969e2b", "metadata": {}, "source": [ "Unlike `if-then-else` *statements* that you may have used in imperative\n", @@ -602,28 +424,17 @@ }, { "cell_type": "code", - "execution_count": 19, - "id": "6a6e0df1", + "execution_count": null, + "id": "11a426b2", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : int = 6\n" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "4 + (if 'a' = 'b' then 1 else 2)" ] }, { "cell_type": "markdown", - "id": "0940b595", + "id": "138561d9", "metadata": {}, "source": [ "`If` expressions can be nested in a pleasant way:\n", @@ -643,30 +454,21 @@ }, { "cell_type": "code", - "execution_count": 20, - "id": "7838140c", + "execution_count": null, + "id": "ff5bc9a7", "metadata": { "tags": [ "raises-exception" ] }, - "outputs": [ - { - "ename": "error", - "evalue": "compile_error", - "output_type": "error", - "traceback": [ - "File \"[20]\", line 1, characters 14-15:\n1 | if 2 > 3 then 5\n ^\nError: This expression has type int but an expression was expected of type\n unit\n because it is in the result of a conditional with no else branch\n" - ] - } - ], + "outputs": [], "source": [ "if 2 > 3 then 5" ] }, { "cell_type": "markdown", - "id": "7525e8a6", + "id": "8e9cc30a", "metadata": {}, "source": [ "**Syntax.** The syntax of an `if` expression:\n", @@ -720,28 +522,17 @@ }, { "cell_type": "code", - "execution_count": 21, - "id": "137569eb", + "execution_count": null, + "id": "5753995e", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "val x : int = 42\n" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "let x = 42" ] }, { "cell_type": "markdown", - "id": "fd3e4637", + "id": "4f14c204", "metadata": {}, "source": [ "In the above example, variable `x` has type `int`, which is what the colon\n", @@ -757,28 +548,17 @@ }, { "cell_type": "code", - "execution_count": 22, - "id": "d4daf21f", + "execution_count": null, + "id": "6d1827b2", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "val x : int = 42\n" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "let x = 42;;" ] }, { "cell_type": "markdown", - "id": "afe49cb4", + "id": "9b53123d", "metadata": {}, "source": [ "defines `x` to be 42, after which we can use `x` in future definitions at the\n", @@ -789,28 +569,17 @@ }, { "cell_type": "code", - "execution_count": 23, - "id": "857c0017", + "execution_count": null, + "id": "bbaddbf1", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : int = 43\n" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "let x = 42 in x + 1" ] }, { "cell_type": "markdown", - "id": "46390426", + "id": "cc815014", "metadata": {}, "source": [ "Here we're *binding* a value to the name `x` then using that binding inside\n", @@ -822,30 +591,21 @@ }, { "cell_type": "code", - "execution_count": 24, - "id": "88a56cbd", + "execution_count": null, + "id": "cfbbf975", "metadata": { "tags": [ "raises-exception" ] }, - "outputs": [ - { - "ename": "error", - "evalue": "compile_error", - "output_type": "error", - "traceback": [ - "File \"[24]\", line 1, characters 11-12:\n1 | (let x = 42) + 1\n ^\nError: Syntax error\n" - ] - } - ], + "outputs": [], "source": [ "(let x = 42) + 1" ] }, { "cell_type": "markdown", - "id": "b05929fa", + "id": "fb0f3822", "metadata": {}, "source": [ "Syntactically, a `let` definition is not permitted on the left-hand side of the\n", @@ -855,28 +615,17 @@ }, { "cell_type": "code", - "execution_count": 25, - "id": "3c777d91", + "execution_count": null, + "id": "ed188654", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : int = 43\n" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "(let x = 42 in x) + 1" ] }, { "cell_type": "markdown", - "id": "140395bc", + "id": "eab2203d", "metadata": {}, "source": [ "Another way to understand let definitions at the toplevel is that they are like\n", @@ -1091,28 +840,17 @@ }, { "cell_type": "code", - "execution_count": 26, - "id": "f15b8dfd", + "execution_count": null, + "id": "f7860e0b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "- : int = 5\n" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "(5 : int)" ] }, { "cell_type": "markdown", - "id": "8fdc1157", + "id": "567d6143", "metadata": {}, "source": [ "An incorrect annotation will produce a compile-time error:" @@ -1120,30 +858,21 @@ }, { "cell_type": "code", - "execution_count": 27, - "id": "3ebbf874", + "execution_count": null, + "id": "1ecfd423", "metadata": { "tags": [ "raises-exception" ] }, - "outputs": [ - { - "ename": "error", - "evalue": "compile_error", - "output_type": "error", - "traceback": [ - "File \"[27]\", line 1, characters 1-2:\n1 | (5 : float)\n ^\nError: This expression has type int but an expression was expected of type\n float\n Hint: Did you mean `5.'?\n" - ] - } - ], + "outputs": [], "source": [ "(5 : float)" ] }, { "cell_type": "markdown", - "id": "a3391e4e", + "id": "1b68abb4", "metadata": {}, "source": [ "And that example shows why you might use manual type annotations during\n", @@ -1159,30 +888,21 @@ }, { "cell_type": "code", - "execution_count": 28, - "id": "a290852d", + "execution_count": null, + "id": "2fdf2af5", "metadata": { "tags": [ "raises-exception" ] }, - "outputs": [ - { - "ename": "error", - "evalue": "compile_error", - "output_type": "error", - "traceback": [ - "File \"[28]\", line 1, characters 1-2:\n1 | (5 : float) +. 1.1\n ^\nError: This expression has type int but an expression was expected of type\n float\n Hint: Did you mean `5.'?\n" - ] - } - ], + "outputs": [], "source": [ "(5 : float) +. 1.1" ] }, { "cell_type": "markdown", - "id": "cdd2604f", + "id": "fe8c9132", "metadata": {}, "source": [ "It's clear that the type annotation has failed. Although that might seem silly\n", @@ -1229,15 +949,6 @@ "language": "OCaml", "name": "ocaml-jupyter" }, - "language_info": { - "codemirror_mode": "text/x-ocaml", - "file_extension": ".ml", - "mimetype": "text/x-ocaml", - "name": "OCaml", - "nbconverter_exporter": null, - "pygments_lexer": "OCaml", - "version": "4.14.0" - }, "source_map": [ 14, 58, @@ -1266,28 +977,28 @@ 187, 191, 194, - 230, - 232, - 240, 242, - 258, - 263, - 313, - 315, + 244, + 252, + 254, + 270, + 275, 325, 327, - 332, - 334, - 340, - 343, - 347, - 349, - 560, - 562, - 566, - 569, + 337, + 339, + 344, + 346, + 352, + 355, + 359, + 361, + 572, + 574, + 578, 581, - 584 + 593, + 596 ] }, "nbformat": 4, diff --git a/_sources/chapters/basics/expressions.md b/_sources/chapters/basics/expressions.md index 5f0cd255..6d5caf0a 100644 --- a/_sources/chapters/basics/expressions.md +++ b/_sources/chapters/basics/expressions.md @@ -220,6 +220,18 @@ happens, and the entire expression evaluates to a special value called *unit*. The unit value is written `()` and its type is `unit`. But if the result is `false`, an exception is raised. +One way to test a function `f` is to write a series of assertions like this: + +```ocaml +let () = assert (f input1 = output1) +let () = assert (f input2 = output2) +let () = assert (f input3 = output3) +``` + +Those assert that `f input1` should be `output1`, and so forth. The +`let () = ...` part of those is used to handle the unit value returned by each +assertion. + ## If Expressions {{ video_embed | replace("%%VID%%", "XJ6QPtlPD7s")}} diff --git a/chapters/basics/expressions.html b/chapters/basics/expressions.html index 48bbf801..1b8bc74e 100644 --- a/chapters/basics/expressions.html +++ b/chapters/basics/expressions.html @@ -925,6 +925,15 @@
()
and its type is unit
. But if the result is
false
, an exception is raised.
+One way to test a function f
is to write a series of assertions like this:
let () = assert (f input1 = output1)
+let () = assert (f input2 = output2)
+let () = assert (f input3 = output3)
+
Those assert that f input1
should be output1
, and so forth. The
+let () = ...
part of those is used to handle the unit value returned by each
+assertion.