{"categories":["Principles of Programming Languages"],"contentHtml":"<p>When we make our programs more and more complex, we need more complex data types as well. We have only used OCaml's built-in data types, how can we construct our own data types?</p>\n<h2><code>type</code></h2>\n<p>The <code>type</code> keyword is similar to the <code>typedef</code> keyword in C, except more limited in scope. A <code>type</code> can only be multiple variants of arbitrary values.</p>\n<pre><code>(* coin is enum with variants Heads and Tails*)\ntype coin = Heads | Tails\n</code></pre>\n<p>Each variant can also contain data of other data types.</p>\n<pre><code>type shape =\n | Rect of float * float\n | Circle of float\nlet r = Rect (3.0, 4.0) (* r has type shape *)\n</code></pre>\n<p><code>shape</code> here has two variants. It can either be a tuple of two <code>float</code>s when it is a <code>Rect</code>, or it can be a single <code>float</code> when it is a <code>Circle</code>.</p>\n<p>These data types are also known as <em>algebraic data types</em> or <em>tagged unions</em>.</p>\n<h2>Option</h2>\n<p>ADTs can be useful when we want to ensure the complete handling of all cases. For example, if an object is nullable, it is useful to make sure that we must handle the null case instead of passing that off to the developer who might carelessly not handle it. This is where the <strong>option</strong> type comes from.</p>\n<pre><code>type 'a option =\n | Some of 'a\n | None\n</code></pre>\n<p>The <code>'a</code> keyword means that that the type <code>option</code> is polymorphic, and the variant <code>Some</code> will contain whatever type that <code>option</code> is defined for. When handling an <code>option</code>, you <em>must</em> destructure it into its <code>Some</code> and <code>None</code> variants and handle both cases, otherwise OCaml will warn you for a non-exhaustive pattern match.</p>\n<h2>List</h2>\n<p>We can actually define our own list data type as a <strong>recursive data type</strong>, which is a data type which contains itself.</p>\n<pre><code>type 'a list =\n | Nil\n | Cons of 'a * 'a list\n</code></pre>\n<p>Here, <code>list</code> has two variants, <code>Nil</code> and a <code>Cons</code> tuple of an element and a <code>list</code>. If we think of the traditional list data type, this is actually just a more verbose version. <code>[]</code> is sugar for <code>Nil</code> and <code>::</code> is sugar for <code>Cons</code> tuple.</p>\n<pre><code>let rec len l =\n    match l with\n    | Nil -&gt; 0\n    | Cons (_, t) -&gt; 1 + (len t)\n(* same as *)\nlet rec len l =\n    match l with\n    | [] -&gt; 0\n    | _ :: t -&gt; 1 + (len t)\n</code></pre>\n<h2>Exceptions</h2>\n<p><strong>Exceptions</strong> are a special data type used for errors in OCaml. Exceptions are similar to type constructors in that they can take arguments or have none.</p>\n<pre><code>exception Sign of int\nlet f n =\n    if n &gt; 0 then\n        raise (Sign n)\n    else\n        raise (Failure \"foo\")\n</code></pre>\n<p>We can <code>raise</code> an exception with arguments whenever we want, which will exit the function with the exception name and its arguments. <code>Failure</code> is a generic exception type that is used with strings.</p>\n<p>There is also special <code>try</code> syntax used to catch exceptions.</p>\n<pre><code>let g n =\n    try\n        f n\n    with Sign n -&gt;\n            Printf.printf \"Caught %d\\n\" n\n          | Failure s -&gt;\n            Printf.printf \"Caught %s\\n\" s\n</code></pre>\n<p>The function <code>g</code> will try running <code>f n</code>, but if that raises an exception, it will be caught in <code>with</code>. It can be pattern matched for different exception types.</p>","contentMarkdown":"When we make our programs more and more complex, we need more complex data types as well. We have only used OCaml's built-in data types, how can we construct our own data types?\n\n## `type`\n\nThe `type` keyword is similar to the `typedef` keyword in C, except more limited in scope. A `type` can only be multiple variants of arbitrary values.\n\n```ocaml\n(* coin is enum with variants Heads and Tails*)\ntype coin = Heads | Tails\n```\n\nEach variant can also contain data of other data types.\n\n```ocaml\ntype shape =\n | Rect of float * float\n | Circle of float\nlet r = Rect (3.0, 4.0) (* r has type shape *)\n```\n\n`shape` here has two variants. It can either be a tuple of two `float`s when it is a `Rect`, or it can be a single `float` when it is a `Circle`.\n\nThese data types are also known as *algebraic data types* or *tagged unions*.\n\n## Option\n\nADTs can be useful when we want to ensure the complete handling of all cases. For example, if an object is nullable, it is useful to make sure that we must handle the null case instead of passing that off to the developer who might carelessly not handle it. This is where the **option** type comes from.\n\n```ocaml\ntype 'a option =\n | Some of 'a\n | None\n```\n\nThe `'a` keyword means that that the type `option` is polymorphic, and the variant `Some` will contain whatever type that `option` is defined for. When handling an `option`, you *must* destructure it into its `Some` and `None` variants and handle both cases, otherwise OCaml will warn you for a non-exhaustive pattern match.\n\n## List\n\nWe can actually define our own list data type as a **recursive data type**, which is a data type which contains itself.\n\n```ocaml\ntype 'a list =\n | Nil\n | Cons of 'a * 'a list\n```\n\nHere, `list` has two variants, `Nil` and a `Cons` tuple of an element and a `list`. If we think of the traditional list data type, this is actually just a more verbose version. `[]` is sugar for `Nil` and `::` is sugar for `Cons` tuple. \n\n```ocaml\nlet rec len l =\n    match l with\n    | Nil -> 0\n    | Cons (_, t) -> 1 + (len t)\n(* same as *)\nlet rec len l =\n    match l with\n    | [] -> 0\n    | _ :: t -> 1 + (len t)\n```\n\n## Exceptions\n\n**Exceptions** are a special data type used for errors in OCaml. Exceptions are similar to type constructors in that they can take arguments or have none.\n\n```ocaml\nexception Sign of int\nlet f n =\n    if n > 0 then\n        raise (Sign n)\n    else\n        raise (Failure \"foo\")\n```\n\nWe can `raise` an exception with arguments whenever we want, which will exit the function with the exception name and its arguments. `Failure` is a generic exception type that is used with strings.\n\nThere is also special `try` syntax used to catch exceptions.\n\n```ocaml\nlet g n =\n    try\n        f n\n    with Sign n ->\n            Printf.printf \"Caught %d\\n\" n\n          | Failure s ->\n            Printf.printf \"Caught %s\\n\" s\n```\n\nThe function `g` will try running `f n`, but if that raises an exception, it will be caught in `with`. It can be pattern matched for different exception types.","dataUrl":"https://sharifhsn.dev/api/posts/data-types.json","date":"2022-02-17","datePublished":"2022-02-17","description":"When we make our programs more and more complex, we need more complex data types as well. We have only used OCaml's built-in data types, how can we construct our own data types?","site":"https://sharifhsn.dev","slug":"data-types","source":"Archive","sourceUrl":null,"tags":["Principles of Programming Languages"],"title":"Data Types in OCaml","url":"https://sharifhsn.dev/blog/data-types/","version":"1","wordCount":561}