From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by c5ff346549e7 (Postfix) with ESMTPS id E669C5D4 for ; Tue, 1 Sep 2020 07:55:59 +0000 (UTC) X-IronPort-AV: E=Sophos;i="5.76,359,1592863200"; d="scan'208,217";a="465495053" Received: from prod-listesu18.inria.fr (HELO sympa.inria.fr) ([128.93.162.160]) by mail2-relais-roc.national.inria.fr with ESMTP; 01 Sep 2020 09:55:57 +0200 Received: by sympa.inria.fr (Postfix, from userid 20132) id 87AB7E0B17; Tue, 1 Sep 2020 09:55:57 +0200 (CEST) Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id 4601BE016E for ; Tue, 1 Sep 2020 09:55:54 +0200 (CEST) Authentication-Results: mail2-smtp-roc.national.inria.fr; spf=Pass smtp.pra=alan.schmitt@polytechnique.org; spf=Pass smtp.mailfrom=SRS0=pURB=CK=polytechnique.org=alan.schmitt@bounces.m4x.org; spf=Pass smtp.helo=postmaster@mx1.polytechnique.org IronPort-PHdr: =?us-ascii?q?9a23=3ASqHyvRb1OnMD/8UESuF0lJ3/LSx+4OfEezUN459i?= =?us-ascii?q?sYplN5qZps+9YB7h7PlgxGXEQZ/co6odzbaP7ea5AzBLsc/JmUtBWaQEbwUCh8?= =?us-ascii?q?QSkl5oK+++Imq/EsTXaTcnFt9JTl5v8iLzG0FUHMHjew+a+SXqvnYdFRrlKAV6?= =?us-ascii?q?OPn+FJLMgMSrzeCy/IDYbxlViDanbr5+MRS7oR/MusUIjoZuJaU8xgbUqXZUZu?= =?us-ascii?q?pawn9lK0iOlBjm/Mew+5Bj8yVUu/0/8sNLTLv3caclQ7FGFToqK2866tHluhnF?= =?us-ascii?q?VguP+2ATUn4KnRpSAgjK9w/1U5HsuSbnrOV92S2aPcrrTbAoXDmp8qlmRAP0hC?= =?us-ascii?q?oBKjU18GLZispujKJauxKhpgdww4rKb4qIOvt+ebndcs4BRWFcWspcWTBNDoa6?= =?us-ascii?q?YoASDeQOIPxYopH9qVUQsBWwCwqiC+zzxTJTnHD6wbc33v49HQ3a3gEtGc8Fvn?= =?us-ascii?q?TOrNXyMacfSfy4zK3SwjXFcvhYxCvy6IjNchAgvfGMQa97fM3LxkkrDQzFiE+c?= =?us-ascii?q?qZf5MDOV0+QNsnSb7/Z7WOK3jG4nrwFwoiSxycgwionJgIMVyknZ9Spn2oo1Is?= =?us-ascii?q?e4SEFibNOiDZBfuD2UOZFsTcM+X2Fnpjw6yrsetJKlYCQEyJopyhrBZ/GIfYWF?= =?us-ascii?q?4hPuWeWQLDp8mX9rdq+yigqy/EW81ODyVte43lZEoydZndTBtW4B2RzQ58aHVP?= =?us-ascii?q?dw+Fqq1ziI1wDW8O5EIEY0mLLDK5E/3r4wl4YTvlrbHi/xnUX2ibGZel8i+ue2?= =?us-ascii?q?9+TrerLmqYOGOI9xjgHyKKMumtawAeggPQgOWG+b+eu41LL950H2XLJKjvgunq?= =?us-ascii?q?nWsZDaOcQbprOiDANPzokj7BO/Ay+739QFhnYHMV1Fdwybj4TzNVHOOuj0De2h?= =?us-ascii?q?jFS3jDhr3fHGPqX9ApnUKnjMirHhfbln505b0gozwshT55BOBbEHPv3zQVPxtM?= =?us-ascii?q?bGARAnLwy42froCNJ41o8GWGKPBLWZMKLIvlOS6OIvOfGAZIgWuDb4Kvgl5eTi?= =?us-ascii?q?jXgjmV8SZaWpx4EYaXC8HvRnOEqVe2bjgtAEEWsSvgs+S/HqiEGfUTFIeXm+Rb?= =?us-ascii?q?4z5jY+CI6+FYfDXZ6igLiF3Ce8BZ1afHxJCleJEXvwdoWLRvcNaCaWIsN7lTwE?= =?us-ascii?q?T7ehRok83h+trA/306drIvTQ9yECqJ7vyNd46/fdmB0u7zB5AcuQ33mQQ2x6g2?= =?us-ascii?q?8EXSE60aBwrEBn11uPzbJ0j+FaGNBP4f5CTx00OoTGz+NgDtD/QgLBccmNSFah?= =?us-ascii?q?WtimBD4wQs8rz98WZEZ9H9Wjjgzd0CW2A78Vkb2LBIUp8q3CxXTxINx9y3ne2K?= =?us-ascii?q?kgiVkpXNdPOHW7iqJh8wXfHZPFn1mWmqqwe6kQwDTB+WmMwGaWuUFXSg9wUaHL?= =?us-ascii?q?XXAFYUvWqMz06F7eQbGzFbgqKhNBxsCeJKZXctDkk1BISe/7ONTZZ2Kwm3uwCg?= =?us-ascii?q?iUybOMaorqenwd3DjDB0QelAAT53mGOBAkCSeluW3eCiZiFUnzbEPs9Ol+qW+7?= =?us-ascii?q?TlMvwg6RaE1hyry19QILivyHUf8T270JuSg7pzVzBla90MraC8CcqAp5YKVcfd?= =?us-ascii?q?Q97U9b2m3Dsgx9OoWsL6Rjhl4FbwR6pFju1hVyCoVYi8cmtnIqzAxoKaKZylxN?= =?us-ascii?q?bT2Y3YqjcoHQfyP24xblI/rSxVf21MmQvKEC9KJ84x/oowfjXgJ2+Gph+91UyG?= =?us-ascii?q?eHoJTGHQ4WF5XrXRBzvxNzorWfZigm+6vV02dtOO+6qHuK0NUsHMMhyw28ZJFY?= =?us-ascii?q?KqmFCAb2HcoKQcWze8IwnF38RxYNOqhp/64xPt+6P6+P3Ketev1rnDenkXhv+I?= =?us-ascii?q?d5w16B/Cp6S/fV0tAC2f7OjVjPbCv1kFr06pO/ootDfzxHRTLmlHrUQbVJb6g3?= =?us-ascii?q?Rr4lTGejJ8rtnYd7l8erQ3lc5UKuDFMA2da0dFyVdVOvhFQMh3RSmmSunG6D9x?= =?us-ascii?q?Ixiysg9/vNxCvK0vjvfxoBO3dWSS9ll1i+eNHl3eBfZ1Chak0SrDXg4E/7w6ZB?= =?us-ascii?q?o6EmcDvZRlpOdCXtaWQ+Qu23rLXQOsM=3D?= X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: =?us-ascii?q?A0BEAgAtzUdffSIeaIFgg3ZSBkABXlUyL?= =?us-ascii?q?IQ3iQGJPYIQhT+RYoERA1AQAQMBDBgBDAcBAgQBAYN3gyACHQYBBTMTAhABAQU?= =?us-ascii?q?BAQECAQMDBAETAQELFAiGDAyCNwwZgx4BGAkEBjsqIwMUAQYDAhEBFwEUChcBE?= =?us-ascii?q?hQFAYMNgnwFCgOXMpt6fzOEOwEDAgECDgEOCYRCgUINAhOBFoVIS4MBhBEPgU0?= =?us-ascii?q?/gRGCWwdsgkUMCwEBAQEBFoEDBRwBAYM3gmAEj3qKIokdkhdeKgeCZoEKBAuGT?= =?us-ascii?q?YEAhhCEa4ZtgweBJohChTOOIyGSK4dpfYFlhgGGBIRThFCBQSpaDYETMxowQ4J?= =?us-ascii?q?pCQlXDY4qAReBAgEIgkOBPoJiOTuFRD8zAgEBMwIGAQkBAQMJdQEBBRMLAY5qX?= =?us-ascii?q?AEB?= X-IPAS-Result: =?us-ascii?q?A0BEAgAtzUdffSIeaIFgg3ZSBkABXlUyLIQ3iQGJPYIQhT+?= =?us-ascii?q?RYoERA1AQAQMBDBgBDAcBAgQBAYN3gyACHQYBBTMTAhABAQUBAQECAQMDBAETA?= =?us-ascii?q?QELFAiGDAyCNwwZgx4BGAkEBjsqIwMUAQYDAhEBFwEUChcBEhQFAYMNgnwFCgO?= =?us-ascii?q?XMpt6fzOEOwEDAgECDgEOCYRCgUINAhOBFoVIS4MBhBEPgU0/gRGCWwdsgkUMC?= =?us-ascii?q?wEBAQEBFoEDBRwBAYM3gmAEj3qKIokdkhdeKgeCZoEKBAuGTYEAhhCEa4Ztgwe?= =?us-ascii?q?BJohChTOOIyGSK4dpfYFlhgGGBIRThFCBQSpaDYETMxowQ4JpCQlXDY4qAReBA?= =?us-ascii?q?gEIgkOBPoJiOTuFRD8zAgEBMwIGAQkBAQMJdQEBBRMLAY5qXAEB?= X-IronPort-AV: E=Sophos;i="5.76,359,1592863200"; d="scan'208,217";a="465495024" X-MGA-submission: =?us-ascii?q?MDHqW4LVz5IbccmigY+BjSZBo2mSR2LerQDdCO?= =?us-ascii?q?8hF9Ou3JH6setP2DvVXyNDlLfFnPKi5AVJQBbsxSzGBWueKDrE1nZTQL?= =?us-ascii?q?1Dy4spkmhlmhHa3YJHMd8OGGt2grfWIUKF1gWdO6hx3ymu0Ymt5wrlgf?= =?us-ascii?q?IojsqGYioIy231y+PiCV4EXA=3D=3D?= Received: from mx1.polytechnique.org ([129.104.30.34]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 01 Sep 2020 09:55:52 +0200 Received: from set (set.irisa.fr [131.254.10.170]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ssl.polytechnique.org (Postfix) with ESMTPSA id 43493564DD4; Tue, 1 Sep 2020 09:55:51 +0200 (CEST) From: Alan Schmitt To: "lwn" , "cwn" , caml-list@inria.fr, comp@lists.orbitalfox.eu Date: Tue, 01 Sep 2020 09:55:51 +0200 Message-ID: <87imcy9bi0.fsf@m4x.org> MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="=-=-=" X-AV-Checked: ClamAV using ClamSMTP at svoboda.polytechnique.org (Tue Sep 1 09:55:51 2020 +0200 (CEST)) X-Spam-Flag: No, tests=bogofilter, spamicity=0.000024, queueID=7F1D1564DDC X-Org-Mail: alan.schmitt.1995@polytechnique.org Subject: [Caml-list] Attn: Development Editor, Latest OCaml Weekly News Reply-To: Alan Schmitt X-Loop: caml-list@inria.fr X-Sequence: 18232 Errors-To: caml-list-owner@inria.fr Precedence: list Precedence: bulk Sender: caml-list-request@inria.fr X-no-archive: yes List-Id: List-Help: List-Subscribe: List-Unsubscribe: List-Post: List-Owner: List-Archive: Archived-At: --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hello Here is the latest OCaml Weekly News, for the week of August 25 to September 01, 2020. Table of Contents =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80 Writing bindings for Google Apps Script (GAS) What the Jane Street interns have wrought a small library for shell/AWK/Perl-like scripting letters 0.2.0 raylib-ocaml 0.1.0 OCaml Workshop 2020 Online Conference is live now Other OCaml News Old CWN Writing bindings for Google Apps Script (GAS) =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90 Archive: Danielo Rodr=C3=ADguez announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80 Thanks to the help of this community I successfully completed a crazy idea: To write some ocaml functions to use inside [Google Apps Script] for a small stupid spreadsheet that I had. The way it works now is by having a main index.js file that calls the Ocaml functions that are available under a global Lib namespace. Everything is bundled using parcel and the Idea was to use as few JS code as possible. Because it was easier than I expected I decided to go one step further and write some bindings for the GAS functions I was using and reduce the glue JS code even more. This are the bindings that I wrote so far. They work, but are not usable inside Ocaml yet. =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 type spreadsheet =E2=94=82 type sheet =E2=94=82 type range =E2=94=82 external getActiveSpreadsheet : unit -> spreadsheet =3D "getAct= iveSpreadsheet" [@@bs.val][@@bs.scope =E2=94=82 "SpreadsheetApp"] =E2=94=82 external getSheets : spreadsheet -> sheet array =3D "getSheets"= [@@bs.send] =E2=94=82 external getSheetByName : spreadsheet -> string -> sheet =3D "g= etSheetByName" [@@bs.send] =E2=94=82 external getDataRange : sheet -> range =3D "getDataRange" [@@b= s.send] =E2=94=82 external getValues : range -> 'a array array =3D "getValues" [= @@bs.send] =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 My doubt are on the edges. When it is just obscure GAS stuff I have no doubt, abstract types and functions to interact with them. Is when a GAS function returns data where I have doubts. Usually they are just arrays of arrays of Numbers or Strings. In the example above, the last definition says that you will get an array of arrays of `'a', but that is not true because it will be an array of "stuff" (strings, numbers, floats). How should I type it in a way that it's flexible but not cumbersome? For example, I don't think using a functor will help because you will need to create a functor for every possible return type, in my case if you have 3 sheets with 3 different shapes, you will need 3 functors. An alternative that I have used was to provide some helper functions to convert from JS to Ocaml types and then unwrap the Ocaml types, like the example I'm doing with Number_or_string. This is nothing serious and I will just add the bindings that I may need for now, but I want to hear what the community (and potential users) thinks. If anyone is interested in taking a look on the project, it is here: [Google Apps Script] Matthieu Dubuget said =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Not answering directly to your question, sorry. But here is a binding I have been using for around 4 years: . Hongbo Zhang also replied =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 For return type polymorphism, you can use GADT with bs.ignore, the rough idea: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 type 'a t =3D Int : int t | String : string t =E2=94=82 external f : ('a t [@bs.ignore]) -> ... -> 'a =3D "xx" =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 I read discuss.ocaml.org from time to time, but checks daily where you can get a quick answer What the Jane Street interns have wrought =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: Yaron Minsky announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 I thought folks here might find this interesting: The post summarizes three of the intern projects that happened this summer at Jane Street. It might be interesting if you're looking for an internship (or know someone who is), or if you're interested in any of the underlying tech. For example, if there's significant interest in a library for writing OCaml, we'd be more likely to open-source it. a small library for shell/AWK/Perl-like scripting =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: Oleg announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Some time ago Chet Murthy asked about writing shell-like scripts in OCaml. Prompted by it, I also want to report on my experience and announce a small library that made it pleasant to do shell/AWK/Perl-like scripting in OCaml. The library is available at and consists of two small ML files, myawk.ml and strings.ml. The latter collects general-purpose string operations, more convenient than those in Stdlib.String. The rest of that web directory contains half a dozen sample scripts with comments. Here is the first example: a typical AWK script, but written in OCaml: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 #!/bin/env -S ocaml =E2=94=82=20 =E2=94=82 #load "myawk.cma" =E2=94=82 open Myawk open Strings =E2=94=82 let hash =3D string_of_int <|> Hashtbl.hash =E2=94=82 ;; =E2=94=82 (* Sanitize the files originally used by join1.ml and join2.ml =E2=94=82 The files are made of space-separated fields; the first fiel= d is the =E2=94=82 key. It is sensitive; but because it is a key it can't be re= placed with =E2=94=82 meaningless garbage. We obfuscate it beyond recognition. The= third field =E2=94=82 is obfuscated as well. The second and fourth can be left as = they are, =E2=94=82 and the fifth, if present, is replaced with XXX =E2=94=82=20 =E2=94=82 The script is a proper filter: reads from stdin, writes to s= tdout =E2=94=82 *) =E2=94=82=20 =E2=94=82 for_each_line @@ map words @@ function (f1::f2::f3::f4::rest) -> =E2=94=82 print [hash f1; f2; hash f3; f4; if rest =3D [] then "" else = "XXX"] =E2=94=82 ;; =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Here <|> is a function composition. I wish it were in Stdlib. The real example, used in real life, was performing a database join =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 SELECT T2.* from Table1 as T1, Table2 as T2 where T1.f1 =3D T2.= f1 =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 where Table1 and Table2 are text files with space-separated column values. Table1 is supposed to be fed to stdin: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 let () =3D =E2=94=82 for_each_line @@ map words @@ =E2=94=82 map_option (function (x::_) -> Some x | _ -> None) @@ =E2=94=82 (ignore <|> shell "grep %s table1.txt") =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 It is a typical rough-and-dirty script. Alas, it was too rough: I was so excited that it typechecked and worked the first time, that I didn't look carefully at the output and overlooked what I was looking for (resulting in an unneeded hassle and apology). I should have queried exactly for what I wanted: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 SELECT T1.f1, T1.f4 FROM Table1 as T1, Table2 as T2 =E2=94=82 WHERE T1.f1 =3D T2.f1 AND T1.f3 <> "3" =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 which is actually easy to write in myawk (probably not so in AWK though) =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 let () =3D =E2=94=82 for_each_line ~fname:"table2.txt" @@ map words @@ =E2=94=82 map_option (function (w::_) -> Some w | _ -> None) @@ =E2=94=82 fun w -> =E2=94=82 for_each_line ~fname:"table1.txt" @@ map words @@ =E2=94=82 map_option (function =E2=94=82 (x::f2::f3::f4::_) when x =3D w && f4 <> "3" -> Some [x;f4= ] | _ -> None) @@ =E2=94=82 print =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 This is the classical nested loop join. Chet Murthy might be pleased to see the extensive use of the continuation-passing style. I was apprehensive at first, but it turned out not to be a hassle. The library has a few other examples, including case-branching and rewriting a real AWK script from the OCaml distribution. Finally, let's compare with shell scripts. The example below doesn't show off the library, but it does show the benefits of OCaml for scripting. The original shell script is a sample GIT commit hook, quoted in the comments: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 (* =E2=94=82 From GIT's sample hooks: =E2=94=82 ANY-GIT-REPO/.git/hooks/commit-msg.sample =E2=94=82=20 =E2=94=82 # Called by "git commit" with one argument, the name of the f= ile =E2=94=82 # that has the commit message. The hook should exit with non= -zero =E2=94=82 # status after issuing an appropriate message if it wants to = stop the =E2=94=82 # commit. The hook is allowed to edit the commit message fil= e. =E2=94=82=20 =E2=94=82 # This example catches duplicate Signed-off-by lines. =E2=94=82=20 =E2=94=82 test "" =3D "$(grep '^Signed-off-by: ' "$1" | =E2=94=82 sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { =E2=94=82 echo >&2 Duplicate Signed-off-by lines. =E2=94=82 exit 1 =E2=94=82 } =E2=94=82=20 =E2=94=82 *) =E2=94=82 module H =3D Hashtbl =E2=94=82=20 =E2=94=82 let commit_msg =3D Sys.argv.(1) =E2=94=82 let ht =3D H.create 5 =E2=94=82 let () =3D =E2=94=82 for_each_line ~fname:commit_msg @@ fun l -> =E2=94=82 if is_prefix "Signed-off-by: " l <> None then begin =E2=94=82 if H.find_opt ht l <> None then begin =E2=94=82 prerr_endline "Duplicate Signed-off-by lines."; =E2=94=82 exit 1 =E2=94=82 end else =E2=94=82 H.add ht l () =E2=94=82 end =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Although the OCaml script seems to have more characters, one doesn't need to type them all. Scripts like that are meant to be entered in an editor; even ancient editors have completion facilities. Looking at the original shell script brings despair, and drives me right towards Unix Haters. Not only the script is algorithmically ugly: if a duplicate signed-off line occurs near the beginning, we can report it right away and stop. We don't need to read the rest of the commit message, filter it, sort it, precisely count all duplicates and filter again. Not only the script gratuitously wastes system resources (read: the laptop battery) by launching many processes and allocating communication buffers. Mainly, the script isn't good at its primary purpose: it isn't easy to write and read. Pipeline composition of small stream processors is generally a good thing =E2=80=93 but not when = each stream processor is written in its own idiosyncratic language. Incidentally, I have doubts about the script: I think that quotes around $1 are meant to be embedded; but why they are not escaped then? Probably it is some edge case of bash, out of several 0thousands. In contrast, OCaml script does exactly what is required, with no extra work. Everything is written in only one language. letters 0.2.0 =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: Miko announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Getting this release done took a bit longer than expected due to some real life factors, but finally here it is. This one mainly focuses on the most requested features and improvements like simplifying configuration around CA certificates, provides some basic documentation and additionally adds support for `multipart/alternative' emails with combined HTML and plain text content. jerben then added =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80 Link to Github: raylib-ocaml 0.1.0 =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90 Archive: Tobias Mock announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 I'd like to announce the first version of [raylib-ocaml], a binding to the awesome [raylib] game development library. The release can be found on opam as ["raylib"]. The bindings are nearly complete, as far as functions and types go, but only a subset was tested so far. I will work on bringing more of the numerous examples of the C version to OCaml in the future. Currently, raylib-ocaml only works on Linux, but I plan to support Windows (and possibly other targets) in the future. Feel free to give it a spin and please report any issues you run into. [raylib-ocaml] [raylib] ["raylib"] OCaml Workshop 2020 Online Conference is live now =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95= =90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: Deep in this thread, Didier Wenzek announced =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80 [OCaml 2020 All Videos] [OCaml 2020 All Videos] Other OCaml News =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2= =95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 >>From the ocamlcore planet blog =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2= =94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94= =80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Here are links from many OCaml blogs aggregated at [OCaml Planet]. =E2=80=A2 [BuckleScript Good and Bad News] =E2=80=A2 [What the interns have wrought, 2020 edition] =E2=80=A2 [Coq 8.12.0 is out] [OCaml Planet] [BuckleScript Good and Bad News] [What the interns have wrought, 2020 edition] [Coq 8.12.0 is out] Old CWN =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 If you happen to miss a CWN, you can [send me a message] and I'll mail it to you, or go take a look at [the archive] or the [RSS feed of the archives]. If you also wish to receive it every week by mail, you may subscribe [online]. [Alan Schmitt] [send me a message] [the archive] [RSS feed of the archives] [online] [Alan Schmitt] --=-=-= Content-Type: text/html; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: quoted-printable OCaml Weekly News

