From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Authentication-Results: plum.tunbury.org; dkim=pass (1024-bit key; unprotected) header.d=inria.fr header.i=@inria.fr header.a=rsa-sha256 header.s=dc header.b=Wc7pAjIm; dkim-atps=neutral Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=192.134.164.83; helo=mail2-relais-roc.national.inria.fr; envelope-from=caml-list-owner@inria.fr; receiver=tunbury.org Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by plum.tunbury.org (Postfix) with ESMTPS id 5CC394008B for ; Tue, 29 Sep 2026 07:10:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=inria.fr; s=dc; h=from:to:date:message-id:mime-version:subject:reply-to: sender:list-id:list-help:list-subscribe:list-unsubscribe: list-post:list-owner:list-archive; bh=dwgkioJ8tI7hwXcMDDFPsh0Q1jaYm8t2dNWTb9gGabc=; b=Wc7pAjImED1ohg0823icm8zZuWRwZZjVfrGhOz0zaVyJhIPpHaGgInwA J6DIBlNuErF1eX37TO6LlWfA3MdBig4Mfh8trj3XLXISA+ZZlED9A5YhP aM38FMihA8Wr991gc0EQYArBqqxSs2eZwEr1mxEqqnLqmwZBD85TI8Rdz 8=; X-CSE-ConnectionGUID: zRcHRSafSXeoIzZHSOwmyw== X-CSE-MsgGUID: rxNffNQDToyhtkQddQT2+g== Authentication-Results: mail2-relais-roc.national.inria.fr; dkim=none (message not signed) header.i=none; spf=SoftFail smtp.mailfrom=caml-list-owner@inria.fr; spf=None smtp.helo=postmaster@prod-sympa-app.inria.fr Received-SPF: SoftFail (mail2-relais-roc.national.inria.fr: domain of caml-list-owner@inria.fr is inclined to not designate 128.93.162.27 as permitted sender) identity=mailfrom; client-ip=128.93.162.27; receiver=mail2-relais-roc.national.inria.fr; envelope-from="caml-list-owner@inria.fr"; x-sender="caml-list-owner@inria.fr"; x-conformance=spf_only; x-record-type="v=spf1"; x-record-text="v=spf1 ip4:128.93.142.0/24 ip4:192.134.164.0/24 ip4:128.93.162.160 ip4:128.93.162.3 ip4:128.93.162.88 ip4:89.107.174.7 mx ~all" Received-SPF: None (mail2-relais-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@prod-sympa-app.inria.fr) identity=helo; client-ip=128.93.162.27; receiver=mail2-relais-roc.national.inria.fr; envelope-from="caml-list-owner@inria.fr"; x-sender="postmaster@prod-sympa-app.inria.fr"; x-conformance=spf_only X-IronPort-AV: E=Sophos;i="6.27,130,1787004000"; d="asc'?scan'208,217";a="297446115" Received: from prod-sympa-app.inria.fr ([128.93.162.27]) by mail2-relais-roc.national.inria.fr with ESMTP; 29 Sep 2026 09:10:53 +0200 Received: by prod-sympa-app.inria.fr (Postfix, from userid 990) id 5C1218232D; Tue, 29 Sep 2026 09:10:53 +0200 (CEST) Received: from mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by prod-sympa-app.inria.fr (Postfix) with ESMTP id 83FA081DBB for ; Tue, 29 Sep 2026 09:10:42 +0200 (CEST) X-CSE-ConnectionGUID: 6vrr/KEOQ0SSyeYKdWdWCg== X-CSE-MsgGUID: pB8SY6wESlmDxlL5jJNhSw== IronPort-SDR: 6abb6470_OSy88+tAjrFJF4J5j8iVEkZXA0srq5MEVfGV+tM8tK+9eLP UAx/911++Jj0xHMeoJd+88ZzvfeVd2Z+mVwt1dg== X-ThreatScanner-Verdict: Negative X-IPAS-Result: =?us-ascii?q?A0EABQD0YrtqhSIeaIFQCh4BEgsBDINNgQQbAW9hGRoHC?= =?us-ascii?q?EmEWINPjiSBFpA2inwNgmodFiECDgcBAwEIBS4BGwQBAgQBAQECAQIBgguCL?= =?us-ascii?q?UYCjgkCHwYBBDQTAQIEAwIDAQEBAQEBAQEBAQELAQEBBAEBAQIBAQIEAwEBA?= =?us-ascii?q?QECEAEBAQFASYYVATkNi31RcWAEAwY4AQEBAQEBAQEBAQEBAQEBAQEBAQEBA?= =?us-ascii?q?QEBAQEBAQEBAQEBAQEBAQEBAQEBAgQIARkQdQkEBhMBATgYIwMUAQYDAhEBN?= =?us-ascii?q?RcBEhqCaAGCIAICUAMFDAaWVppSGzd6fzOBAYIMAQEGgQk+AgELAgIDDy4B2?= =?us-ascii?q?hqBYgkJFIEhGIFYhBqCUQ8NAStJagIBAoRRCYQ4Jw+BVUSBFTWCPgdvggJBH?= =?us-ascii?q?gEBAQFcVQsBAQhEAQmDJYJqgiZ6EhuBXWABBEqBF4VWixyCQiwBVRMXCwcFX?= =?us-ascii?q?oEIAyovLW4yHYEjPhcvWBsGBYEdgSCCGSMZNnqBCV6BKylhEBeBB4IHAoJUg?= =?us-ascii?q?gECAUlDDgdFUwklRRJHJiIIEgkBExowC4EhOEEJKD9tPTcVGY8MECENgUtIG?= =?us-ascii?q?R6Bex0OPgJgIwoBByIBASACDSkjEQQBBwMWAxkbBEAGCwsgBwgDkkMUKJ4hk?= =?us-ascii?q?1mBCjQHhCGBYAYMiQqBJpYHhASBV4s9hwOSVCKYZiOCNocoXUQFCYFvH0yFI?= =?us-ascii?q?o4kgW4shVmBfyOBKxsPBzMaMEOCMwEzCUccD1iHSoRdgS8WgzgoQX2BIQWBI?= =?us-ascii?q?1E7xwhCNQIBATsHAgcBDASFawEBjDqBTAEB?= IronPort-PHdr: A9a23:8ylfQRNhqdM6IDMY2bsl6nZlAxdPi9zP1u491JMrhvp0f7i5+Ny6Z QqDvqsr1AWCAtiLs7ptsKn/jePJYSQ4+5GPsXQPItRndiQuroE7uTJlK+O+TXPBEfjxciYhF 95DXlI2t1uyMExSBdqsLwaK+i764jEdAAjwOhRoLerpBIHSk9631+ev8JHPfglEnjWwbL1zI RmssQndqMYajIliJ6sy1hfCv2dFdflRyW50Kl2fmArx6N2t95B56SRQvPwh989EUarkeqkzU KJVAjc7PW0r/cPnrRbNQxOA6XcFTGgYnQdGDxDK4x/mUJjxtDD6tvdm1ymBIcL2V7E0Vi+84 KptVRTllT0INz898GHQl8xwkKdWqw+vqhBj34LZZpyeO/1jcKPAZtMaXXROUdpNVyJPBYO8a pEAD+sHPe1Fq4XwqF8DoR64CAKxBu3g1yVIi2f206MkzuovHwLI0wM8EN8Vv3TYsM/4Ob0OX eypzqTFyyjIYfNM2Tf67YjFagwsofWWUrJ2bMHf1FUgFwPAjlWRtYzlIy6e2+MXvGif9eVgU /iji3U7pAFxpzivx9ssipXSi4INzVDE8SV4wJorKtKkSE57Z9+kEIJNty6ELYd2RdkiQ25xt Ss817YJtoK1cjIQx5Q72x7QdeaHc46Q7x7/VOidPzZ1iXxqdb+8iBu//1StxOPhWsS30FtEo DRJn9fOu30C1xLd5cyKR/R880u91juDyQLe5+9LLE01iafWLYMqzLA3lpoWq0vDHyn2lV3uj KCIakUk+/So5Pr/YrXho5+cMpF7hhv4MqswhsyzGeM4PRQUUGie/eSwzrrj/Vf2QLlSgf02k 7XZsJDHJcsAvKK2HwhV0oM75xawDjemzNQYnWQcI15feRKHiJDlNE/KIPD9FPu/h06jkDFkx /zcOb3hGJrNImDfkLj7fLZ970BdyAs1zd9C+51UEaoBLOjvVU/2sdzUFhA5PBa1wun9B9V90 JkRWWOVAqCHKq/StkWI5u03L+aQZI8aojD9K/c76P71l3M5nEIScbGo3ZsRcnC4H+5pL1+XY Xr2mtsBEGEKvhQkQ+zwiV2NSzhTZ2qyX6Il/D00FZypDZnbSoC2g7yB3SO7HplMamBDF1+AC Wnnd5+eW/gWdCKSI9ZhkiEaWrS7V4Ah1QmitAjmxLp8L+rU9TMXtZT52Nhy/e3Tmgk+9T5vD 8iH0mGNU2d5lX4LST8uxK1zvFJxx1OZ3aRln/BVGsZf6v1VXgsgO5PRwPR2B838Vw7cZNuFV larT9q8DT0vU9492cECbkl5FtikkxvNxTClA6UPmLyOHJE08rzT33z2J8tlznbH27Qtg0M+Q stIMW2nhrJ/+BbPCI7JlUWZlr+qdbkC0yLX82eD12WOsFlZUA52T6rFQWgSalbIodn9/E/OU qOiBLs9PgZP1cKOMKVHZ9LxgVVDXvjjOdDeY2yrm2e3ABaF3q6CYpb3dWkBxCjdDEoLnh4T8 nueNwYxCT+so3rZDDxqFVPvf13j/vV+qHO9T0801hyKYFN727qy4B4ViuSRROkX3r0evicts S50E0q939LTCtqAuxZhcb5HbtM6/VdH037WuBJmPpC6KqBviVEffx5wv0P02BV7Ep9AntQyr HM20ApyLrqV309beDOd2ZD8I7nXKmjp/BCzcKPWwVHf0NOO+qgV8vg4qlPjvBuoFkU46Xln3 cNV32Oa5prRFAUSS47+Ul4r9xhmoLHXejQx65vb1XJyNqm6sSXM1sopCuU50hqgZclQML2HG gHoC8AaAsevJPEwl1ixaRIEOOBT9LIqMMy6d/uG3q+rPP99nD24l2hH55p90k2U+yVhSe7I3 pMFzumA0AWIWTjykkuvv9zxl4xceD4SG3CwyTL4C4NJfqN8ZJ4FB2i2L82s3tV+iYbgVWRE+ VC+Gl0KwNSpeQKcb1Pl3Q1fy0AXoXu/lCWi0zF6jiwn/eKj23mEx/vkPlJTPnFNbG19ixHqL JTiy5gRVU2sKgwojweN5EDgxqEdqr4sAXPURBJheyHwZ1ppUq6xqqbKN8dL4ZVuqi5XVeWgf XiCTbrsvxYR0yXiBnZTgjcheGf56d3CgxVmhTfFfz5Ip33DdJQslH83hfTZTP9VhX8dQTVgz CLQHh66NsWo+tOdk9HCtPq/XiSvTM4bajHlmKWHsibz/mh2GVunhfnmk9nuF04h2i/+1sV2f T3PqAfgb4Lr0aWjLO8heVNnVxfn88QvIohlicMrgY0In30Th5Gb530CxFzJCo0O3ZPVUy8te 2sTxNrE/AXu2EtiN2+EgYXjWSCUxsJnIcKxYmYXxj4V5cdXDqyZ9/pBwTszpUC3/krKefYop j4G0rM17WICxeEEvA141iKGHrUbBlVVJwTph03O99e6vblab2apcKGt2Qx5h9/J4KiqhAZaV T65f54jGXQ19cBjKBfX12W17Ij4ed7WZNZVtxuOkh6GgfIHYJQ23uEHgyZqIwef9TUs1vI7g Bpy3Jq7oJnPKmNj+7i8CwJZMTu9bt0a+zXkh6JT1siM2IXnEpJkEzQNFJzmKJDgWDsWvPKhL A2OFTwgtl+DHr7OAQKU6EFntm/CVZexODDfJXUUy8ljWAjIPFZW02V2FH0xmp80EBzvxdS0K R0ooGlJuhij8l0XlrENVVG3SGrUqQa2Zy1hTZGeKEET9QRe/wLONtTY6OtvHiZe95nnrQqXK 2XdaR4baANBEkGCGV3nOaGjoNfa9O3NTNGEFKObZYSllrl+aaKQwpa+zoZt/zCNL9iCeH54A Kgy3kNFG2tyG8HYhyknQSsKkSnAdIie+Af6/Td45JPakryjSEf06I2DBqEHe9xr8hbwmqyDM u+MmA5hLjJJyp4HxXnJ0aUSmlkIhGs9ElvlWaRFvinLQqXKn6ZRBBNOcCJ/OvxD6Kck1xVMM 8rW4j/s/oZxleV9S1JMVFi639qsedRPOGalclXOGEeMMr2CYzzN2cD+J62mG/Vci+Bdthv4v jj+cQerBQ64z2ztZjuQZMFy2TmcOA1CtYq9dBd0FGWlS8jpPxS/OdkxljY2xLwomlvAMnMaO jVnNUYRvvuX9yw94L03F2Fa73VjJPWJgG7Atbiec85K96AzRH8o3+tBqGw30b5U8D1JSLRul S3eo8QvxjPu2uiDxzx7UQZf/zNChYaFp0Jnau3S8phNX2qB/QpYtD/BTU1S+50+Upu05/M1q JCHjq/4JTZc/siB+MIdA5ORM8ebKD86NgKvHjfIDQwDRDrtNGfFhkUbnuvBkx/d5pU8tJXon 4IDD7FBU1lgXMggMRwwGO0pH8JXYGY8lrqKkMMD5Xy/tQTcAsJAscXOUvuUR+7kKDOYkaVsb RwVx7j1NsIWap293FZtIAof/syCCw/LUNZBrzc0JDQOmx0Y9ElVcTgT5Rf9bQe8/HIYFfi1h wM7zAxkbrEk8D7qpUw8Jl/LuDcYmk4sn97omnaULC63K72/F9IzaWK8pw06NZX1RBxwZAu5k Bl/NTvKcLlWiqNpaWFhjAKP8YsKA/NXSrdIJQMB3fzCLet9ykxS82/0oC0PrfuAE5ZpkxEmN IKhv24VkRw2d8Y7fOSTJbIVnAEK1+TX5nPujbh3m1NWZEcVrDHLIn9O4RRUcOJ+YXH1m44ko U+Dg2cRKTFKDqBz5KwwsBplZKzDzjq+geQbchnja7WTd/GQ6TfJmJPaEA08iRNazBIgn/A+k sY7LRjODxh2nufIG0xbbJiTdQ1YPZgNrybfL3nS7r2FhJtxO8/V+vnAdeaVr+5Uh0ulGF1sB IEQ9oEaGYHq1kjELMDhJbpDyBM35Q2tKk/XRPhOfRuKln8AraTdhNdv2pJBIzgGHWhnGSCnv /DPoQs7nPeIXNE3e2oXGIweOTo6Vda7lChQo3lbRGDtg6RAkFTEtGe6/XiYBSKZDZIrfPqOY BJwFNy6sS4y9aS7kx+f85nTIX37KcU3utLL7rBSrJKGBvVICLhl5h6Gys8BHyDsCDaJSoLmQ vq4I5MhZtH1FHugB1m2ijZuCtz0IM7oNa+QxwfhWYdTtoCfmjElL860UD8ESHIS76kO4rxxY Qobbt81exnt4k4FDZfndQOp+er7Y1j4MTxSXuVSxuW8ZqVKwmwrdODvwX8pSNchxOmy8FIRb JsNkxfVyO3lYtVOFy/pFTYOHmeH7Tp8jGVnOusol60nxwjUtFAHLz2RXOl5MSpcuNUtGV6ZI XN3E3c1AViGgsCQh2zkl6BX9CxbkdFO1ORDu3WrpZ7TbgWnX6mzoInUuS4tPpA25rd8Oov5L o6apYvTy3bBGYLIvFTPA0vYX7JK38JdKyVCTLxUlHE5bIYY7JFZ5xN5X497LrhLQsHESZigb idiBiMJiypFR8WHxjNQ249UOpPfhk7WaJMmIQAJu5VEg8IAXmhxeCxM/cdLsq3OkGuVVmUAI AES9BlBogUamd0oFt0= IronPort-Data: A9a23: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 IronPort-HdrOrdr: A9a23:x+f/la7UsecStXEC7QPXwPfXdLJyesId70hD6qkRc202TiX8ra rCoB11737JYVoqNE3I+urwW5VoI0m9yXcd2+B4VotKNzOJhILHFu5fxLqn6wKlMSzz/OxQ2M 5bAs1DIey1K0N1yeLz4AzQKadG/DBrytHNudvj X-Talos-CUID: 9a23:grFMLWNq1MLx9+5DBjd97gk3N+ccKkbm3XrhAEOHBVlCR+jA X-Talos-MUID: 9a23:xTfl2wWGA+CY1DDq/CfG1ApTathF2KCrJFAJtcgEme+EDjMlbg== X-IronPort-Anti-Spam-Filtered: true X-IronPort-AV: E=Sophos;i="6.27,130,1787004000"; d="asc'?scan'208,217";a="158284030" X-IronPort-Outbreak-Status: No, level 0, Unknown - Unknown X-MGA-submission: =?us-ascii?q?MDGwYoXzdbSJRkT3pFL1damNdIVulcg+/r+zYp?= =?us-ascii?q?zr3SsWu+1QRG2Nd0X+JDVni20el7VC/iKwuritQcJAqiejtlWDCw7/3G?= =?us-ascii?q?gWkOpeae/4s5MAGOjt8wuD6QskLvfcsbP5jxZ3QK6pwKkmVEJDSGV48t?= =?us-ascii?q?CqIEHrSQCngGzlI4M3R2yVCA=3D=3D?= Received: from mx1.polytechnique.org ([129.104.30.34]) by mail3-smtp-sop.national.inria.fr with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Sep 2026 09:10:40 +0200 Received: from mac-03220211.irisa.fr (mac-03220211.irisa.fr [131.254.21.249]) (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 EBC9B1A452; Tue, 29 Sep 2026 09:10:39 +0200 (CEST) From: Alan Schmitt To: "lwn" , caml-list@inria.fr Date: Tue, 29 Sep 2026 09:10:38 +0200 Message-ID: MIME-Version: 1.0 Content-Type: multipart/signed; boundary="===-=-="; micalg=pgp-sha256; protocol="application/pgp-signature" X-AV-Checked: ClamAV using ClamSMTP at svoboda.polytechnique.org (Tue Sep 29 09:10:40 2026 +0200 (CEST)) X-Spam-Flag: Unsure, tests=bogofilter, spamicity=0.499767, queueID=248381A456 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: 19590 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: multipart/mixed; boundary="=-=-=" --=-=-= Content-Type: multipart/alternative; boundary="==-=-=" --==-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hello Here is the latest OCaml Weekly News, for the week of September 22 to 29, 2026. 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 2nd release elm_playground (a game engine for beginners) moonpool 0.12 tw 1.1.0, Tailwind CSS in OCaml Cascade: A Typed CSS Toolkit in OCaml ppx_deriving_{yaml,ezjsonm,yamlx} 0.5.0 kqueue-ml 0.5.0 Windtrap: one library for all your OCaml tests Ocsigen Server 8.0.0 Old CWN 2nd release elm_playground (a game engine for beginners) =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=E2=95=90= =E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90=E2=95=90 Archive: Yoann Padioleau 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 It is my pleasure, again, to announce the second release of `elm_playground', an OCaml package that allows you to easily create /pictures/, /animations/, and even /video games/ in a portable way using an API that really simplifies how to view the computer and its devices (the screen, keyboard, and mouse). The library offers a native backend to run the games from a terminal and a web backend to run the games in your browser. This is a port of the excellent Elm playground package to OCaml. You can install it via OPAM via `opam install elm_playground; opam install elm_playground_native'. The main changes are most of the bugs in the first release have been fixed (mostly by Claude Code), and that now the native and web backend are fully working on all the examples and games. Here is for instance how to play Tetris compiled by jsoo: Here are a few examples of code using the library. First a =E2=80=9Cpicture=E2=80=9D app: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 (* from https://elm-lang.org/examples/picture *) =E2=94=82 open Playground =E2=94=82=20 =E2=94=82 let app =3D =E2=94=82 picture [ =E2=94=82 rectangle brown 40. 200. =E2=94=82 |> move_down 80.; =E2=94=82 circle green 100. =E2=94=82 |> move_up 100.; =E2=94=82 ] =E2=94=82=20 =E2=94=82 let main =3D Playground_platform.run_app app =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Then an =E2=80=9Canimation=E2=80=9D app: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 (* from https://elm-lang.org/examples/animation *) =E2=94=82 open Playground =E2=94=82=20 =E2=94=82 let view time =3D [ =E2=94=82 octagon darkGray 36. =E2=94=82 |> move_left 100. =E2=94=82 |> rotate (spin 3. time); =E2=94=82 octagon darkGray 36. =E2=94=82 |> move_right 100. =E2=94=82 |> rotate (spin 3. time); =E2=94=82 rectangle red 300. 80. =E2=94=82 |> move_up (wave 50. 54. 2. time) =E2=94=82 |> rotate (zigzag (-. 2.) 2. 8. time); =E2=94=82 ] =E2=94=82=20 =E2=94=82 let app =3D =E2=94=82 animation view =E2=94=82=20 =E2=94=82 let main =3D Playground_platform.run_app app =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 And finally a =E2=80=9Cgame=E2=80=9D app: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 (* from https://elm-lang.org/examples/mouse *) =E2=94=82 open Playground =E2=94=82=20 =E2=94=82 let view _computer (x, y) =3D [=20 =E2=94=82 square blue 40. =E2=94=82 |> move x y =E2=94=82 ] =E2=94=82=20 =E2=94=82 let update computer (x, y) =3D =E2=94=82 (x +. to_x computer.keyboard, y +. to_y computer.keyboard) =E2=94=82=20 =E2=94=82 let app =3D=20 =E2=94=82 game view update (0., 0.) =E2=94=82=20 =E2=94=82 let main =3D Playground_platform.run_app app =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Note that you can write more complex games. For example here is a screenshot of a toy tetris app: For more information, follow the README at See also the code of some classic examples and try them online thx to jsoo: moonpool 0.12 =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: Simon Cruanes 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 Howdy, I just released moonpool 0.12, now coming to an opam repository near you. Moonpool (first announced [here]) is a threadpool library for OCaml 5, leveraging domains to actually go brrrrrrr on multiple cores. The (still unique=E2=80=BD) design of moonpool allows the user to create mult= iple pools, whose cumulative size exceeds `Domain.recommended_domain_count()' without slowdown. It does that by using=E2=80=A6 threads=E2=80=A6 instead of domains. Yep. Anyway there's a whole bunch of bugfixes (including one to correct pathological memory usage in #45, big up @gasche as usual :heart_hands:), support for `ambient-context', some cleanup, dscheck for tests, etc. Cheerios on you and your cereal bowls [here] tw 1.1.0, Tailwind CSS in OCaml =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: Thomas Gazagnaire 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 I am happy to announce the release of [tw] 1.1.0 (available on brew already and soon in [opam]). =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 $ brew install samoht/tap/tw =E2=94=82 $ opam install tw.1.1.0 =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 `tw' is an implementation of [Tailwind CSS v4] in pure OCaml. This is the first version I would advise people to use: the previous ones only partially supported some features, and it was unclear where things were breaking. The 1.1.0 release now covers /all/ the Tailwind v4 utilities, variants and official plugins, and more importantly it comes with a proper, mechanical way to check that its output has no visual difference from Tailwind's. `tw' now comes with a CLI that is a drop-in replacement for the Tailwind CLI. It builds whole Tailwind projects from their CSS entrypoint (`tw -i src/app.css -o dist/app.css'), including `@theme', `@source', `@apply', custom utilities and variants, and the typography and forms plugins, *without Node.js*. It works for any project configured in CSS, whatever language generates the HTML. If you are using OCaml you can directly use an OCaml API with [Tw_html] that lets you build HTML components carrying their own styles. It exposes [htmlit]'s API but attaches `tw' classes to every node so you can query what CSS a given HTML fragment needs to be displayed. You can read more about the process to get to this release in my [blog post]. Feedback greatly appreciated in the [issue tracker] or in DMs! [tw] [opam] [Tailwind CSS v4] [Tw_html] [htmlit] [blog post] [issue tracker] Cascade: A Typed CSS Toolkit in OCaml =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: Continuing this thread, Thomas Gazagnaire 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=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80=E2=94=80= =E2=94=80 I am happy to announce the release of `cascade' 1.2.1 in `opam' and Homebrew. It mostly contains (many) bug fixes, a lot of them found by rendering stylesheets in headless Chrome and comparing the pixels. If you shipped minified CSS built with 1.1.0, please regenerate it and check the difference: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 $ cascade diff --diff=3Dcanonical old.css new.css =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 If you want to check pixel-level differences of the rendering on a given page, you can now use: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 $ cascade diff --browser --html page.html a.css b.css =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 This new command helped to identify and fix numerous issues; hence the (way too long) list of fixes in [CHANGES.md]. [CHANGES.md] ppx_deriving_{yaml,ezjsonm,yamlx} 0.5.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=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: Patrick Ferris 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 Hello! I'm happy to announce the release of `ppx_deriving_yaml' and `ppx_deriving_ezjsonm' version `0.5.0' alongside the first release of `ppx_deriving_yamlx' which uses [YAMLx] as a backend (thank you to @raphael-proust and @mjambon for their work and input). All three derivers use the same core codec with each specialising to their particular representation. This release also contains a bug fix for deriving `_ array' types which was completely broken (so broken, your code wouldn't compile). [YAMLx] Installing =E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2= =95=8C=E2=95=8C =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 opam update =E2=94=82 opam install ppx_deriving_yaml =E2=94=82 opam install ppx_deriving_ezjsonm =E2=94=82 opam install ppx_deriving_yamlx =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 Documentation =E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2= =95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C Please find the documentation on ocaml.org, for example [docs for ppx_deriving_yamlx]. Happy deriving :two_hump_camel: [docs for ppx_deriving_yamlx] kqueue-ml 0.5.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 Archive: Continuing this thread, Anurag Soni 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=E2=94=80 I've published a couple of new releases since 0.5. =E2=80=A2 Added support for `EVFILT_USER' and `EVFILT_SIGNAL' =E2=80=A2 Change the interface for registering events to avoid needing to allocate a record The new update can be found on [opam] [opam] Windtrap: one library for all your OCaml tests =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: Thibaut Mattio 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 Hi everyone! I'm happy to announce the release of [Windtrap], a testing framework for OCaml that brings the different testing methods of the ecosystem into one library: =E2=80=A2 Unit tests, with an Alcotest-like API. =E2=80=A2 Expect and snapshot tests, with a companion PPX compatible with `ppx_expect' and `ppx_inline_test', but usable without it. =E2=80=A2 Property tests as seen in [QCheck], with a library of textbook = laws (round trips, orders, associativity, and more). =E2=80=A2 Stateful and differential tests, as seen in [qcheck-stm] and [Monolith], on one domain or several. =E2=80=A2 Test coverage (as with [Bisect_ppx]) and mutation testing (as w= ith [mutaml]). Every kind of test composes with the others into one suite and one output, and the library has *no dependencies* beyond OCaml (the optional PPX uses ppxlib). Here's a small suite that tests the standard library with a unit test, a property stated as a textbook law, and a stateful test of `Stack' against a list: =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 open Windtrap =E2=94=82=20 =E2=94=82 (* A reference for Stack: a list, its top first. *) =E2=94=82 module Model =3D struct =E2=94=82 type t =3D int list ref =E2=94=82=20 =E2=94=82 let create () =3D ref [] =E2=94=82 let push x m =3D m :=3D x :: !m =E2=94=82 let length m =3D List.length !m =E2=94=82=20 =E2=94=82 let pop m =3D =E2=94=82 match !m with =E2=94=82 | [] -> raise Stack.Empty =E2=94=82 | x :: rest -> =E2=94=82 m :=3D rest; =E2=94=82 x =E2=94=82 end =E2=94=82=20 =E2=94=82 let stack =3D abstract "s" ~pp:(fun ppf m -> Testable.pp (list = int) ppf !m) =E2=94=82=20 =E2=94=82 let lists =3D =E2=94=82 group "list" =E2=94=82 [ =E2=94=82 test "rev reverses a list" (fun () -> =E2=94=82 equal (list int) [ 3; 2; 1 ] (List.rev [ 1; 2; 3 ])); =E2=94=82 prop "rev is an involution" (Gen.list Gen.int) =E2=94=82 (Law.involutive (list int) List.rev); =E2=94=82 ] =E2=94=82=20 =E2=94=82 let stacks =3D =E2=94=82 group "stack" =E2=94=82 [ =E2=94=82 stateful "behaves like a list" =E2=94=82 [ =E2=94=82 command "create" (Gen.unit @-> makes stack) Model.cre= ate Stack.create; =E2=94=82 command "push" =E2=94=82 (Gen.int @-> stack ^-> returns unit) =E2=94=82 Model.push Stack.push; =E2=94=82 command "pop" (stack ^-> returns int) Model.pop Stack= .pop; =E2=94=82 command "length" (stack ^-> returns int) Model.length= Stack.length; =E2=94=82 ]; =E2=94=82 ] =E2=94=82=20 =E2=94=82 let () =3D exit (run "stdlib" [ lists; stacks ]) =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 We built Windtrap at [Invariant] as part of our work on making code written by agents more trustworthy. Agents replicate what they find in a repository, so a project full of strong tests gets more of them. Windtrap comes with an [agent skill] that guides agents towards the right kind of test, but we care just as much about humans, and put a lot of effort into making the API and output ergonomic and delightful. You can read more about it in the [announcement post]. It walks through an example suite, what a failure looks like, coverage and mutation testing, and an experiment where we used Windtrap to test the OCaml standard library. To install it (when [the PR] is merged on opam-repository): =E2=94=8C=E2=94=80=E2=94=80=E2=94=80=E2=94=80 =E2=94=82 opam install windtrap ppx_windtrap=20 =E2=94=94=E2=94=80=E2=94=80=E2=94=80=E2=94=80 The [manual] (written by agents with my guidance, I hope you'll find the writing voice bearable, but if enough people complain I'll look into rewriting it by hand) has one page per kind of test. Feedback is very welcome, here or on the [issue tracker]. Happy hacking! =E2=80=94 [Windtrap] [QCheck] [qcheck-stm] [Monolith] [Bisect_ppx] [mutaml] [Invariant] [agent skill] [announcement post] [the PR] [manual] [issue tracker] Acknowledgments =E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2= =95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C=E2=95=8C Windtrap builds on ideas and code from several OCaml projects: =E2=80=A2 *[Alcotest]* by Thomas Gazagnaire: test structure and runner de= sign. =E2=80=A2 *Craig Ferguson's Alcotest PRs* ([#294], [#247]): API design, subcomponent diffing. =E2=80=A2 *[QCheck2]* by Simon Cruanes et al.: generator design and integ= rated shrinking. =E2=80=A2 *[Monolith]* by Fran=C3=A7ois Pottier, and *[qcheck-stm]* by Jan Midtgaard et al.: stateful testing against a reference, on one domain or several. =E2=80=A2 *[ppx_expect]* and *[ppx_inline_test]* by Jane Street: expect t= est paradigm and dune integration, and ppx_expect's test corpus. =E2=80=A2 *[Bisect_ppx]* by Anton Bachin et al.: coverage instrumentation= and runtime. =E2=80=A2 *[mutaml]* by Jan Midtgaard: mutation testing for OCaml as a PP= X. =E2=80=A2 *[mtime]* by Daniel B=C3=BCnzli: the monotonic clock. [Alcotest] [#294] [#247] [QCheck2] [Monolith] [qcheck-stm] [ppx_expect] [ppx_inline_test] [Bisect_ppx] [mutaml] [mtime] Ocsigen Server 8.0.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=E2=95=90=E2=95=90 Archive: Vincent Balat 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 Hi everyone! Ocsigen Server 8.0.0 is out, the web server written in OCaml, usable as an executable or as a library. Some highlights: =E2=80=A2 *One command, no config file*: `ocsigenserver ./public' serves a directory, and `ocsigenserver --reverse-proxy http://localhost:9000' puts a proxy in front of your app, with compression and security headers already on. =E2=80=A2 *Static files* now answer conditional requests (ETag, 304) and = byte ranges, so seeking in a video or resuming a download just works. =E2=80=A2 *zstd compression*, on a new bytesrw backend. =E2=80=A2 A new *Securityheaders* extension. =E2=80=A2 Access logs in the standard *Combined Log Format*, readable by = the usual tools. =E2=80=A2 The public modules were renamed (`Ocsigen.Server', `Ocsigen.Con= fig', =E2=80=A6). The new `ocsigenserver-compat' package keeps the old names,= so existing code still builds. `opam install ocsigenserver' A release of Eliom and other projects compatible with this version will follow in a few weeks. All the details are in the blog post: 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 to the [caml-list]. [Alan Schmitt] [send me a message] [the archive] [RSS feed of the archives] [caml-list] [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<= /a> Up Next Week

