OCaml Planet
http://planet.ocamlcore.org
OCaml Planet - http://planet.ocamlcore.orgShayne Fletcher: Perfectly balanced binary search trees
http://blog.shaynefletcher.org/2016/08/perfectly-balanced-binary-search-trees.html
<p>The type of "association tables" (binary search trees). </p><pre class="prettyprint ml"><br />type (α, β) t =<br />| Empty<br />| Node of (α , β) t * α * β * (α, β) t * int<br /></pre>There are two cases : a tree that is empty or, a node consisting of a left sub-tree, a key, the value associated with that key, a right sub-tree and, an integer representing the "height" of the tree (the number of nodes to traverse before reaching the most distant leaf). <p></p><p>The binary search tree invariant will be made to apply in that for any non empty tree $n$, every node in the left sub-tree is ordered less than $n$ and every node in the right sub-tree of $n$ is ordered greater than $n$ (in this program, ordering of keys is performed using the <code>Pervasives.compare</code> function). </p><p>This function, <code>height</code>, given a tree, extracts its height. </p><pre class="prettyprint ml"><br />let height : (α, β) t -> int = function<br /> | Empty -> 0<br /> | Node (_, _, _, _, h) -> h<br /></pre><p></p><p>The value <code>empty</code>, is a constant, the empty tree. </p><pre class="prettyprint ml"><br />let empty : (α, β) t = Empty<br /></pre><p></p><p><code>create l x d r</code> creates a new non-empty tree with left sub-tree <code>l</code>, right sub-tree <code>r</code> and the binding of key <code>x</code> to the data <code>d</code>. The height of the tree created is computed from the heights of the two sub-trees. </p><pre class="prettyprint ml"><br />let create (l : (α, β) t) (x : α) (d : β) (r : (α, β) t) : (α, β) t =<br /> let hl = height l and hr = height r in<br /> Node (l, x, d, r, (max hl hr) + 1)<br /></pre><p></p><p>This next function, <code>balance</code> is where all the action is at. Like the preceding function <code>create</code>, it is a factory function for interior nodes and so takes the same argument list as <code>create</code>. It has an additional duty though in that the tree that it produces takes balancing into consideration. </p><pre class="prettyprint ml"><br />let balance (l : (α, β) t) (x : α) (d : β) (r : (α, β) t) : (α, β) t =<br /> let hl = height l and hr = height r in<br /> if hl > hr + 1 then<br /> match l with<br /></pre>In this branch of the program, it has determined that production of a node with the given left and right sub-trees (denoted $l$ and $r$ respectively) would be unbalanced because $h(l) > hr(1) + 1$ (where $h$ denotes the height function). <p></p><p>There are two possible reasons to account for this. They are considered in turn. </p><pre class="prettyprint ml"><br /> (*Case 1*)<br /> | Node (ll, lv, ld, lr, _) when height ll >= height lr -><br /> create ll lv ld (create lr x d r)<br /></pre>So here, we find that $h(l) > h(r) + 1$, because of the height of the left sub-tree of $l$. <pre class="prettyprint ml"><br /> (*Case 2*)<br /> | Node (ll, lv, ld, Node (lrl, lrv, lrd, lrr, _), _) -><br /> create (create ll lv ld lrl) lrv lrd (create lrr x d r)<br /></pre>In this case, $h(l) > h(r) + 1$ because of the height of the right sub-tree of $l$. <pre class="prettyprint ml"><br /> | _ -> assert false<br /></pre>We <code>assert false</code> for all other patterns as we aim to admit by construction no further possibilities. <p></p><p>We now consider the case $h(r) > h(l) + 1$, that is the right sub-tree being "too long". </p><pre class="prettyprint ml"><br /> else if hr > hl + 1 then<br /> match r with<br /></pre><p></p><p>There are two possible reasons. </p><pre class="prettyprint ml"><br /> (*Case 3*)<br /> | Node (rl, rv, rd, rr, _) when height rr >= height rl -><br /> create (create l x d rl) rv rd rr<br /></pre>Here $h(r) > h(l) + 1$ because of the right sub-tree of $r$. <pre class="prettyprint ml"><br /> (*Case 4*)<br /> | Node (Node (rll, rlv, rld, rlr, _), rv, rd, rr, _) -><br /> create (create l x d rll) rlv rld (create rlr rv rd rr)<br /></pre>Lastly, $h(r) > h(l) + 1$ because of the left sub-tree of $r$. <pre class="prettyprint ml"><br /> | _ -> assert false<br /></pre>Again, all other patterns are (if we write this program correctly according to our intentions,) impossible and so, <code>assert false</code> as there are no further possibilities. <p></p><p>In the last case, neither $h(l) > h(r) + 1$ or $h(r) > h(l) + 1$ so no rotation is required. </p><pre class="prettyprint ml"><br /> else<br /> create l x d r<br /></pre><p></p><p><code>add x data t</code> computes a new tree from <code>t</code> containing a binding of <code>x</code> to <code>data</code>. It resembles standard insertion into a binary search tree except that it propagates rotations through the tree to maintain balance after the insertion. </p><pre class="prettyprint ml"><br />let rec add (x : α) (data : β) : (α, β) t -> (α, β) t = function<br /> | Empty -> Node (Empty, x, data, Empty, 1)<br /> | Node (l, v, d, r, h) -><br /> let c = compare x v in<br /> if c = 0 then<br /> Node (l, x, data, r, h)<br /> else if c < 0 then<br /> balance (add x data l) v d r<br /> else <br /> balance l v d (add x data r)<br /></pre><p></p><p>To implement removal of nodes from a tree, we'll find ourselves needing a function to "merge" two binary searchtrees $l$ and $r$ say where we can assume that all the elements of $l$ are ordered before the elements of $r$. </p><pre class="prettyprint ml"><br />let rec merge (l : (α, β) t) (r : (α, β) t) : (α, β) t = <br /> match (l, r) with<br /> | Empty, t -> t<br /> | t, Empty -> t<br /> | Node (l1, v1, d1, r1, h1), Node (l2, v2, d2, r2, h2) -><br /> balance l1 v1 d1 (balance (merge r1 l2) v2 d2 r2)<br /></pre>Again, rotations are propagated through the tree to ensure the result of the merge results in a perfectly balanced tree. <p></p><p>With <code>merge</code> available, implementing <code>remove</code> becomes tractable. </p><pre class="prettyprint ml"><br />let remove (id : α) (t : (α, β) t) : (α, β) t = <br /> let rec remove_rec = function<br /> | Empty -> Empty<br /> | Node (l, k, d, r, _) -><br /> let c = compare id k in<br /> if c = 0 then merge l r else<br /> if c < 0 then balance (remove_rec l) k d r<br /> else balance l k d (remove_rec r) in<br /> remove_rec t<br /></pre><p></p><p>The remaining algorithms below are "stock" algorithms for binary search trees with no particular consideration of balancing necessary and so we won't dwell on them here. </p><pre class="prettyprint ml"><br />let rec find (x : α) : (α, β) t -> β = function<br /> | Empty -> raise Not_found<br /> | Node (l, v, d, r, _) -><br /> let c = compare x v in<br /> if c = 0 then d<br /> else find x (if c < 0 then l else r)<br /><br />let rec mem (x : α) : (α, β) t -> bool = function<br /> | Empty -> false<br /> | Node (l, v, d, r, _) -><br /> let c = compare x v in<br /> c = 0 || mem x (if c < 0 then l else r)<br /> <br />let rec iter (f : α -> β -> unit) : (α, β) t -> unit = function<br /> | Empty -> ()<br /> | Node (l, v, d, r, _) -><br /> iter f l; f v d; iter f r<br /><br />let rec map (f : α -> β -> γ) : (α, β) t -> (α, γ) t = function<br /> | Empty -> Empty<br /> | Node (l, k, d, r, h) -> <br /> Node (map f l, k, f k d, map f r, h)<br /><br />let rec fold (f : α -> β -> γ -> γ) (m : (α, β) t) (acc : γ) : γ =<br /> match m with<br /> | Empty -> acc<br /> | Node (l, k, d, r, _) -> fold f r (f k d (fold f l acc))<br /><br />open Format<br /><br />let print <br /> (print_key : formatter -> α -> unit)<br /> (print_data : formatter -> β -> unit)<br /> (ppf : formatter)<br /> (tbl : (α, β) t) : unit =<br /> let print_tbl ppf tbl =<br /> iter (fun k d -> <br /> fprintf ppf "@[<2>%a ->@ %a;@]@ " print_key k print_data d)<br /> tbl in<br /> fprintf ppf "@[<hv>[[%a]]@]" print_tbl tbl<br /></pre><p>The source code for this post can be found in the file 'ocaml/misc/tbl.ml' in the OCaml source distribution. More information on balanced binary search trees including similar but different implementation techniques and complexity analyses can be found in <a href="https://www.cs.cornell.edu/courses/cs3110/2009sp/lectures/lec11.html">this Cornell lecture</a> and <a href="http://www.cs.cornell.edu/courses/cs3110/2008fa/lectures/lec20.html">this one</a>. </p>2016-08-27T13:18:15+00:00Shayne FletcherFunctional Jobs: Full-Stack Developer (Haskell/PureScript) at CollegeVine (Full-time)
https://functionaljobs.com/jobs/8951-full-stack-developer-haskell-purescript-at-collegevine
<h3>Overview</h3>
<p>CollegeVine is looking for a product-focused full-stack developer to help engineer the future of mentorship and higher education attainment.</p>
<p>There aren't many industries left that haven't been significantly disrupted by technology in some way, but you're reading about one right here! You will find many opportunities to apply high-leverage computer science (think machine learning, probabilistic reasoning, etc.) as well as plenty of opportunities for the more human side of the problem. As it stands, the current admissions process is a huge source of stress and confusion for students and parents alike. If we execute correctly, your work will impact the entire next generation of college graduates-to-be.</p>
<p>You will join a fast-moving company whose culture centers around authenticity, excellence, and balance. You'll find that everyone likes to keep things simple and transparent. We prefer to be goal-oriented and hands-off as long as you are a self-starter.</p>
<p>Our modern perspective on developer potential means we celebrate and optimize for real output. And that's probably the reason why we're a polyglot functional programming shop, with emphasis on Haskell and functional paradigms. Our infrastructure and non-mission-critical tooling tends to be in whatever works best for the task at hand: sometimes that's Haskell with advanced GHC extensions a-blazin', other times it's minimalist Ruby or bash—basically, it's a team decision based on whatever sits at the intersection of appropriateness, developer joy, quality, and velocity.</p>
<p>As an early-stage company headquartered in Cambridge, MA, we have a strong preference for key members of our team to be located in the Boston metro area; however, given that our company has its roots in remote work (and that it's 2016), we are open to remote arrangements after one year of continuous employment and/or executive approval.</p>
<h3>Requirements</h3>
<p>You know you are right for this position if:</p>
<ul>
<li>You have at least five years of professional software engineering experience, and at least two years of preference for a high-level programming language that's used in industry, like Haskell, Clojure, OCaml, Erlang, F#, or similar.</li>
<li>You have some front-end experience with JS or a functional language that compiles to JS, like PureScript, Elm, Clojurescript, or similar. We use PureScript, React, and ES6 on the front-end. It's pretty awesome.</li>
<li>You are a self-starter and internally motivated, with a strong desire to be part of a successful team that shares your high standards.</li>
<li>You have great written communication skills and are comfortable with making big decisions over digital presence (e.g. video chat).</li>
<li>You have polyglot experience along several axes (dynamic/static, imperative/functional, lazy/strict, weird/not-weird).</li>
<li>You are comfortable with modern infrastructure essentials like AWS, Heroku, Docker, CI, etc. You have basic but passable sysadmin skills.</li>
<li>You are fluent with git.</li>
<li>You instrument before you optimize. You test before you ship. You listen before you conclude. You measure before you cut. Twice.</li>
</ul>
<h3>Benefits</h3>
<p>We offer a competitive salary and a full suite of benefits, some of them unconventional, but awesome for the right person:</p>
<ul>
<li>Medical, dental, vision insurance and 401k come standard.</li>
<li>Flexible hours with a 4-hour core - plan the rest of your workday as you wish, just give us the majority of your most productive hours. Productivity ideas: avoid traffic, never wait in line at the grocery store, wake up without an alarm clock.</li>
<li>Goal-based environment (as opposed to grind-based or decree-based environment; work smarter, not harder; intelligently, not mindlessly). We collaborate on setting goals, but you set your own process for accomplishing those goals. You will be entrusted with a lot of responsibility and you might even experience fulfillment and self-actualization as a result.</li>
<li>Daily physical activity/mindfulness break + stipend: invest a non-core hour to make yourself more awesome by using it for yoga, tap-dance lessons, a new bike, massage, a surfboard - use your imagination! Just don’t sit at a computer all day! Come back to work more relaxed and productive and share your joy with the rest of the team. Note: You must present and share proof of your newly enriched life with the team in order to receive the stipend.</li>
<li>Equipment/setup budget so you can tool up the way you want. A brand new 15" MBP is standard issue if you have no strong opinions.</li>
</ul>
<p>Remember: We’re a startup. You’re an early employee. We face challenges. We have to ship. Your ideas matter. You <em>will</em> make a difference.</p>
<p>Get information on <a href="https://functionaljobs.com/jobs/8951-full-stack-developer-haskell-purescript-at-collegevine">how to apply</a> for this position.</p>2016-08-26T23:22:19+00:00Caml Weekly News: OCaml Weekly News, 23 Aug 2016
http://alan.petitepomme.net/cwn/2016.08.23.html
<ol><li><a href="http://alan.petitepomme.net/cwn/2016.08.23.html#1">OCaml-MariaDB</a></li> <li><a href="http://alan.petitepomme.net/cwn/2016.08.23.html#2">CPS converting existential data type</a></li> <li><a href="http://alan.petitepomme.net/cwn/2016.08.23.html#3">OASIS v0.4.7</a></li> <li><a href="http://alan.petitepomme.net/cwn/2016.08.23.html#4">Other OCaml News</a></li></ol>2016-08-23T12:00:00+00:00Sylvain Le Gall: Release of OASIS 0.4.7
http://le-gall.net/sylvain+violaine/blog/index.php?post/2016/08/22/Release-of-OASIS-0.4.6
<p>I am happy to announce the release of OASIS v0.4.7.</p>
<p><img src="http://le-gall.net/sylvain+violaine/blog/images/logo.png" alt="Logo OASIS small" style="display: block; margin: 0 auto;" title="Logo OASIS small, juin 2012" /></p>
<p>OASIS is a tool to help OCaml developers to integrate configure, build and install systems in their projects. It should help to create standard entry points in the source code build system, allowing external tools to analyse projects easily.</p>
<p>This tool is freely inspired by Cabal which is the same kind of tool for Haskell.</p>
<p>You can find the new release <a href="https://forge.ocamlcore.org/frs/?group_id=54&release_id=1223">here</a> and the changelog <a href="https://forge.ocamlcore.org/frs/shownotes.php?release_id=1223">here</a>. More information about OASIS in general on the <a href="http://oasis.forge.ocamlcore.org">OASIS website</a>.</p>
<p>Pull request for inclusion in OPAM is <a href="https://github.com/ocaml/opam-repository/pull/7281">pending</a>.</p>
<p>Here is a quick summary of the important changes:</p>
<ul>
<li>Drop support for OASISFormat 0.2 and 0.1.</li>
<li>New plugin "omake" to support build, doc and install actions.</li>
<li>Improve automatic tests (Travis CI and AppVeyor)</li>
<li>Trim down the dependencies (removed ocaml-gettext, camlp4, ocaml-data-notation)</li>
</ul>
<p>Features:</p>
<ul>
<li>findlib_directory (beta): to install libraries in sub-directories of findlib.</li>
<li>findlib_extra_files (beta): to install extra files with ocamlfind.</li>
<li>source_patterns (alpha): to provide module to source file mapping.</li>
</ul>
<p>This version contains a lot of changes and is the achievement of a huge amount of work. The addition of OMake as a plugin is a huge progress. The overall work has been targeted at making OASIS more library like. This is still a work in progress but we made some clear improvement by getting rid of various side effect (like the requirement of using "chdir" to handle the "-C", which leads to propage ~ctxt everywhere and design OASISFileSystem).</p>
<p>I would like to thanks again the contributor for this release: Spiros Eliopoulos, Paul Snively, Jeremie Dimino, Christopher Zimmermann, Christophe Troestler, Max Mouratov, Jacques-Pascal Deplaix, Geoff Shannon, Simon Cruanes, Vladimir Brankov, Gabriel Radanne, Evgenii Lepikhin, Petter Urkedal, Gerd Stolpmann and Anton Bachin.</p>2016-08-22T23:51:18+00:00gildorOCamlCore Forge News: OASIS v0.4.7 release
https://forge.ocamlcore.org/forum/forum.php?forum_id=938
Read the full blog post here:
http://le-gall.net/sylvain+violaine/blog/index.php?post/2016/08/22/Release-of-OASIS-0.4.62016-08-22T23:37:29+00:00Sylvain Le GallCaml Weekly News: OCaml Weekly News, 16 Aug 2016
http://alan.petitepomme.net/cwn/2016.08.16.html
<ol><li><a href="http://alan.petitepomme.net/cwn/2016.08.16.html#1">Tools and compilers positions at Jane Street</a></li> <li><a href="http://alan.petitepomme.net/cwn/2016.08.16.html#2">OCaml 4.04.0+beta1</a></li> <li><a href="http://alan.petitepomme.net/cwn/2016.08.16.html#3">Tyre</a></li> <li><a href="http://alan.petitepomme.net/cwn/2016.08.16.html#4">Job opportunity for OCaml programmer</a></li> <li><a href="http://alan.petitepomme.net/cwn/2016.08.16.html#5">Other OCaml News</a></li></ol>2016-08-16T12:00:00+00:00Functional Jobs: Software Engineer (Haskell/Clojure) at Capital Match (Full-time)
https://functionaljobs.com/jobs/8949-software-engineer-haskell-clojure-at-capital-match
<p><strong>Overview</strong></p>
<p><a href="https://www.capital-match.com">Capital Match</a> is a leading marketplace lending and invoice financing platform in Singapore. Our in-house platform, mostly developed in Haskell, has in the last year seen more than USD 10 million business loans processed with a strong monthly growth (current rate of USD 1.5-2.5 million monthly). We are also eyeing expansion into new geographies and product categories. Very exciting times!</p>
<p>We have just secured another funding round to build a world-class technology as the key business differentiator. The key components include credit risk engine, seamless banking integration and end-to-end product automation from loan origination to debt collection.</p>
<p><strong>Responsibilities</strong></p>
<p>We are looking to hire a software engineer with a minimum of 2-3 years coding experience. The current tech team includes a product manager and 3 software engineers. We are currently also in the process of hiring CTO.</p>
<p>The candidate should have been involved in a development of multiple web-based products from scratch. He should be interested in all aspects of the creation, growth and operations of a secure web-based platform: front-to-back features development, distributed deployment and automation in the cloud, build and test automation etc.</p>
<p>Background in fintech and especially lending / invoice financing space would be a great advantage.</p>
<p><strong>Requirements</strong></p>
<p>Our platform is primarily developed in Haskell with an Om/ClojureScript frontend. We are expecting our candidate to have experience working with a functional programming language e.g. Haskell/Scala/OCaml/F#/Clojure/Lisp/Erlang.</p>
<p>Deployment and production is managed with Docker containers using standard cloud infrastructure so familiarity with Linux systems, command-line environment and cloud-based deployment is mandatory. Minimum exposure to and understanding of XP practices (TDD, CI, Emergent Design, Refactoring, Peer review and programming, Continuous improvement) is expected. </p>
<p>We are looking for candidates that are living in or are willing to relocate to Singapore.</p>
<p><strong>Offer</strong></p>
<p>We offer a combination of salary and equity depending on experience and skills of the candidate.</p>
<p>Most expats who relocate to Singapore do not have to pay their home country taxes and the local tax rate in Singapore is more or less 5% (effective on the proposed salary range).</p>
<p>Visa sponsorship will be provided. </p>
<p>Singapore is a great place to live, a vibrant city rich with diverse cultures, a very strong financial sector and a central location in Southeast Asia.</p>
<p>Get information on <a href="https://functionaljobs.com/jobs/8949-software-engineer-haskell-clojure-at-capital-match">how to apply</a> for this position.</p>2016-08-12T11:05:58+00:00OCamlCore Forge News: planet.ocamlcore.org will soon be deprecated
https://forge.ocamlcore.org/forum/forum.php?forum_id=937
For the past 8 years the OCaml Planet was running on http://planet.ocamlcore.org. A few years ago, another planet has forked and it is now better maintained than the old one. This new planet is located here http://ocaml.org/community/planet/ and the old planet will soon redirect to this new location.
If you use a feed reader, I recommend to point it directly to the new planet:
http://ocaml.org/feed.xml2016-08-12T07:26:21+00:00Sylvain Le GallAndrej Bauer: What is a formal proof?
http://math.andrej.com/2016/08/09/what-is-a-formal-proof/
<p>Mike Shulman just wrote a very nice <a href="https://golem.ph.utexas.edu/category/2016/08/what_is_a_formal_proof.html">blog post on what is a formal proof</a>. I much agree with what he says, but I would like to offer my own perspective. I started writing it as a comment to Mike’s post and then realized that it is too long, and that I would like to have it recorded independently as well. Please read Mike’s blog post first.</p>
<p><span id="more-1920"></span></p>
<p>Just as Mike, I am discussing here formal proofs from the point of view of proof assistants, i.e., what criteria need to be satisfied by the things we call “formal proofs” for them to serve their intended purpose, which is: to convince machines (and indirectly humans) of mathematical truths. Just as Mike, I shall call a (formal) proof a <em>complete</em> derivation tree in a formal system, such as type theory or first-order logic.</p>
<p>What Mikes calls an <em>argument</em> I would prefer to call a <em>proof representation</em>. This can be any kind of concrete representation of the actual formal proof. The representation may be very indirect and might require a lot of effort to reconstruct the original proof. Unless we deal with an extremely simple formal system, there is always the possibility to have <em>invalid representations</em>, i.e., data of the correct datatype which however does not represent a proof.</p>
<p>I am guaranteed to reinvent the wheel here, at least partially, since many people before me thought of the problem, but here I go anyway. Here are (some) criteria that formal proofs should satisfy:</p>
<ul>
<li><strong>Reproducibility:</strong> it should be possible to replicate and communicate proofs. If I have a proof it ought to be possible for me to send you a copy of the proof.</li>
<li><strong>Objectivity:</strong> all copies of the same proof should represent the same piece of information, and there should be no question what is being represented.</li>
<li><strong>Verifiability:</strong> it should be possible to recognize the fact that something is a proof.</li>
</ul>
<p>There is another plausible requirement:</p>
<ul>
<li><strong>Falsifiability:</strong> it should be possible to recognize the fact that something is <em>not</em> a proof.</li>
</ul>
<p>Unlike the other three requirements, I find falsifiability questionable. I have received too many messages from amateur mathematicians who could not be convinced that their proofs were wrong. Also, mathematics is a cooperative activity in which mistakes (both honest and dishonest) are easily dealt with – once we expand the resources allocated to verifying a proof we simply give up. An adversarial situation, such as <a href="https://en.wikipedia.org/wiki/Proof-carrying_code">proof carrying code</a>, is a different story with a different set of requirements.</p>
<p>The requirements impose conditions on how formal proofs in a proof assistant might be designed. Reproducibility dictates that proofs should be easily accessible and communicable. That is, they should be pieces of digital information that are commonly handled by computers. They should not be prohibitively large, of if they are, they need to be suitably compressed, lest storage and communication become unfeasible. Objectivity is almost automatic in the era of crisp digital data. We will worry about Planck-scale proof objects later. Verifiability can be ensured by developing and implementing algorithms that recognize correct representations of proofs.</p>
<p>This post grew out of a comment that I wanted to make about a particular statement in Mike’s post. He says:</p>
<blockquote><p>“… for a proof assistant to honestly call itself an <em>implementation</em> of that formal system, it ought to include, somewhere in its internals, some data structure that represents those proofs reasonably faithfully.”</p></blockquote>
<p>This requirement is too stringent. I think Mike is shooting for some combination of reproducibility and verifiability, but explicit storage of proofs in raw form is only one way to achieve them. What we need instead is <em>efficient communication</em> and <em>verification </em>of (communicated) proofs. These can both be achieved without storage of proofs in explicit form.</p>
<p>Proofs may be stored and communicated in implicit form, and proof assistants such as Coq and Agda do this. Do not be fooled into thinking that Coq gives you the “proof terms”, or that Agda aficionados type down actual complete proofs. Those are not the derivation trees, because they are missing large subtrees of equality reasoning. Complete proofs are too big to be communicated or stored in memory (or some day they will be), and little or nothing is gained by storing them or re-verifying their complete forms. Instead, it is better to devise compact representations of proofs which get <em>elaborated</em> or <em>evaluated</em> into actual proofs on the fly. Mike comments on this and explains that Coq and Agda both involve a large amount of elaboration, but let me point out that even the elaborated stuff is still only a shadow of the actual derivation tree. The data that gets stored in the Coq .vo file is really a bunch of instructions for the proof checker to easily reconstruct the proof using a specific algorithm. The <em>actual</em> derivation tree is implicit in the execution trace of the proof checker, stored in the space-time continuum and inaccessible with pre-Star Trek technology. It does not matter that we cannot get to it, because the whole process is replicable. If we feel like going through the derivation tree again, we can just run the proof assistant again.</p>
<p>I am aware of the fact that people strongly advocate some points which I am arguing against, two of which might be:</p>
<ul>
<li>Proofs assistants must provide proofs that can be independently checked.</li>
<li>Proof checking must be <em>decidable</em>, not just <em>semi-decidable.</em></li>
</ul>
<p>As far as I can tell, nobody actually subscribes to these in practice. (Now that the <a href="http://math.andrej.com/2016/08/06/hask-is-not-a-category/">angry Haskell mob</a> has subsided, I feel like I can take a hit from an angry proof assistant mob, which the following three paragraphs are intended to attract. What I <em>really</em> want the angry mob to think about deeply is how their professed beliefs match up with their practice.)</p>
<p>First, nobody downloads compiled .vo files that contain the proof certificates, we all download other people’s original .v files and compile them ourselves. So the .vo files and proof certificates are a double illusion: they do not contain actual proofs but half-digested stuff that may still require a lot of work to verify, and nobody uses them to communicate or verify proofs anyhow. They are just an optimization technique for faster loading of libraries. The <em>real</em> representations of proofs are in the .v files, and those can only be <em>semi-</em>checked for correctness.</p>
<p>Second, in practice it is irrelevant whether checking a proof is decidable because the elaboration phase and the various proof search techniques are possibly non-terminating anyhow. If there are a couple of possibly non-terminating layers on top of the trusted kernel, we might as well let the kernel be possibly non-terminating, too, and instead squeeze some extra expressivity and efficiency from it.</p>
<p>Third, and still staying with decidability of proof checking, what actually <em>is</em> annoying are uncontrollable or unidentifiable sources of inefficiency. Have you ever danced a little dance around Coq or Agda to cajole its <em>terminating</em> normalization procedure into finishing before getting <a href="https://en.wikipedia.org/wiki/Andromeda–Milky_Way_collision">run over by Andromeda</a>? Bow to the gods of decidable proof checking.</p>
<p>It is far more important that <em>cooperating</em> parties be able to communicate and verify proofs efficiently, than it is to be able to tell whether an <em>adversary</em> is wasting our time. Therefore, proofs should be, and in practice are communicated in the most flexible manner possible, as programs. LCF-style proof assistants embrace this idea, while others move slowly towards it by giving the user ever greater control over the internal mechanisms of the proof assistant (for instance, witness Coq’s recent developments such as partial user control over the universe mechanism, or Agda’s rewriting hackery). In an adversarial situations, such as <a href="https://en.wikipedia.org/wiki/Proof-carrying_code">proof carrying code</a>, the design requirements for formalized proofs are completely different from the situation we are considering.</p>
<p>We do not expect humans to memorize every proof of every mathematical statement they ever use, nor do we imagine that knowledge of a mathematical fact is the same thing as the proof of it. Humans actually memorize “proof ideas” which allow them to replicate the proofs whenever they need to. Proof assistants operate in much the same way, for good reasons.</p>2016-08-09T12:28:11+00:00Andrej BauerAndrej Bauer: Hask is not a category
http://math.andrej.com/2016/08/06/hask-is-not-a-category/
<p>This post is going to draw an angry Haskell mob, but I just have to say it out loud: I have never seen a definition of the so-called <a href="https://wiki.haskell.org/Hask">category Hask</a> and I do not actually believe there is one until someone does some serious work.</p>
<p><span id="more-1908"></span></p>
<p>Let us look at the matter a bit closer. The <a href="https://wiki.haskell.org/Hask">Haskell wiki page on Hask</a> says:</p>
<p style="padding-left: 30px;">The objects of Hask are Haskell types, and the morphisms from objects <code>A</code> to <code>B</code> are Haskell functions of type <code>A -> B</code>. The identity morphism for object <code>A</code> is <code>id :: A -> A</code>, and the composition of morphisms <code>f</code> and <code>g</code> is <code>f . g = \x -> f (g x)</code>.</p>
<p>Presumably “function” here means “closed expression”. It is then immediately noticed that there is a problem because the supposed identity morphisms do not actually work correctly: <code>seq undefined () = undefined</code> and <code>seq (undefined . id) () = ()</code>, therefore we do not have <code>undefined . id = undefined</code>.</p>
<p>The proposed solution is to equate <code>f :: A -> B</code> and <code>g :: A -> B</code> when <code>f x = g x</code> for all <code>x :: A</code>. Again, we may presume that here <code>x</code> ranges over all closed expressions of type <code>A</code>. But this begs the question: <em>what does <code>f x = g x</code> mean?</em> Obviously, it cannot mean “syntactically equal expressions”. If we had a notion of observational or contextual equivalence then we could use that, but there is no such thing until somebody provides an operational semantics of Haskell. Written down, in detail, in standard form.</p>
<p>The wiki page gives two references. One is about the denotational semantics of Haskell, which is just a certain category of continuous posets. That is all fine, but such a category is not the syntactic category we are looking for. The other paper is a fine piece of work that uses denotational semantics to prove cool things, but does not speak of any syntactic category for Haskell.</p>
<p>There are several ways in which we could resolve the problem:</p>
<ol>
<li>If we define a notion of observational or contextual equivalence for Haskell, then we will know what it means for two expressions to be indistinguishable. We can then use this notion to equate indistinguishable morphisms.</li>
<li>We could try to define the equality relation more carefully. The wiki page does a first step by specifying that at a function type equality is the extensional equality. Similarly, we could define that two pairs are equal if their components are equal, etc. But there are a lot of type constructors (including recursive types) and you’d have to go through them, and define a notion of equality on all of them. And after that, you need to show that this notion of equality actually gives a category. All the while, there will be a nagging doubt as to what it all means, since there is no operational semantics of Haskell.</li>
<li>We could import a category-theoretic structure from a denotational semantics. It seems that denotational semantics of Haskell actually exists and is some sort of a category of domains. However, this would just mean we’re restricting attention to a subcategory of the semantic category on the definable objects and morphisms. There is little to no advantage of doing so, and it’s better to just stick with the semantic category.</li>
</ol>
<p>Until someone actually does some work, <strong>there is no Hask</strong>! I’d delighted to be wrong, but I have not seen a complete construction of such a category yet.</p>
<p>Perhaps you think it is OK to pretend that something is a category when it is not. In that case, you would also pretend that the Haskell monads are actual category-theoretic monads. I recall a story from one of my math professors: when she was still a doctoral student she participated as “math support” in the construction of a small experimental nuclear reactor in Slovenia. One of the physicsts asked her to estimate the value of the harmonic series $1 + 1/2 + 1/3 + \cdots$ to four decimals. When she tried to explain the series diverged, he said “that’s ok, let’s just pretend it converges”.</p>
<p><strong>Supplemental: </strong> Of the three solutions mentioned above I like the best the one where we give Haskell an operational semantics. It’s more or less clear how we would do this, after all Haskell is more or less a glorified PCF. However, the thing that worries me is <code>seq</code>. Because of it <code>undefined</code> and <code>undefined . id</code> are <em>not</em> observationally equivalent, which means that we cannot use observational equivalence for equality of morphisms. We could try the wiki definition: <code>f :: A -> B</code> and <code>g :: A -> B</code> represent the same morphisms if <code>f x</code> and <code>g x</code> are observationally equivalent for all closed expressions <code>x :: A</code>. But then we need to prove something after that to know that we really have a category. For instance, I do not find it obvious anymore that programs which involve seq behave nicely. And what happens with higher-order functions, where observational equivalence and extensional equality get mixed up, is everything still holding water? There are just too many questions to be answered before we have a category.</p>
<p><strong>Supplemental II:</strong> Now that the mob is here, I can see certain patterns in the comments, so I will allow myself replying to them en masse by supplementing the post. I hope you all will notice this. Let me be clear that I am not arguing against the usefulness of category-theoretic thinking in programming. In fact, I support programming that is informed by abstraction, as it often leads to new insights and helps gets things done correctly. (And anyone who knows my work should find this completely obvious.)</p>
<p>Nor am I objecting to “fast & loose” mode of thinking while investigating a new idea in Haskell, that is obviously quite useful as well. I am objecting to:</p>
<ol>
<li>The fact the the Haskell wiki claims there is such a thing as “the category Hask” and it pretends that everything is ok.</li>
<li>The fact that some people find it acceptable to defend broken mathematics on the grounds that it is useful. Non-broken mathematics is also useful, as well as correct. Good engineers do not rationalize broken math by saying “life is tough”.</li>
</ol>
<p>Anyhow, we do not need the Hask category. There already are other categories into which we can map Haskell, and they explain things quite well. It is ok to say “you can think of Haskell as a sort of category, but beware, there are technical details which break this idea, so you need to be a bit careful”. It is not ok to write on the Haskell wiki “Hask is a category”. Which is why I put up this blog post, so when people Google for Hask they’ll hopefully find the truth behind it.</p>
<p><strong>Supplemental III</strong>: On Twitter people have suggested some references that provide an operational semantics of Haskell:</p>
<ul>
<li>John Launchbury: <a href="http://www.cse.chalmers.se/edu/year/2015/course/DAT140/Launchbury.pdf">A natural semantics for lazy evaluation</a></li>
<li>Alan Jeffrey: <a href="http://ect.bell-labs.com/who/ajeffrey/papers/cs1293.pdf">A fully abstract semantics for concurrent graph reduction</a></li>
</ul>
<p>Can we use these to define a suitable notion of equality of morphisms? (And let’s forget about <code>seq</code> for the time being.)</p>2016-08-06T20:36:40+00:00Andrej Bauer