OCaml Weekly News

Previous Week Up Next Week

Hello

Here is the latest OCaml Weekly News, for the week of August 25 to Septembe= r 01, 2020.

Writing bindings for Google Apps Script (GAS)

Danielo Rodr=C3=ADguez announced

Thanks to the help of this community I successfully completed a crazy idea:= To write some ocaml functions to use inside Google Apps Script for a small stupid spreadsheet that I had.

The way it works now is by having a main index.js file that calls the Ocaml= functions that are available under a global Lib namespace. Everything is bundled using parcel = and the Idea was to use as few JS code as possible. Because it was easier than I expected I decided to= go one step further and write some bindings for the GAS functions I was using and reduce the glue J= S code even more.

This are the bindings that I wrote so far. They work, but are not usable in= side Ocaml yet.

type spreadsheet
type sheet
type range
external getActiveSpreadsheet : unit -> spreadshee=
t =3D "getActiveSpreadsheet" [@@bs.val][@@bs.scope
"SpreadsheetApp"]
external getSheets : spreadsheet -> sheet array =
=3D "getSheets" [@@bs.send]
external getSheetByName : spreadsheet -> string -&=
gt; sheet =3D "getSheetByName" [@@bs.send]
external getDataRange : sheet -> range =3D "getDataRange"  [@@bs.send]
external getValues : range -> 'a array array =3D <=
span style=3D"color: #8b2252;">"getValues"  [@@bs.send]