Hello

Here is the latest OCaml Weekly News, for the week of September 22 to 29, 2= 026.

2nd release elm_playground (a game engine for beginners)

Yoann Padioleau announced

It is my pleasure, again, to announce the second release of elm_playg= round, an OCaml package that allows you to easily create pictures= , animations, and even video games in a portable way usin= g an API that really simplifies how to view the computer and its devices (t= he screen, keyboard, and mouse). The library offers a native backend to run= the games from a terminal and a web backend to run the games in your brows= er.

This is a port of the excellent Elm playground package https://github.com/eva= ncz/elm-playground to OCaml.

You can install it via OPAM via=20

opam install elm_playground; opam install elm_playground_native.

The main changes are most of the bugs in the first release have been fixed = (mostly by Claude Code), and that now the native and web backend are fully = working on all the examples and games. Here is for instance how to play Tet= ris compiled by jsoo:

h= ttps://aryx.github.io/ocaml-elm-playground/games/Tetris.html

Here are a few examples of code using the library.

First a =E2=80=9Cpicture=E2=80=9D app:

(* f=
rom https://elm-lang.org/examples/picture *)
open Playground

let app =3D
  picture [
    rectangle brown 40. 200.
      |> move_down 80.;
    circle green 100.
      |> move_up 100.;
  ]

let main =3D Playground_platform.run_app app

3D"76fc1=

Then an =E2=80=9Canimation=E2=80=9D app:

(* f=
rom https://elm-lang.org/examples/animation *)
open Playground

let view time =3D [
    octagon darkGray 36.
      |> move_left 100.
      |> rotate (spin 3. time);
    octagon darkGray 36.
      |> move_right 100.
      |> rotate (spin 3. time);
    rectangle red 300. 80.
      |> move_up (wave 50. 54. 2.=
 time)
      |> rotate (zigzag (-. 2.) 2=
. 8. time);
  ]

let app =3D
  animation view

let main =3D Playground_platform.run_app app

3D"e9156=

And finally a =E2=80=9Cgame=E2=80=9D app:

(* f=
rom https://elm-lang.org/examples/mouse *)
open Playground

let view _computer<=
/span> (x, y) =3D [=20
  square blue 40.
   |> move x y
 ]

let update computer=
 (x, y) =3D
  (x +. to_x computer.keyboard, y +. to_y computer.keyboard)

let app =3D=20
  game view update (0., 0.)

let main =3D Playground_platform.run_app app

3D"24e8f=

Note that you can write more complex games. For example here is a screensho= t of a toy tetris app:

3D"4ded1d55c9994935=

For more information, follow the README at https://github.com/aryx/ocaml-elm-playground

See also the code of some classic examples and try them online thx to jsoo:= https://ary= x.github.io/ocaml-elm-playground/games/

moonpool 0.12

Simon Cruanes announced

Howdy, I just released moonpool 0.12, now coming to an opam repository near= you.

Moonpool (first announced here) is a threadpool library for OCaml 5, leveraging dom= ains to actually go brrrrrrr on multiple cores. The (still unique=E2=80=BD)= design of moonpool allows the user to create multiple pools, whose cumulat= ive size exceeds Domain.recommended_domain_count() without slo= wdown. It does that by using=E2=80=A6 threads=E2=80=A6 instead of domains. = Yep.

Anyway there's a whole bunch of bugfixes (including one to correct patholog= ical memory usage in #45, big up @gasche as usual :heart_hands:), support f= or ambient-context, some cleanup, dscheck for tests, etc.

Cheerios on you and your cereal bowls

tw 1.1.0, Tailwind CSS in OCaml

Thomas Gazagnaire announced

I am happy to announce the release of tw 1.1.0 (available on brew already and soon in opam).

$ brew install samoht/tap/tw
$ opam install tw.1.1.0

tw is an implementation of Tailwind CSS v4 in pure OCaml. This is the first version I would advi= se people to use: the previous ones only partially supported some features,= and it was unclear where things were breaking. The 1.1.0 release now cover= s all the Tailwind v4 utilities, variants and official plugins, and = more importantly it comes with a proper, mechanical way to check that its o= utput has no visual difference from Tailwind's.

tw now comes with a CLI that is a drop-in replacement for the = Tailwind CLI. It builds whole Tailwind projects from their CSS entrypoint (= tw -i src/app.css -o dist/app.css), including @theme, @source, @apply, custom utilities and varian= ts, and the typography and forms plugins, without Node.js. It works = for any project configured in CSS, whatever language generates the HTML.

If you are using OCaml you can directly use an OCaml API with Tw_html that= lets you build HTML components carrying their own styles. It exposes htmlit's API but attaches tw classes to every node so you can query what CSS a given HTML f= ragment needs to be displayed.

You can read more about the process to get to this release in my blog post= . Feedback greatly appreciated in the issue tracker or in DMs!

Cascade: A Typed CSS Toolkit in OCaml

Continuing this thread, Thomas Gazagnaire announced

I am happy to announce the release of cascade 1.2.1 in o= pam and Homebrew. It mostly contains (many) bug fixes, a lot of them= found by rendering stylesheets in headless Chrome and comparing the pixels.

If you shipped minified CSS built with 1.1.0, please regenerate it and chec= k the difference:

$ cascade diff --diff=3Dcanonical old.css new.css

If you want to check pixel-level differences of the rendering on a given pa= ge, you can now use:

$ cascade diff --browser --html page.html a.css b.css

This new command helped to identify and fix numerous issues; hence the (way= too long) list of fixes in CHANGES.md.

ppx_deriving_{yaml,ezjsonm,yamlx} 0.5.0

Patrick Ferris announced

Hello!

I'm happy to announce the release of ppx_deriving_yaml and ppx_deriving_ezjsonm version 0.5.0 alongside the fir= st release of ppx_deriving_yamlx which uses YAMLx as a backend (thank you to @raphael-pr= oust and @mjambon for their work and input). All three derivers use the sam= e core codec with each specialising to their particular representation.

This release also contains a bug fix for deriving _ array type= s which was completely broken (so broken, your code wouldn't compile).

Installing

opam update
opam install ppx_deriving_yaml
opam install ppx_deriving_ezjsonm
opam install ppx_deriving_yamlx

Documentation

Please find the documentation on ocaml.org, for example docs for ppx_deriving= _yamlx.

Happy deriving :two_hump_camel:

kqueue-ml 0.5.0

Continuing this thread, Anurag Soni announced

I've published a couple of new releases since 0.5.

  • Added support for EVFILT_USER and EVFILT_SIGNAL
  • Change the interface for registering events to avoid needing to allocat= e a record

The new update can be found on opam

Windtrap: one library for all your OCaml tests

Thibaut Mattio announced

Hi everyone!

I'm happy to announce the release of Windtrap, a testing framework for OCaml that brings the = different testing methods of the ecosystem into one library:

  • Unit tests, with an Alcotest-like API.
  • Expect and snapshot tests, with a companion PPX compatible with p= px_expect and ppx_inline_test, but usable without it.
  • Property tests as seen in = QCheck, with a library of textbook laws (round trips, orders, associati= vity, and more).
  • Stateful and differential tests, as seen in qcheck-stm and Monolith, on one domain or several.
  • Test coverage (as with Bisect_ppx) and mutation testing (as with mutaml).

Every kind of test composes with the others into one suite and one output, = and the library has no dependencies beyond OCaml (the optional PPX u= ses ppxlib).

Here's a small suite that tests the standard library with a unit test, a pr= operty stated as a textbook law, and a stateful test of Stack = against a list:

open W=
indtrap

(* A reference for Stack: a list, its=
 top first. *)
module Model =3D struct
  type t =3D int list ref

  let create () =3D ref []
  let push x <=
span style=3D"color: #007a9f;">m =3D m :=3D x :: !m
  let length m=
 =3D List.length =
!m

  let pop m =3D
    match !m with
    | [] -> raise Stack.Empty
    | x :: rest ->
        m :=3D rest;
        x
end

let stack =3D abstract "s" ~pp:(fun ppf m -=
> Testable.pp =
(list int) ppf !m)

let lists =3D
  group "list"
    [
      test "rev reverses a list" (fun () ->
          equal (list int) [ 3; 2; 1 ] (List.rev [ 1; 2; 3 ]));
      prop "rev is an involution" (<=
span style=3D"color: #557400; font-weight: bold;">Gen.list Gen.int)
        (Law.invo=
lutive (list int) List.<=
/span>rev);
    ]

let stacks =3D
  group "stack"
    [
      stateful "behaves like a list"
        [
          command "create" (Gen.unit @-> makes stack) Model.create Stack.create;
          command "push"
            (Gen.=
int @-> stack ^-> returns unit)
            Model.push Stack.push;
          command "pop" (stack ^-> returns int) Model.pop Stack.pop;
          command "length" (stack ^-> returns int) Model.length Stack.length;
        ];
    ]

let () =3D exit (run "stdlib" [ lists; stacks ])

We built Windtrap at Invariant as = part of our work on making code written by agents more trustworthy. Agents = replicate what they find in a repository, so a project full of strong tests= gets more of them. Windtrap comes with an agent skill that guides agents = towards the right kind of test, but we care just as much about humans, and = put a lot of effort into making the API and output ergonomic and delightful.

You can read more about it in the announcement post. It walks through an example sui= te, what a failure looks like, coverage and mutation testing, and an experi= ment where we used Windtrap to test the OCaml standard library.

To install it (when the PR is merged on opam-repository):

opam install windtrap ppx_windtrap=20

The manual (written by agents with my guidance, I hope you'll find the w= riting voice bearable, but if enough people complain I'll look into rewriti= ng it by hand) has one page per kind of test. Feedback is very welcome, her= e or on the iss= ue tracker.

Happy hacking!

—

Acknowledgments

Windtrap builds on ideas and code from several OCaml projects:

  • Alcotest by T= homas Gazagnaire: test structure and runner design.
  • Craig Ferguson's Alcotest PRs (#294, #247): API design, subcomponent diffing.
  • QCheck2 by Simo= n Cruanes et al.: generator design and integrated shrinking.
  • Monolith by Fran=C3=A7ois Pottier, and qcheck-stm by Jan Midtgaard et al.: stateful= testing against a reference, on one domain or several.
  • ppx_expect<= /b> and ppx_in= line_test by Jane Street: expect test paradigm and dune integration= , and ppx_expect's test corpus.
  • Bisect_ppx= by Anton Bachin et al.: coverage instrumentation and runtime.
  • mutaml by Jan Mid= tgaard: mutation testing for OCaml as a PPX.
  • mtime by Dan= iel B=C3=BCnzli: the monotonic clock.

Ocsigen Server 8.0.0

Vincent Balat announced

Hi everyone!

Ocsigen Server 8.0.0 is out, the web server written in OCaml, usable as an = executable or as a library. Some highlights:

  • One command, no config file: ocsigenserver ./public= serves a directory, and ocsigenserver --reverse-proxy http://localho= st:9000 puts a proxy in front of your app, with compression and secu= rity headers already on.
  • Static files now answer conditional requests (ETag, 304) and byt= e ranges, so seeking in a video or resuming a download just works.
  • zstd compression, on a new bytesrw backend.
  • A new Securityheaders extension.
  • Access logs in the standard Combined Log Format, readable by the= usual tools.
  • The public modules were renamed (Ocsigen.Server, Ocs= igen.Config, …). The new ocsigenserver-compat pa= ckage keeps the old names, so existing code still builds.

opam install ocsigenserver

A release of Eliom and other projects compatible with this version will fol= low in a few weeks.

All the details are in the blog post: https://ocsigen.org/blog/posts/ocsigenserver= -8.0.0.html

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 <= a href=3D"https://alan.petitepomme.net/cwn/cwn.rss">RSS feed of the archive= s.

If you also wish to receive it every week by mail, you may subscribe to the= caml-list.

--==-=-=-- --=-=-=-- --===-=-= Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQFvBAEBCABZFiEE6lXof/BsSVW56ZmGBA0KO07S5ccFAmq7ZG8bFIAAAAAABAAO bWFudTIsMi41KzEuMTIsMCwzHxxhbGFuLnNjaG1pdHRAcG9seXRlY2huaXF1ZS5v cmcACgkQBA0KO07S5cfdIggAhsJPVsLG1wlRfQemEYRgjbY/b1GnOUc4nD9ffJ8e Y6hiU3272RGWfmd7VzzC5WCBK8nks/CjoJ78ADvlnvDA4hRWIvHb91Z7kGMrMtzd ZJZH5XXtyb8wg4UvNROnYrtqKuZI0wbHNkWrG6DNStx0R4Xig0DdFf6JaHt0euPd ndEU+Ji4lOOCy9u9Pk/NMFIw+0HyBVH9PnfA1jHRYCSz8vogXT2CKSvozCSAWAcI tHQNe16ZM6GIqTo8SO/7YFu+oLaBK7GPBnayiKi06dw+02plih/3gFnKSQMu7+Zu a/JOBeuJ2PfRhwARrvHWrzClYixm49BiFWBsHYxj1pX2SQ== =qeTz -----END PGP SIGNATURE----- --===-=-=--