ocaml-programming

Simple OCaml programs
git clone git://git.laack.co/ocaml-programming.git
Log | Files | Refs | README

exercises_unit_1.ipynb (40808B)


      1 {
      2  "cells": [
      3   {
      4    "cell_type": "code",
      5    "execution_count": 1,
      6    "id": "e3d34281-2d39-48ec-8bc3-a257d071bd82",
      7    "metadata": {},
      8    "outputs": [
      9     {
     10      "data": {
     11       "text/plain": [
     12        "- : int = 0\n"
     13       ]
     14      },
     15      "execution_count": 1,
     16      "metadata": {},
     17      "output_type": "execute_result"
     18     }
     19    ],
     20    "source": [
     21     "Sys.command \"opam install -y qcheck > /tmp/opam.log 2>&1\";;"
     22    ]
     23   },
     24   {
     25    "cell_type": "code",
     26    "execution_count": 2,
     27    "id": "3fc0418a-4ca6-475a-b32a-7faa5527fbae",
     28    "metadata": {},
     29    "outputs": [
     30     {
     31      "data": {
     32       "text/plain": [
     33        "val cube : int -> int = <fun>\n"
     34       ]
     35      },
     36      "execution_count": 2,
     37      "metadata": {},
     38      "output_type": "execute_result"
     39     }
     40    ],
     41    "source": [
     42     "let cube n = n*n*n"
     43    ]
     44   },
     45   {
     46    "cell_type": "code",
     47    "execution_count": 3,
     48    "id": "a4db5988-0b39-4b2d-8bc9-952b16d54ad0",
     49    "metadata": {},
     50    "outputs": [
     51     {
     52      "data": {
     53       "text/plain": [
     54        "val fahrenheit_of_celsius : float -> float = <fun>\n"
     55       ]
     56      },
     57      "execution_count": 3,
     58      "metadata": {},
     59      "output_type": "execute_result"
     60     }
     61    ],
     62    "source": [
     63     "let fahrenheit_of_celsius (c : float) = (c *. (9. /. 5.)) +. 32."
     64    ]
     65   },
     66   {
     67    "cell_type": "code",
     68    "execution_count": 4,
     69    "id": "4dc8ee72-86ad-49dc-8d87-f11f129ea38d",
     70    "metadata": {},
     71    "outputs": [
     72     {
     73      "data": {
     74       "text/plain": [
     75        "- : float = 41.\n"
     76       ]
     77      },
     78      "execution_count": 4,
     79      "metadata": {},
     80      "output_type": "execute_result"
     81     }
     82    ],
     83    "source": [
     84     "fahrenheit_of_celsius 5."
     85    ]
     86   },
     87   {
     88    "cell_type": "code",
     89    "execution_count": 5,
     90    "id": "5b3adb38-ed81-4b18-abeb-97790f1bfee7",
     91    "metadata": {},
     92    "outputs": [],
     93    "source": [
     94     " (*  `sign n` returns -1 if n is negative, 0 if zero, 1 if positive.\n",
     95     "   Use nested if/then/else expressions and notice that every branch must\n",
     96     "   produce an int.\n",
     97     "*)"
     98    ]
     99   },
    100   {
    101    "cell_type": "code",
    102    "execution_count": 6,
    103    "id": "4ced9283-2066-4f6e-b14b-555a0271fb1b",
    104    "metadata": {},
    105    "outputs": [
    106     {
    107      "data": {
    108       "text/plain": [
    109        "val sign : int -> int = <fun>\n"
    110       ]
    111      },
    112      "execution_count": 6,
    113      "metadata": {},
    114      "output_type": "execute_result"
    115     }
    116    ],
    117    "source": [
    118     "let sign n = if n < 0 then -1\n",
    119     "    else if n = 0\n",
    120     "        then 0\n",
    121     "        else 1"
    122    ]
    123   },
    124   {
    125    "cell_type": "code",
    126    "execution_count": 7,
    127    "id": "4a78286a-4406-42f8-a103-1558a7b98e7c",
    128    "metadata": {},
    129    "outputs": [
    130     {
    131      "data": {
    132       "text/plain": [
    133        "- : int = 0\n"
    134       ]
    135      },
    136      "execution_count": 7,
    137      "metadata": {},
    138      "output_type": "execute_result"
    139     },
    140     {
    141      "data": {
    142       "text/plain": [
    143        "- : int = -1\n"
    144       ]
    145      },
    146      "execution_count": 7,
    147      "metadata": {},
    148      "output_type": "execute_result"
    149     },
    150     {
    151      "data": {
    152       "text/plain": [
    153        "- : int = 1\n"
    154       ]
    155      },
    156      "execution_count": 7,
    157      "metadata": {},
    158      "output_type": "execute_result"
    159     },
    160     {
    161      "data": {
    162       "text/plain": [
    163        "- : int = -1\n"
    164       ]
    165      },
    166      "execution_count": 7,
    167      "metadata": {},
    168      "output_type": "execute_result"
    169     },
    170     {
    171      "data": {
    172       "text/plain": [
    173        "- : int = 1\n"
    174       ]
    175      },
    176      "execution_count": 7,
    177      "metadata": {},
    178      "output_type": "execute_result"
    179     }
    180    ],
    181    "source": [
    182     "sign 0;;\n",
    183     "sign (-1);;\n",
    184     "sign 1;;\n",
    185     "sign (-1000);;\n",
    186     "sign 100000;;"
    187    ]
    188   },
    189   {
    190    "cell_type": "code",
    191    "execution_count": 8,
    192    "id": "ad9ac3d1-1f21-4764-95ad-06706a5043ab",
    193    "metadata": {},
    194    "outputs": [
    195     {
    196      "data": {
    197       "text/plain": [
    198        "val fib : int -> int = <fun>\n"
    199       ]
    200      },
    201      "execution_count": 8,
    202      "metadata": {},
    203      "output_type": "execute_result"
    204     }
    205    ],
    206    "source": [
    207     "let rec fib n = if n <= 1 then n else fib (n - 1) + fib (n - 2)\n"
    208    ]
    209   },
    210   {
    211    "cell_type": "code",
    212    "execution_count": 9,
    213    "id": "32f0fbe4-4a4a-44d5-9f71-4affc1bdec98",
    214    "metadata": {},
    215    "outputs": [
    216     {
    217      "data": {
    218       "text/plain": [
    219        "- : int = 0\n"
    220       ]
    221      },
    222      "execution_count": 9,
    223      "metadata": {},
    224      "output_type": "execute_result"
    225     },
    226     {
    227      "data": {
    228       "text/plain": [
    229        "- : int = 1\n"
    230       ]
    231      },
    232      "execution_count": 9,
    233      "metadata": {},
    234      "output_type": "execute_result"
    235     },
    236     {
    237      "data": {
    238       "text/plain": [
    239        "- : int = 1\n"
    240       ]
    241      },
    242      "execution_count": 9,
    243      "metadata": {},
    244      "output_type": "execute_result"
    245     },
    246     {
    247      "data": {
    248       "text/plain": [
    249        "- : int = 2\n"
    250       ]
    251      },
    252      "execution_count": 9,
    253      "metadata": {},
    254      "output_type": "execute_result"
    255     },
    256     {
    257      "data": {
    258       "text/plain": [
    259        "- : int = 3\n"
    260       ]
    261      },
    262      "execution_count": 9,
    263      "metadata": {},
    264      "output_type": "execute_result"
    265     }
    266    ],
    267    "source": [
    268     "fib 0;;\n",
    269     "fib 1;;\n",
    270     "fib 2;;\n",
    271     "fib 3;;\n",
    272     "fib 4;;"
    273    ]
    274   },
    275   {
    276    "cell_type": "code",
    277    "execution_count": 10,
    278    "id": "8808ba7e-f3ec-4f10-bd90-56c784c01f72",
    279    "metadata": {},
    280    "outputs": [
    281     {
    282      "data": {
    283       "text/plain": [
    284        "- : bool = true\n"
    285       ]
    286      },
    287      "execution_count": 10,
    288      "metadata": {},
    289      "output_type": "execute_result"
    290     },
    291     {
    292      "data": {
    293       "text/plain": [
    294        "- : bool = false\n"
    295       ]
    296      },
    297      "execution_count": 10,
    298      "metadata": {},
    299      "output_type": "execute_result"
    300     }
    301    ],
    302    "source": [
    303     "1.0 = 1.0;;\n",
    304     "1.0 == 1.0;;"
    305    ]
    306   },
    307   {
    308    "cell_type": "code",
    309    "execution_count": 11,
    310    "id": "be0aa1f3-2f8a-4ccb-93bd-5889ccb19fd1",
    311    "metadata": {},
    312    "outputs": [],
    313    "source": [
    314     "(* count digits non-tail recursive *)"
    315    ]
    316   },
    317   {
    318    "cell_type": "code",
    319    "execution_count": 12,
    320    "id": "0143fdea-b247-4af2-9311-6bcd955d6160",
    321    "metadata": {},
    322    "outputs": [
    323     {
    324      "data": {
    325       "text/plain": [
    326        "val count_digits : int -> int = <fun>\n"
    327       ]
    328      },
    329      "execution_count": 12,
    330      "metadata": {},
    331      "output_type": "execute_result"
    332     }
    333    ],
    334    "source": [
    335     "let rec count_digits n = if n < 0 then count_digits (n * (-1))\n",
    336     "    else if n > 9 \n",
    337     "        then count_digits (n / 10) + 1\n",
    338     "        else 1"
    339    ]
    340   },
    341   {
    342    "cell_type": "code",
    343    "execution_count": 13,
    344    "id": "319f2854-0d2d-466a-8e12-80cd5c14b5a0",
    345    "metadata": {},
    346    "outputs": [
    347     {
    348      "data": {
    349       "text/plain": [
    350        "- : int = 1\n"
    351       ]
    352      },
    353      "execution_count": 13,
    354      "metadata": {},
    355      "output_type": "execute_result"
    356     },
    357     {
    358      "data": {
    359       "text/plain": [
    360        "- : int = 3\n"
    361       ]
    362      },
    363      "execution_count": 13,
    364      "metadata": {},
    365      "output_type": "execute_result"
    366     },
    367     {
    368      "data": {
    369       "text/plain": [
    370        "- : int = 2\n"
    371       ]
    372      },
    373      "execution_count": 13,
    374      "metadata": {},
    375      "output_type": "execute_result"
    376     },
    377     {
    378      "data": {
    379       "text/plain": [
    380        "- : int = 1\n"
    381       ]
    382      },
    383      "execution_count": 13,
    384      "metadata": {},
    385      "output_type": "execute_result"
    386     },
    387     {
    388      "data": {
    389       "text/plain": [
    390        "- : int = 3\n"
    391       ]
    392      },
    393      "execution_count": 13,
    394      "metadata": {},
    395      "output_type": "execute_result"
    396     },
    397     {
    398      "data": {
    399       "text/plain": [
    400        "- : int = 4\n"
    401       ]
    402      },
    403      "execution_count": 13,
    404      "metadata": {},
    405      "output_type": "execute_result"
    406     },
    407     {
    408      "data": {
    409       "text/plain": [
    410        "- : int = 1\n"
    411       ]
    412      },
    413      "execution_count": 13,
    414      "metadata": {},
    415      "output_type": "execute_result"
    416     }
    417    ],
    418    "source": [
    419     "count_digits 0;;\n",
    420     "count_digits 100;;\n",
    421     "count_digits 10;;\n",
    422     "count_digits 9;;\n",
    423     "count_digits (-102);;\n",
    424     "count_digits (-1002);;\n",
    425     "count_digits (-1);;"
    426    ]
    427   },
    428   {
    429    "cell_type": "code",
    430    "execution_count": 14,
    431    "id": "a2ec41ef-f24f-485a-9ee6-ab04fcbe301a",
    432    "metadata": {},
    433    "outputs": [],
    434    "source": [
    435     "(* count digits tail recursive *)"
    436    ]
    437   },
    438   {
    439    "cell_type": "code",
    440    "execution_count": 15,
    441    "id": "880519a5-6abe-4622-9d00-cd8d6f7a0b71",
    442    "metadata": {},
    443    "outputs": [
    444     {
    445      "data": {
    446       "text/plain": [
    447        "val cnt : int -> int -> int = <fun>\n"
    448       ]
    449      },
    450      "execution_count": 15,
    451      "metadata": {},
    452      "output_type": "execute_result"
    453     },
    454     {
    455      "data": {
    456       "text/plain": [
    457        "val count_digits : int -> int = <fun>\n"
    458       ]
    459      },
    460      "execution_count": 15,
    461      "metadata": {},
    462      "output_type": "execute_result"
    463     }
    464    ],
    465    "source": [
    466     "let rec cnt acc n = \n",
    467     "    if n < 0 then cnt 0 (n * (-1))\n",
    468     "    else if n > 9 \n",
    469     "        then cnt (acc + 1) (n / 10)\n",
    470     "        else (acc + 1)\n",
    471     "\n",
    472     "let count_digits = cnt 0"
    473    ]
    474   },
    475   {
    476    "cell_type": "code",
    477    "execution_count": 16,
    478    "id": "63a70c83-ff18-4d95-82e2-89d4b1b05d95",
    479    "metadata": {},
    480    "outputs": [
    481     {
    482      "data": {
    483       "text/plain": [
    484        "- : int = 1\n"
    485       ]
    486      },
    487      "execution_count": 16,
    488      "metadata": {},
    489      "output_type": "execute_result"
    490     },
    491     {
    492      "data": {
    493       "text/plain": [
    494        "- : int = 3\n"
    495       ]
    496      },
    497      "execution_count": 16,
    498      "metadata": {},
    499      "output_type": "execute_result"
    500     },
    501     {
    502      "data": {
    503       "text/plain": [
    504        "- : int = 2\n"
    505       ]
    506      },
    507      "execution_count": 16,
    508      "metadata": {},
    509      "output_type": "execute_result"
    510     },
    511     {
    512      "data": {
    513       "text/plain": [
    514        "- : int = 1\n"
    515       ]
    516      },
    517      "execution_count": 16,
    518      "metadata": {},
    519      "output_type": "execute_result"
    520     },
    521     {
    522      "data": {
    523       "text/plain": [
    524        "- : int = 3\n"
    525       ]
    526      },
    527      "execution_count": 16,
    528      "metadata": {},
    529      "output_type": "execute_result"
    530     },
    531     {
    532      "data": {
    533       "text/plain": [
    534        "- : int = 4\n"
    535       ]
    536      },
    537      "execution_count": 16,
    538      "metadata": {},
    539      "output_type": "execute_result"
    540     },
    541     {
    542      "data": {
    543       "text/plain": [
    544        "- : int = 1\n"
    545       ]
    546      },
    547      "execution_count": 16,
    548      "metadata": {},
    549      "output_type": "execute_result"
    550     }
    551    ],
    552    "source": [
    553     "count_digits 0;;\n",
    554     "count_digits 100;;\n",
    555     "count_digits 10;;\n",
    556     "count_digits 9;;\n",
    557     "count_digits (-102);;\n",
    558     "count_digits (-1002);;\n",
    559     "count_digits (-1);;"
    560    ]
    561   },
    562   {
    563    "cell_type": "code",
    564    "execution_count": 17,
    565    "id": "581edd75-6dac-4cc3-937c-e16797b9fd9e",
    566    "metadata": {},
    567    "outputs": [],
    568    "source": [
    569     " (*  `fib_fast n` computes the same thing but must be *tail recursive* and run\n",
    570     "   in linear time. Use an inner `let rec go ... in` helper carrying two\n",
    571     "   accumulators (the previous two Fibonacci numbers).\n",
    572     "   It must handle fib_fast 1_000_000 without overflowing the stack (the\n",
    573     "   number itself will wrap around, that is fine, we only care about space). *)"
    574    ]
    575   },
    576   {
    577    "cell_type": "code",
    578    "execution_count": 18,
    579    "id": "01137212-a52f-4100-9398-989af9a70387",
    580    "metadata": {},
    581    "outputs": [
    582     {
    583      "data": {
    584       "text/plain": [
    585        "val fib_fast : int -> int = <fun>\n"
    586       ]
    587      },
    588      "execution_count": 18,
    589      "metadata": {},
    590      "output_type": "execute_result"
    591     }
    592    ],
    593    "source": [
    594     "let fib_fast m = \n",
    595     "    let rec go n min_one min_two  = \n",
    596     "        if n >= m\n",
    597     "            then \n",
    598     "                if n = 1 then m\n",
    599     "                else min_one + min_two\n",
    600     "            else go (n + 1) min_two (min_one + min_two) in\n",
    601     "    go 1 1 0"
    602    ]
    603   },
    604   {
    605    "cell_type": "code",
    606    "execution_count": 19,
    607    "id": "7286b831-9e71-4861-b062-ede92b0405aa",
    608    "metadata": {},
    609    "outputs": [
    610     {
    611      "data": {
    612       "text/plain": [
    613        "- : int = 0\n"
    614       ]
    615      },
    616      "execution_count": 19,
    617      "metadata": {},
    618      "output_type": "execute_result"
    619     },
    620     {
    621      "data": {
    622       "text/plain": [
    623        "- : int = 1\n"
    624       ]
    625      },
    626      "execution_count": 19,
    627      "metadata": {},
    628      "output_type": "execute_result"
    629     },
    630     {
    631      "data": {
    632       "text/plain": [
    633        "- : int = 1\n"
    634       ]
    635      },
    636      "execution_count": 19,
    637      "metadata": {},
    638      "output_type": "execute_result"
    639     },
    640     {
    641      "data": {
    642       "text/plain": [
    643        "- : int = 2\n"
    644       ]
    645      },
    646      "execution_count": 19,
    647      "metadata": {},
    648      "output_type": "execute_result"
    649     },
    650     {
    651      "data": {
    652       "text/plain": [
    653        "- : int = 3\n"
    654       ]
    655      },
    656      "execution_count": 19,
    657      "metadata": {},
    658      "output_type": "execute_result"
    659     },
    660     {
    661      "data": {
    662       "text/plain": [
    663        "- : int = 5\n"
    664       ]
    665      },
    666      "execution_count": 19,
    667      "metadata": {},
    668      "output_type": "execute_result"
    669     },
    670     {
    671      "data": {
    672       "text/plain": [
    673        "- : int = 8\n"
    674       ]
    675      },
    676      "execution_count": 19,
    677      "metadata": {},
    678      "output_type": "execute_result"
    679     },
    680     {
    681      "data": {
    682       "text/plain": [
    683        "- : int = 13\n"
    684       ]
    685      },
    686      "execution_count": 19,
    687      "metadata": {},
    688      "output_type": "execute_result"
    689     },
    690     {
    691      "data": {
    692       "text/plain": [
    693        "- : int = 21\n"
    694       ]
    695      },
    696      "execution_count": 19,
    697      "metadata": {},
    698      "output_type": "execute_result"
    699     },
    700     {
    701      "data": {
    702       "text/plain": [
    703        "- : int = 34\n"
    704       ]
    705      },
    706      "execution_count": 19,
    707      "metadata": {},
    708      "output_type": "execute_result"
    709     },
    710     {
    711      "data": {
    712       "text/plain": [
    713        "- : int = 55\n"
    714       ]
    715      },
    716      "execution_count": 19,
    717      "metadata": {},
    718      "output_type": "execute_result"
    719     }
    720    ],
    721    "source": [
    722     "fib_fast 0;;\n",
    723     "fib_fast 1;;\n",
    724     "fib_fast 2;;\n",
    725     "fib_fast 3;;\n",
    726     "fib_fast 4;;\n",
    727     "fib_fast 5;;\n",
    728     "fib_fast 6;;\n",
    729     "fib_fast 7;;\n",
    730     "fib_fast 8;;\n",
    731     "fib_fast 9;;\n",
    732     "fib_fast 10;;"
    733    ]
    734   },
    735   {
    736    "cell_type": "code",
    737    "execution_count": 20,
    738    "id": "c3ebcf22-4a49-48a8-8fb7-b9635c305647",
    739    "metadata": {},
    740    "outputs": [
    741     {
    742      "data": {
    743       "text/plain": [
    744        "val power : int -> int -> int = <fun>\n"
    745       ]
    746      },
    747      "execution_count": 20,
    748      "metadata": {},
    749      "output_type": "execute_result"
    750     }
    751    ],
    752    "source": [
    753     "let power base exp = \n",
    754     "    let rec go acc exp = \n",
    755     "        if exp <= 0\n",
    756     "            then acc\n",
    757     "            else go (acc * base) (exp - 1) in\n",
    758     "        go 1 exp"
    759    ]
    760   },
    761   {
    762    "cell_type": "code",
    763    "execution_count": 21,
    764    "id": "5aa3f86f-5cc4-43ef-ba1b-ce7395c5fd45",
    765    "metadata": {},
    766    "outputs": [
    767     {
    768      "data": {
    769       "text/plain": [
    770        "- : int = 1\n"
    771       ]
    772      },
    773      "execution_count": 21,
    774      "metadata": {},
    775      "output_type": "execute_result"
    776     },
    777     {
    778      "data": {
    779       "text/plain": [
    780        "- : int = 2\n"
    781       ]
    782      },
    783      "execution_count": 21,
    784      "metadata": {},
    785      "output_type": "execute_result"
    786     },
    787     {
    788      "data": {
    789       "text/plain": [
    790        "- : int = 4\n"
    791       ]
    792      },
    793      "execution_count": 21,
    794      "metadata": {},
    795      "output_type": "execute_result"
    796     },
    797     {
    798      "data": {
    799       "text/plain": [
    800        "- : int = 8\n"
    801       ]
    802      },
    803      "execution_count": 21,
    804      "metadata": {},
    805      "output_type": "execute_result"
    806     },
    807     {
    808      "data": {
    809       "text/plain": [
    810        "- : int = 9\n"
    811       ]
    812      },
    813      "execution_count": 21,
    814      "metadata": {},
    815      "output_type": "execute_result"
    816     }
    817    ],
    818    "source": [
    819     "power 2 0;;\n",
    820     "power 2 1;;\n",
    821     "power 2 2;;\n",
    822     "power 2 3;;\n",
    823     "power 3 2;;"
    824    ]
    825   },
    826   {
    827    "cell_type": "code",
    828    "execution_count": 22,
    829    "id": "3ab5d14e-6518-4ecf-a4a7-a19902ca49ec",
    830    "metadata": {},
    831    "outputs": [],
    832    "source": [
    833     "(*   `compose f g` returns the function that applies g first, then f.\n",
    834     "   Write no type annotation. The inferred type should be\n",
    835     "     ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b\n",
    836     "   which is your first taste of polymorphism falling out of inference. *)"
    837    ]
    838   },
    839   {
    840    "cell_type": "code",
    841    "execution_count": 23,
    842    "id": "69f16a49-d963-4f27-96ea-6180931a3ea9",
    843    "metadata": {},
    844    "outputs": [
    845     {
    846      "data": {
    847       "text/plain": [
    848        "val compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>\n"
    849       ]
    850      },
    851      "execution_count": 23,
    852      "metadata": {},
    853      "output_type": "execute_result"
    854     }
    855    ],
    856    "source": [
    857     "let compose f g = fun x -> f (g x);;"
    858    ]
    859   },
    860   {
    861    "cell_type": "code",
    862    "execution_count": 24,
    863    "id": "e6a0ad52-5b27-4384-9d3e-c320eace2da2",
    864    "metadata": {},
    865    "outputs": [
    866     {
    867      "data": {
    868       "text/plain": [
    869        "- : int = 13\n"
    870       ]
    871      },
    872      "execution_count": 24,
    873      "metadata": {},
    874      "output_type": "execute_result"
    875     }
    876    ],
    877    "source": [
    878     "compose succ (( * ) 3) 4    (* = 13 *)"
    879    ]
    880   },
    881   {
    882    "cell_type": "code",
    883    "execution_count": 25,
    884    "id": "578a49bd-e885-4107-8cc7-553dc5c70a79",
    885    "metadata": {},
    886    "outputs": [
    887     {
    888      "data": {
    889       "text/plain": [
    890        "val gcd : int -> int -> int = <fun>\n"
    891       ]
    892      },
    893      "execution_count": 25,
    894      "metadata": {},
    895      "output_type": "execute_result"
    896     }
    897    ],
    898    "source": [
    899     "let rec gcd a b = \n",
    900     "    if b = 0 then a\n",
    901     "    else gcd b (a mod b)"
    902    ]
    903   },
    904   {
    905    "cell_type": "code",
    906    "execution_count": 26,
    907    "id": "dfce273a-8c44-49c0-9011-6db991bec36f",
    908    "metadata": {},
    909    "outputs": [
    910     {
    911      "data": {
    912       "text/plain": [
    913        "- : int = 6\n"
    914       ]
    915      },
    916      "execution_count": 26,
    917      "metadata": {},
    918      "output_type": "execute_result"
    919     },
    920     {
    921      "data": {
    922       "text/plain": [
    923        "- : int = 6\n"
    924       ]
    925      },
    926      "execution_count": 26,
    927      "metadata": {},
    928      "output_type": "execute_result"
    929     },
    930     {
    931      "data": {
    932       "text/plain": [
    933        "- : int = 1\n"
    934       ]
    935      },
    936      "execution_count": 26,
    937      "metadata": {},
    938      "output_type": "execute_result"
    939     },
    940     {
    941      "data": {
    942       "text/plain": [
    943        "- : int = 5\n"
    944       ]
    945      },
    946      "execution_count": 26,
    947      "metadata": {},
    948      "output_type": "execute_result"
    949     }
    950    ],
    951    "source": [
    952     "gcd 12 18;;\n",
    953     "gcd 270 192;;\n",
    954     "gcd 17 15;;\n",
    955     "gcd 0 5;;"
    956    ]
    957   },
    958   {
    959    "cell_type": "code",
    960    "execution_count": 27,
    961    "id": "71305179-f9ac-4684-8490-ba55e1aa5b96",
    962    "metadata": {},
    963    "outputs": [],
    964    "source": [
    965     "(* --- 17 ------------------------------------------------------------------\n",
    966     "   `repeat f n x` applies f to x exactly n times: repeat f 3 x = f (f (f x)).\n",
    967     "   repeat f 0 x = x. Must work for any type, so again no annotations.\n",
    968     "   This is your accumulator pattern with a *function* as the thing being\n",
    969     "   applied. *)"
    970    ]
    971   },
    972   {
    973    "cell_type": "code",
    974    "execution_count": 28,
    975    "id": "068252f8-1ae0-4bce-8c73-e1da077b268b",
    976    "metadata": {},
    977    "outputs": [
    978     {
    979      "data": {
    980       "text/plain": [
    981        "val repeat : ('a -> 'a) -> int -> 'a -> 'a = <fun>\n"
    982       ]
    983      },
    984      "execution_count": 28,
    985      "metadata": {},
    986      "output_type": "execute_result"
    987     }
    988    ],
    989    "source": [
    990     "let rec repeat f n x = \n",
    991     "    if n = 0\n",
    992     "        then x\n",
    993     "        else repeat f (n - 1) (f x)"
    994    ]
    995   },
    996   {
    997    "cell_type": "code",
    998    "execution_count": 29,
    999    "id": "cf8b242f-0a0b-4169-af6e-74370bbda435",
   1000    "metadata": {},
   1001    "outputs": [
   1002     {
   1003      "data": {
   1004       "text/plain": [
   1005        "val add_5 : int -> int = <fun>\n"
   1006       ]
   1007      },
   1008      "execution_count": 29,
   1009      "metadata": {},
   1010      "output_type": "execute_result"
   1011     },
   1012     {
   1013      "data": {
   1014       "text/plain": [
   1015        "- : int = 52\n"
   1016       ]
   1017      },
   1018      "execution_count": 29,
   1019      "metadata": {},
   1020      "output_type": "execute_result"
   1021     }
   1022    ],
   1023    "source": [
   1024     "let add_5 x = x + 5;;\n",
   1025     "\n",
   1026     "repeat add_5 10 2;;"
   1027    ]
   1028   },
   1029   {
   1030    "cell_type": "code",
   1031    "execution_count": 30,
   1032    "id": "5b4f9d85-d6d6-4b9f-8bef-067b9df432cd",
   1033    "metadata": {},
   1034    "outputs": [],
   1035    "source": [
   1036     "(* --- 10 ------------------------------------------------------------------\n",
   1037     "   NEW IDEA: an accumulator that *builds a value* rather than counting one.\n",
   1038     "\n",
   1039     "   `reverse_int n` reverses the decimal digits of n, for n >= 0. Leading\n",
   1040     "   zeros simply disappear, since the result is a number, not text.\n",
   1041     "\n",
   1042     "       reverse_int 1234 = 4321    reverse_int 1200 = 21\n",
   1043     "       reverse_int 7 = 7          reverse_int 0 = 0\n",
   1044     "\n",
   1045     "   Tail recursive. Each step peels one digit off n with `mod 10` and pushes\n",
   1046     "   it onto the accumulator. Pushing a digit onto a number is the arithmetic\n",
   1047     "   you have to work out.\n",
   1048     "\n",
   1049     "   Once this works, note that `reverse_int n = n` is a palindrome test. *)"
   1050    ]
   1051   },
   1052   {
   1053    "cell_type": "code",
   1054    "execution_count": 31,
   1055    "id": "12e04876-a113-4f9c-8ab5-b1c0065f058a",
   1056    "metadata": {},
   1057    "outputs": [
   1058     {
   1059      "data": {
   1060       "text/plain": [
   1061        "val reverse_int : int -> int = <fun>\n"
   1062       ]
   1063      },
   1064      "execution_count": 31,
   1065      "metadata": {},
   1066      "output_type": "execute_result"
   1067     }
   1068    ],
   1069    "source": [
   1070     "let reverse_int n = \n",
   1071     "    let rec go ret_val running =\n",
   1072     "        if running = 0\n",
   1073     "            then ret_val\n",
   1074     "        else\n",
   1075     "            go (ret_val * 10 + ((running mod 10))) (running / 10)\n",
   1076     "        in\n",
   1077     "    go 0 n"
   1078    ]
   1079   },
   1080   {
   1081    "cell_type": "code",
   1082    "execution_count": 32,
   1083    "id": "6bf2e53b-922f-4beb-a3d7-0e3b27887e7e",
   1084    "metadata": {},
   1085    "outputs": [
   1086     {
   1087      "data": {
   1088       "text/plain": [
   1089        "- : int = 7\n"
   1090       ]
   1091      },
   1092      "execution_count": 32,
   1093      "metadata": {},
   1094      "output_type": "execute_result"
   1095     },
   1096     {
   1097      "data": {
   1098       "text/plain": [
   1099        "- : int = 4321\n"
   1100       ]
   1101      },
   1102      "execution_count": 32,
   1103      "metadata": {},
   1104      "output_type": "execute_result"
   1105     },
   1106     {
   1107      "data": {
   1108       "text/plain": [
   1109        "- : int = 21\n"
   1110       ]
   1111      },
   1112      "execution_count": 32,
   1113      "metadata": {},
   1114      "output_type": "execute_result"
   1115     },
   1116     {
   1117      "data": {
   1118       "text/plain": [
   1119        "- : int = 0\n"
   1120       ]
   1121      },
   1122      "execution_count": 32,
   1123      "metadata": {},
   1124      "output_type": "execute_result"
   1125     },
   1126     {
   1127      "data": {
   1128       "text/plain": [
   1129        "- : int = 921\n"
   1130       ]
   1131      },
   1132      "execution_count": 32,
   1133      "metadata": {},
   1134      "output_type": "execute_result"
   1135     }
   1136    ],
   1137    "source": [
   1138     "reverse_int 700;;\n",
   1139     "reverse_int 1234;;\n",
   1140     "reverse_int 1200;;\n",
   1141     "reverse_int 0;;\n",
   1142     "reverse_int 1290;;"
   1143    ]
   1144   },
   1145   {
   1146    "cell_type": "code",
   1147    "execution_count": 33,
   1148    "id": "36ad5f0c-0db0-4297-b7dc-92038a2d50f7",
   1149    "metadata": {},
   1150    "outputs": [
   1151     {
   1152      "data": {
   1153       "text/plain": [
   1154        "- : int = 11\n"
   1155       ]
   1156      },
   1157      "execution_count": 33,
   1158      "metadata": {},
   1159      "output_type": "execute_result"
   1160     }
   1161    ],
   1162    "source": [
   1163     "let x = 5 in ((let x = 6 in x) + x)"
   1164    ]
   1165   },
   1166   {
   1167    "cell_type": "code",
   1168    "execution_count": 34,
   1169    "id": "3692ddcf-fc68-4657-9a46-991ab5d0f10d",
   1170    "metadata": {},
   1171    "outputs": [
   1172     {
   1173      "data": {
   1174       "text/plain": [
   1175        "- : int = 2\n"
   1176       ]
   1177      },
   1178      "execution_count": 34,
   1179      "metadata": {},
   1180      "output_type": "execute_result"
   1181     }
   1182    ],
   1183    "source": [
   1184     "(fun x -> x + 1) 1;;"
   1185    ]
   1186   },
   1187   {
   1188    "cell_type": "code",
   1189    "execution_count": 35,
   1190    "id": "8d938958-ba4f-481a-9b48-08d81d75bd78",
   1191    "metadata": {},
   1192    "outputs": [
   1193     {
   1194      "data": {
   1195       "text/plain": [
   1196        "val add_2 : int -> int = <fun>\n"
   1197       ]
   1198      },
   1199      "execution_count": 35,
   1200      "metadata": {},
   1201      "output_type": "execute_result"
   1202     },
   1203     {
   1204      "data": {
   1205       "text/plain": [
   1206        "val sub_1 : int -> int = <fun>\n"
   1207       ]
   1208      },
   1209      "execution_count": 35,
   1210      "metadata": {},
   1211      "output_type": "execute_result"
   1212     },
   1213     {
   1214      "data": {
   1215       "text/plain": [
   1216        "val mul_2 : int -> int = <fun>\n"
   1217       ]
   1218      },
   1219      "execution_count": 35,
   1220      "metadata": {},
   1221      "output_type": "execute_result"
   1222     },
   1223     {
   1224      "data": {
   1225       "text/plain": [
   1226        "- : int = 6\n"
   1227       ]
   1228      },
   1229      "execution_count": 35,
   1230      "metadata": {},
   1231      "output_type": "execute_result"
   1232     }
   1233    ],
   1234    "source": [
   1235     "let add_2 x = x + 2;;\n",
   1236     "let sub_1 x = x - 1;;\n",
   1237     "let mul_2 x = x * 2;;\n",
   1238     "\n",
   1239     "mul_2 (sub_1 (add_2 2));; \n",
   1240     "\n",
   1241     "(* Parenthesis needed above. *)"
   1242    ]
   1243   },
   1244   {
   1245    "cell_type": "code",
   1246    "execution_count": 36,
   1247    "id": "6b097ffd-fb7d-4694-b61a-9c7105c632e1",
   1248    "metadata": {},
   1249    "outputs": [],
   1250    "source": [
   1251     "(* 13\n",
   1252     "\n",
   1253     "NEW IDEA: the shape of the recursion changes the complexity class.\n",
   1254     "\n",
   1255     "power in 8 does exp multiplications. power_fast must do about log2(exp) of\n",
   1256     "them, by squaring:\n",
   1257     "\n",
   1258     "    b^e = (b*b)^(e/2)          when e is even\n",
   1259     "    b^e = b * (b*b)^(e/2)      when e is odd, using integer division\n",
   1260     "\n",
   1261     "Each step halves the exponent instead of decrementing it. Tail recursive, so\n",
   1262     "carry the collected-so-far factor in an accumulator.\n",
   1263     "\n",
   1264     "power_fast 2 10 = 1024, power_fast 3 5 = 243, power_fast 7 0 = 1,\n",
   1265     "power_fast 2 61 = 2305843009213693952.\n",
   1266     "\n",
   1267     "Then try power_fast 2 1_000_000_000. A linear version would still be running\n",
   1268     "tomorrow; a logarithmic one finishes instantly. That difference is the test.\n",
   1269     "\n",
   1270     "*)"
   1271    ]
   1272   },
   1273   {
   1274    "cell_type": "code",
   1275    "execution_count": 37,
   1276    "id": "16b79160-9c4c-414f-9e06-475b088d02a4",
   1277    "metadata": {},
   1278    "outputs": [
   1279     {
   1280      "data": {
   1281       "text/plain": [
   1282        "val power_fast : int -> int -> int = <fun>\n"
   1283       ]
   1284      },
   1285      "execution_count": 37,
   1286      "metadata": {},
   1287      "output_type": "execute_result"
   1288     }
   1289    ],
   1290    "source": [
   1291     "let power_fast base exp = \n",
   1292     "    let rec go acc base exp =\n",
   1293     "        if exp = 0\n",
   1294     "            then\n",
   1295     "                acc   \n",
   1296     "            else\n",
   1297     "                if exp mod 2 = 0\n",
   1298     "                     then\n",
   1299     "                        go acc (base * base) (exp / 2)\n",
   1300     "                    else\n",
   1301     "                        go (acc * base) (base * base) ((exp - 1) / 2)\n",
   1302     "    in go 1 base exp\n",
   1303     "        "
   1304    ]
   1305   },
   1306   {
   1307    "cell_type": "code",
   1308    "execution_count": 38,
   1309    "id": "2ebe0d8f-7740-440e-8dfb-51d851f91de9",
   1310    "metadata": {},
   1311    "outputs": [
   1312     {
   1313      "data": {
   1314       "text/plain": [
   1315        "- : int = 3125\n"
   1316       ]
   1317      },
   1318      "execution_count": 38,
   1319      "metadata": {},
   1320      "output_type": "execute_result"
   1321     },
   1322     {
   1323      "data": {
   1324       "text/plain": [
   1325        "- : int = 25\n"
   1326       ]
   1327      },
   1328      "execution_count": 38,
   1329      "metadata": {},
   1330      "output_type": "execute_result"
   1331     },
   1332     {
   1333      "data": {
   1334       "text/plain": [
   1335        "- : int = 1\n"
   1336       ]
   1337      },
   1338      "execution_count": 38,
   1339      "metadata": {},
   1340      "output_type": "execute_result"
   1341     },
   1342     {
   1343      "data": {
   1344       "text/plain": [
   1345        "- : int = 5\n"
   1346       ]
   1347      },
   1348      "execution_count": 38,
   1349      "metadata": {},
   1350      "output_type": "execute_result"
   1351     },
   1352     {
   1353      "data": {
   1354       "text/plain": [
   1355        "- : int = 1\n"
   1356       ]
   1357      },
   1358      "execution_count": 38,
   1359      "metadata": {},
   1360      "output_type": "execute_result"
   1361     },
   1362     {
   1363      "data": {
   1364       "text/plain": [
   1365        "- : int = 2\n"
   1366       ]
   1367      },
   1368      "execution_count": 38,
   1369      "metadata": {},
   1370      "output_type": "execute_result"
   1371     },
   1372     {
   1373      "data": {
   1374       "text/plain": [
   1375        "- : int = 4\n"
   1376       ]
   1377      },
   1378      "execution_count": 38,
   1379      "metadata": {},
   1380      "output_type": "execute_result"
   1381     },
   1382     {
   1383      "data": {
   1384       "text/plain": [
   1385        "- : int = 243\n"
   1386       ]
   1387      },
   1388      "execution_count": 38,
   1389      "metadata": {},
   1390      "output_type": "execute_result"
   1391     },
   1392     {
   1393      "data": {
   1394       "text/plain": [
   1395        "- : int = 243\n"
   1396       ]
   1397      },
   1398      "execution_count": 38,
   1399      "metadata": {},
   1400      "output_type": "execute_result"
   1401     },
   1402     {
   1403      "data": {
   1404       "text/plain": [
   1405        "- : int = 81\n"
   1406       ]
   1407      },
   1408      "execution_count": 38,
   1409      "metadata": {},
   1410      "output_type": "execute_result"
   1411     },
   1412     {
   1413      "data": {
   1414       "text/plain": [
   1415        "- : int = 243\n"
   1416       ]
   1417      },
   1418      "execution_count": 38,
   1419      "metadata": {},
   1420      "output_type": "execute_result"
   1421     }
   1422    ],
   1423    "source": [
   1424     "power_fast 5 5;;\n",
   1425     "power_fast 5 2;;\n",
   1426     "power_fast 5 0;;\n",
   1427     "power_fast 5 1;;\n",
   1428     "\n",
   1429     "power_fast 2 0;;\n",
   1430     "power_fast 2 1;;\n",
   1431     "power_fast 2 2;;\n",
   1432     "\n",
   1433     "power_fast 3 5;;\n",
   1434     "\n",
   1435     "27 * power_fast 3 2;;\n",
   1436     "27 * 3;;\n",
   1437     "81 * 3;;"
   1438    ]
   1439   },
   1440   {
   1441    "cell_type": "code",
   1442    "execution_count": 39,
   1443    "id": "bbe1a653-56d1-4d96-a13a-692e0d5296bf",
   1444    "metadata": {},
   1445    "outputs": [],
   1446    "source": [
   1447     "(* 12\n",
   1448     "\n",
   1449     "NEW IDEA: mutual recursion. Two functions that call each other are defined\n",
   1450     "together, joined by and:\n",
   1451     "\n",
   1452     "    let rec f x = ... g ... and g x = ... f ...\n",
   1453     "\n",
   1454     "Define is_even and is_odd for n >= 0 without using mod, division, or each\n",
   1455     "other's arithmetic, only by counting down and handing off to the other\n",
   1456     "function. Both must be tail recursive, so is_even 1_000_000 must not overflow\n",
   1457     "the stack.\n",
   1458     "\n",
   1459     "is_even 0 = true, is_odd 0 = false, is_even 7 = false, is_odd 7 = true.\n",
   1460     "\n",
   1461     "*)"
   1462    ]
   1463   },
   1464   {
   1465    "cell_type": "code",
   1466    "execution_count": 40,
   1467    "id": "71055e50-d3d3-4511-87c5-955f181dd788",
   1468    "metadata": {},
   1469    "outputs": [
   1470     {
   1471      "data": {
   1472       "text/plain": [
   1473        "val is_even : int -> bool = <fun>\n",
   1474        "val is_odd : int -> bool = <fun>\n"
   1475       ]
   1476      },
   1477      "execution_count": 40,
   1478      "metadata": {},
   1479      "output_type": "execute_result"
   1480     }
   1481    ],
   1482    "source": [
   1483     "let rec is_even n = \n",
   1484     "    if n = 0 \n",
   1485     "        then true\n",
   1486     "        else is_odd (n - 1)\n",
   1487     "and is_odd n = \n",
   1488     "        if n = 0 \n",
   1489     "        then false\n",
   1490     "        else is_even (n - 1)\n",
   1491     "(* \n",
   1492     "This is tail recursive because no further computations are required\n",
   1493     "once the invoked function returns to the caller\n",
   1494     "*)"
   1495    ]
   1496   },
   1497   {
   1498    "cell_type": "code",
   1499    "execution_count": 41,
   1500    "id": "1d868719-1713-4448-9493-dd5e3063b242",
   1501    "metadata": {},
   1502    "outputs": [
   1503     {
   1504      "data": {
   1505       "text/plain": [
   1506        "- : bool = true\n"
   1507       ]
   1508      },
   1509      "execution_count": 41,
   1510      "metadata": {},
   1511      "output_type": "execute_result"
   1512     },
   1513     {
   1514      "data": {
   1515       "text/plain": [
   1516        "- : bool = false\n"
   1517       ]
   1518      },
   1519      "execution_count": 41,
   1520      "metadata": {},
   1521      "output_type": "execute_result"
   1522     },
   1523     {
   1524      "data": {
   1525       "text/plain": [
   1526        "- : bool = true\n"
   1527       ]
   1528      },
   1529      "execution_count": 41,
   1530      "metadata": {},
   1531      "output_type": "execute_result"
   1532     },
   1533     {
   1534      "data": {
   1535       "text/plain": [
   1536        "- : bool = false\n"
   1537       ]
   1538      },
   1539      "execution_count": 41,
   1540      "metadata": {},
   1541      "output_type": "execute_result"
   1542     },
   1543     {
   1544      "data": {
   1545       "text/plain": [
   1546        "- : bool = true\n"
   1547       ]
   1548      },
   1549      "execution_count": 41,
   1550      "metadata": {},
   1551      "output_type": "execute_result"
   1552     }
   1553    ],
   1554    "source": [
   1555     "is_even 0;;\n",
   1556     "is_even 1;;\n",
   1557     "is_even 2;;\n",
   1558     "is_even 3;;\n",
   1559     "is_even 300000000;;"
   1560    ]
   1561   },
   1562   {
   1563    "cell_type": "code",
   1564    "execution_count": 42,
   1565    "id": "4a1fd467-9ff0-43d3-89ab-71772f42c611",
   1566    "metadata": {},
   1567    "outputs": [],
   1568    "source": [
   1569     "(* 11\n",
   1570     "\n",
   1571     "NEW IDEA: the accumulator can be a string.\n",
   1572     "\n",
   1573     "to_binary n returns the base-2 representation of n >= 0 as a string. Tail\n",
   1574     "recursive. ^ concatenates strings and string_of_int turns a digit into one.\n",
   1575     "Peeling with mod 2 produces the digits backwards, and the fix is a matter of\n",
   1576     "which side you concatenate on. n = 0 needs thought, since the natural loop\n",
   1577     "produces the empty string.\n",
   1578     "\n",
   1579     "to_binary 0 = \"0\", to_binary 1 = \"1\", to_binary 5 = \"101\",\n",
   1580     "to_binary 10 = \"1010\", to_binary 255 = \"11111111\".\n",
   1581     "\n",
   1582     "*)"
   1583    ]
   1584   },
   1585   {
   1586    "cell_type": "code",
   1587    "execution_count": 43,
   1588    "id": "b337c48c-eda6-48b0-a2cb-d88436e0a39d",
   1589    "metadata": {},
   1590    "outputs": [
   1591     {
   1592      "data": {
   1593       "text/plain": [
   1594        "val to_binary : int -> string = <fun>\n"
   1595       ]
   1596      },
   1597      "execution_count": 43,
   1598      "metadata": {},
   1599      "output_type": "execute_result"
   1600     }
   1601    ],
   1602    "source": [
   1603     "let to_binary n = \n",
   1604     "    let rec go acc current =\n",
   1605     "        if current <= 1\n",
   1606     "            then string_of_int current ^ acc\n",
   1607     "        else\n",
   1608     "            if current mod 2 = 0\n",
   1609     "                then go (\"0\" ^ acc) ((current) / 2)\n",
   1610     "                else\n",
   1611     "                    go (\"1\" ^ acc) ((current - 1) / 2)\n",
   1612     "    in go \"\" n"
   1613    ]
   1614   },
   1615   {
   1616    "cell_type": "code",
   1617    "execution_count": 44,
   1618    "id": "5cb1a2ed-ac2b-4096-812f-eaf642455207",
   1619    "metadata": {},
   1620    "outputs": [
   1621     {
   1622      "data": {
   1623       "text/plain": [
   1624        "- : string = \"1010\"\n"
   1625       ]
   1626      },
   1627      "execution_count": 44,
   1628      "metadata": {},
   1629      "output_type": "execute_result"
   1630     },
   1631     {
   1632      "data": {
   1633       "text/plain": [
   1634        "- : string = \"10\"\n"
   1635       ]
   1636      },
   1637      "execution_count": 44,
   1638      "metadata": {},
   1639      "output_type": "execute_result"
   1640     },
   1641     {
   1642      "data": {
   1643       "text/plain": [
   1644        "- : string = \"1\"\n"
   1645       ]
   1646      },
   1647      "execution_count": 44,
   1648      "metadata": {},
   1649      "output_type": "execute_result"
   1650     }
   1651    ],
   1652    "source": [
   1653     "to_binary 10;;\n",
   1654     "to_binary 2;;\n",
   1655     "to_binary 1;;"
   1656    ]
   1657   },
   1658   {
   1659    "cell_type": "code",
   1660    "execution_count": 45,
   1661    "id": "c234416c-be09-4265-84f8-473c684d5e13",
   1662    "metadata": {},
   1663    "outputs": [
   1664     {
   1665      "data": {
   1666       "text/plain": [
   1667        "- : int = 55\n"
   1668       ]
   1669      },
   1670      "execution_count": 45,
   1671      "metadata": {},
   1672      "output_type": "execute_result"
   1673     },
   1674     {
   1675      "data": {
   1676       "text/plain": [
   1677        "- : int = 55\n"
   1678       ]
   1679      },
   1680      "execution_count": 45,
   1681      "metadata": {},
   1682      "output_type": "execute_result"
   1683     }
   1684    ],
   1685    "source": [
   1686     "fib 10;;\n",
   1687     "fib_fast 10;;"
   1688    ]
   1689   },
   1690   {
   1691    "cell_type": "code",
   1692    "execution_count": 46,
   1693    "id": "831079e0-85d8-4799-9283-139e8b33af7c",
   1694    "metadata": {},
   1695    "outputs": [],
   1696    "source": [
   1697     "(* 14\n",
   1698     "\n",
   1699     "NEW IDEA: carrying a search interval rather than a value, and choosing an\n",
   1700     "invariant you can state.\n",
   1701     "\n",
   1702     "int_sqrt n returns the largest k such that k*k <= n, for n >= 0, so it\n",
   1703     "truncates. Do it by binary search, tail recursively, with an inner helper\n",
   1704     "carrying lo and hi.\n",
   1705     "\n",
   1706     "Before writing it, decide the invariant in words: what must always be true of\n",
   1707     "lo and hi? Getting that sentence right is most of the work, and off-by-one\n",
   1708     "errors here are the norm rather than a failure.\n",
   1709     "\n",
   1710     "One trap worth knowing in advance: for n near 10^12, starting hi at n makes\n",
   1711     "mid * mid overflow a 63-bit int silently. Either start hi somewhere smaller\n",
   1712     "that is still definitely above the answer, or compare without multiplying.\n",
   1713     "\n",
   1714     "int_sqrt 0 = 0, int_sqrt 15 = 3, int_sqrt 16 = 4, int_sqrt 17 = 4,\n",
   1715     "int_sqrt 1_000_000_000_000 = 1_000_000.\n",
   1716     "\n",
   1717     "*)"
   1718    ]
   1719   },
   1720   {
   1721    "cell_type": "code",
   1722    "execution_count": 47,
   1723    "id": "0ac0572b-66a4-4a18-aefa-7de3d02515ba",
   1724    "metadata": {
   1725     "deletable": true,
   1726     "editable": true,
   1727     "slideshow": {
   1728      "slide_type": ""
   1729     },
   1730     "tags": []
   1731    },
   1732    "outputs": [
   1733     {
   1734      "data": {
   1735       "text/plain": [
   1736        "val int_sqrt : int -> int = <fun>\n"
   1737       ]
   1738      },
   1739      "execution_count": 47,
   1740      "metadata": {},
   1741      "output_type": "execute_result"
   1742     }
   1743    ],
   1744    "source": [
   1745     "let int_sqrt n = \n",
   1746     "    let rec go low hi =\n",
   1747     "        if hi - low <= 1 \n",
   1748     "            then \n",
   1749     "            if hi = 0 then 0 else\n",
   1750     "            if hi > n / hi then low else hi\n",
   1751     "        else\n",
   1752     "            let mid = hi - ((hi - low) / 2) in\n",
   1753     "            if mid > n / mid\n",
   1754     "            then\n",
   1755     "                go low mid\n",
   1756     "            else\n",
   1757     "                go mid hi\n",
   1758     "    in go 0 n"
   1759    ]
   1760   },
   1761   {
   1762    "cell_type": "code",
   1763    "execution_count": 69,
   1764    "id": "e13a3ee4-4bde-4a15-ae6f-62db9447c748",
   1765    "metadata": {},
   1766    "outputs": [
   1767     {
   1768      "data": {
   1769       "text/plain": [
   1770        "- : int = 4\n"
   1771       ]
   1772      },
   1773      "execution_count": 69,
   1774      "metadata": {},
   1775      "output_type": "execute_result"
   1776     },
   1777     {
   1778      "data": {
   1779       "text/plain": [
   1780        "- : int = 3\n"
   1781       ]
   1782      },
   1783      "execution_count": 69,
   1784      "metadata": {},
   1785      "output_type": "execute_result"
   1786     },
   1787     {
   1788      "data": {
   1789       "text/plain": [
   1790        "- : int = 4\n"
   1791       ]
   1792      },
   1793      "execution_count": 69,
   1794      "metadata": {},
   1795      "output_type": "execute_result"
   1796     },
   1797     {
   1798      "data": {
   1799       "text/plain": [
   1800        "- : int = 3\n"
   1801       ]
   1802      },
   1803      "execution_count": 69,
   1804      "metadata": {},
   1805      "output_type": "execute_result"
   1806     },
   1807     {
   1808      "data": {
   1809       "text/plain": [
   1810        "- : int = 3\n"
   1811       ]
   1812      },
   1813      "execution_count": 69,
   1814      "metadata": {},
   1815      "output_type": "execute_result"
   1816     },
   1817     {
   1818      "data": {
   1819       "text/plain": [
   1820        "- : int = 0\n"
   1821       ]
   1822      },
   1823      "execution_count": 69,
   1824      "metadata": {},
   1825      "output_type": "execute_result"
   1826     },
   1827     {
   1828      "data": {
   1829       "text/plain": [
   1830        "- : int = 1000000\n"
   1831       ]
   1832      },
   1833      "execution_count": 69,
   1834      "metadata": {},
   1835      "output_type": "execute_result"
   1836     }
   1837    ],
   1838    "source": [
   1839     "int_sqrt 17;;\n",
   1840     "int_sqrt 10;;\n",
   1841     "int_sqrt 16;;\n",
   1842     "int_sqrt 12;;\n",
   1843     "int_sqrt 11;;\n",
   1844     "int_sqrt 0;;\n",
   1845     "int_sqrt 1000000000000;;"
   1846    ]
   1847   },
   1848   {
   1849    "cell_type": "code",
   1850    "execution_count": 120,
   1851    "id": "7415ca41-1c3a-4828-af4e-51736596bb3f",
   1852    "metadata": {},
   1853    "outputs": [
   1854     {
   1855      "name": "stdout",
   1856      "output_type": "stream",
   1857      "text": [
   1858       "- : unit = ()\n",
   1859       "Findlib has been successfully loaded. Additional directives:\n",
   1860       "  #require \"package\";;      to load a package\n",
   1861       "  #list;;                   to list the available packages\n",
   1862       "  #camlp4o;;                to load camlp4 (standard syntax)\n",
   1863       "  #camlp4r;;                to load camlp4 (revised syntax)\n",
   1864       "  #predicates \"p,q,...\";;   to set these predicates\n",
   1865       "  Topfind.reset();;         to force that packages will be reloaded\n",
   1866       "  #thread;;                 to enable threads\n",
   1867       "\n",
   1868       "- : unit = ()\n"
   1869      ]
   1870     }
   1871    ],
   1872    "source": [
   1873     "#use \"topfind\";;\n",
   1874     "#require \"qcheck\";;"
   1875    ]
   1876   },
   1877   {
   1878    "cell_type": "code",
   1879    "execution_count": 124,
   1880    "id": "7bc3f682-7c8b-4520-aeb0-9bb33a802e22",
   1881    "metadata": {},
   1882    "outputs": [
   1883     {
   1884      "data": {
   1885       "text/plain": [
   1886        "val squared_invariant : QCheck.Test.t = QCheck2.Test.Test <abstr>\n"
   1887       ]
   1888      },
   1889      "execution_count": 124,
   1890      "metadata": {},
   1891      "output_type": "execute_result"
   1892     },
   1893     {
   1894      "name": "stdout",
   1895      "output_type": "stream",
   1896      "text": [
   1897       "================================================================================\n",
   1898       "\u001b[32;1msuccess\u001b[0m (ran 1 tests)\n"
   1899      ]
   1900     },
   1901     {
   1902      "data": {
   1903       "text/plain": [
   1904        "- : int = 0\n"
   1905       ]
   1906      },
   1907      "execution_count": 124,
   1908      "metadata": {},
   1909      "output_type": "execute_result"
   1910     }
   1911    ],
   1912    "source": [
   1913     "let squared_invariant = QCheck.Test.make\n",
   1914     "    (QCheck.int_range 0 212000)\n",
   1915     "    (fun n -> n == int_sqrt (n * n));;\n",
   1916     "\n",
   1917     "QCheck_base_runner.run_tests [ squared_invariant ];;"
   1918    ]
   1919   }
   1920  ],
   1921  "metadata": {
   1922   "kernelspec": {
   1923    "display_name": "OCaml default",
   1924    "language": "OCaml",
   1925    "name": "ocaml-jupyter"
   1926   },
   1927   "language_info": {
   1928    "codemirror_mode": "text/x-ocaml",
   1929    "file_extension": ".ml",
   1930    "mimetype": "text/x-ocaml",
   1931    "name": "OCaml",
   1932    "nbconverter_exporter": null,
   1933    "pygments_lexer": "OCaml",
   1934    "version": "4.14.2"
   1935   }
   1936  },
   1937  "nbformat": 4,
   1938  "nbformat_minor": 5
   1939 }