My doubt are on the edges. When it is just obscure GAS stuff I have no doub= t, abstract types and functions to interact with them. Is when a GAS function returns data where = I have doubts. Usually they are just arrays of arrays of Numbers or Strings. In the example above, the = last definition says that you will get an array of arrays of 'a, but that is not true be= cause it will be an array of "stuff" (strings, numbers, floats). How should I type it in a way that it's flexible but not cumbersome? For ex= ample, I don't think using a functor will help because you will need to create a functor for every possi= ble return type, in my case if you have 3 sheets with 3 different shapes, you will need 3 functors. An alternative that I have used was to provide some helper functions to con= vert from JS to Ocaml types and then unwrap the Ocaml types, like the example I'm doing with Number_or_= string. This is nothing serious and I will just add the bindings that I may need fo= r now, but I want to hear what the community (and potential users) thinks.

If anyone is interested in taking a look on the project, it is here: htt= ps://github.com/danielo515/ElectronicProjectsSpreadsheet

Matthieu Dubuget said

Not answering directly to your question, sorry.

But here is a binding I have been using for around 4 years: https://= dubuget.fr/gitea/matthieu/ocaml-google-app.git.

Hongbo Zhang also replied

For return type polymorphism, you can use GADT with bs.ignore, the rough id= ea:

type 'a t =3D  Int : int t | String : stri=
ng t
external f : ('a t [@=
bs.ignore]) -> ... -> 'a =3D "=
xx"

I read discuss.ocaml.org from time to time, but checks https://forum.rescript-lang.org/ daily where y= ou can get a quick answer

What the Jane Street interns have wrought

Yaron Minsky announced

I thought folks here might find this interesting:

https://blog.janestreet.com/what-the-interns-have-wrought-2020/

The post summarizes three of the intern projects that happened this summer = at Jane Street. It might be interesting if you're looking for an internship (or know someone who is), o= r if you're interested in any of the underlying tech. For example, if there's significant interest in= a library for writing OCaml, we'd be more likely to open-source it.

a small library for shell/AWK/Perl-like scripting

Oleg announced

Some time ago Chet Murthy asked about writing shell-like scripts in OCaml. Prompted by it, I also want to report on my experience and announce a small library that made it pleasant to do shell/AWK/Perl-like scripting in OCaml.

The library is available at
http://okmij.o= rg/ftp/ML/myawk/0README.dr
and consists of two small ML files, myawk.ml and strings.ml. The latter collects general-purpose string operations, more convenient than those in Stdlib.String. The rest of that web directory contains half a dozen sample scripts with comments.

Here is the first example: a typical AWK script, but written in OCaml:

#!/bin/=
env -S oc=
aml

#load 
open Myawk open Strings
let hash =3D string_of_int <|> Hashtbl.hash
;;
(* S=
anitize the files originally used by join1.ml and join2.ml
   The files are made of space-separated fi=
elds; the first field is the
   key. It is sensitive; but because it is =
a key it can't be replaced with
   meaningless garbage. We obfuscate it bey=
ond recognition. The third field
   is obfuscated as well. The second and fo=
urth can be left as they are,
   and the fifth, if present, is replaced w=
ith XXX

   The script is a proper filter: reads fro=
m stdin, writes to stdout
 *)<=
/span>

for_each_line @@ map words @@ function (f1::f2::f3<=
span style=3D"color: #000000; background-color: #ffffff;">::f4::rest) ->
  print [hash f1; f2; hash f3; f4; if rest =3D [] then "" else "XXX"]
;;

Here <|> is a function composition. I wish it were in Stdlib. The real example, used in real life, was performing a database join

SELECT T2.* from Table1 as T1, Table2 as T2 where T1.f1 =3D T2.f1

where Table1 and Table2 are text files with space-separated column values. Table1 is supposed to be fed to stdin:

let () =3D
  for_each_line @@ map words @@
  map_option (function (x::_) -> =
Some x | =
_ -> None) @@
  (ignore <|> shell "grep %s table=
1.txt")

It is a typical rough-and-dirty script. Alas, it was too rough: I was so excited that it typechecked and worked the first time, that I didn't look carefully at the output and overlooked what I was looking for (resulting in an unneeded hassle and apology). I should have queried exactly for what I wanted:

SELECT T1.f1, T1.f4 FROM Table1 as T1, Table2 as T2
WHERE T1.f1 =3D T2.f1 AND T1.f3 <> "3"

which is actually easy to write in myawk (probably not so in AWK though)

let () =3D
  for_each_line ~fname:"table2.txt" @@=
 map words @@
  map_option (function (w::_) -> =
Some w | =
_ -> None) @@
  fun ~fname:"table1.txt" @@=
  map words @@
    map_option (function
     (x::=
f2::f3::f4::_) when x =3D w && f4 <> "3" -> Some [x;f4] | _ -> None) @@
    print

This is the classical nested loop join. Chet Murthy might be pleased to see the extensive use of the continuation-passing style. I was apprehensive at first, but it turned out not to be a hassle.

The library has a few other examples, including case-branching and rewriting a real AWK script from the OCaml distribution.

Finally, let's compare with shell scripts. The example below doesn't show off the library, but it does show the benefits of OCaml for scripting. The original shell script is a sample GIT commit hook, quoted in the comments:

(*
From GIT's sample hooks:
  ANY-GIT-REPO/.git/hooks/commit-msg.sample=


  # Called by "git commit" with one argumen=
t, the name of the file
  # that has the commit message.  The hook =
should exit with non-zero
  # status after issuing an appropriate mes=
sage if it wants to stop the
  # commit.  The hook is allowed to edit th=
e commit message file.

  # This example catches duplicate Signed-o=
ff-by lines.

test "" =3D "$(grep '^Signed-off-by: ' "$1"=
 |
         sort | uniq -c | sed -e '/^[   ]*1=
[    ]/d')" || {
        echo >&2 Duplicate Signed-of=
f-by lines.
        exit 1
}

*)
module H =3D Hashtbl<=
/span>

let commit_msg =3D =
Sys.argv.(1)
let ht =3D H.create 5
let () =3D
  for_each_line ~fname:commit_msg @@ fun=
 l ->
  if is_prefix "Signed-off-by: " l <> None =
then begin
    if H.find_opt ht l <> None then =
begin
      prerr_endline "Duplicate Signed-off-b=
y lines.";
      exit 1
    end else
      H.add ht l ()
  end

Although the OCaml script seems to have more characters, one doesn't need to type them all. Scripts like that are meant to be entered in an editor; even ancient editors have completion facilities.

Looking at the original shell script brings despair, and drives me right towards Unix Haters. Not only the script is algorithmically ugly: if a duplicate signed-off line occurs near the beginning, we can report it right away and stop. We don't need to read the rest of the commit message, filter it, sort it, precisely count all duplicates and filter again. Not only the script gratuitously wastes system resources (read: the laptop battery) by launching many processes and allocating communication buffers. Mainly, the script isn't good at its primary purpose: it isn't easy to write and read. Pipeline composition of small stream processors is generally a good thing – but not when = each stream processor is written in its own idiosyncratic language. Incidentally, I have doubts about the script: I think that quotes around $1 are meant to be embedded; but why they are not escaped then? Probably it is some edge case of bash, out of several 0thousands.

In contrast, OCaml script does exactly what is required, with no extra work. Everything is written in only one language.

letters 0.2.0

Miko announced

Getting this release done took a bit longer than expected due to some real = life factors, but finally here it is.

This one mainly focuses on the most requested features and improvements lik= e simplifying configuration around CA certificates, provides some basic documentation and additionally = adds support for multipart/alternative emails with combined HTML and plain text= content.

jerben then added

raylib-ocaml 0.1.0

Tobias Mock announced

I'd like to announce the first version of raylib-ocaml, a binding to the awesome raylib game = development library. The release can be found on opam as "rayli= b".

The bindings are nearly complete, as far as functions and types go, but onl= y a subset was tested so far. I will work on bringing more of the numerous examples of the C version= to OCaml in the future.

Currently, raylib-ocaml only works on Linux, but I plan to support Windows = (and possibly other targets) in the future.

Feel free to give it a spin and please report any issues you run into.

OCaml Workshop 2020 Online Conference is live now

Deep in this thread, Didier Wenzek announced

Other OCaml News

From the ocamlcore planet blog

Old CWN

If you happen to miss a CWN, you can send me a message and I'll mail it to you, or go take a loo= k at the archive or the RSS feed of the archives<= /a>.

If you also wish to receive it every week by mail, you may subscribe online.

--=-=-=--