From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.ciao.gmane.io!not-for-mail From: Chris Vine Newsgroups: gmane.lisp.guile.user Subject: Re: emulate "sum type" pattern matching? Date: Thu, 12 Mar 2020 17:16:18 +0000 Message-ID: <20200312171618.b9536622b8db7927647d3bfa@gmail.com> References: <87sgier7eb.fsf@gmail.com> <20200312144622.0c660172af70ced0493ce9b1@gmail.com> <87wo7pmxjk.fsf@elephly.net> Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Injection-Info: ciao.gmane.io; posting-host="ciao.gmane.io:159.69.161.202"; logging-data="11048"; mail-complaints-to="usenet@ciao.gmane.io" To: guile-user@gnu.org Original-X-From: guile-user-bounces+guile-user=m.gmane-mx.org@gnu.org Thu Mar 12 18:21:37 2020 Return-path: Envelope-to: guile-user@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1jCRWa-0002hp-Oj for guile-user@m.gmane-mx.org; Thu, 12 Mar 2020 18:21:36 +0100 Original-Received: from localhost ([::1]:46528 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jCRWZ-0003lo-Py for guile-user@m.gmane-mx.org; Thu, 12 Mar 2020 13:21:35 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:41458) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1jCRR2-0003FX-NI for guile-user@gnu.org; Thu, 12 Mar 2020 13:15:54 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1jCRR0-0003c6-HI for guile-user@gnu.org; Thu, 12 Mar 2020 13:15:52 -0400 Original-Received: from mail-wr1-x433.google.com ([2a00:1450:4864:20::433]:42698) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1jCRR0-0003bI-AF for guile-user@gnu.org; Thu, 12 Mar 2020 13:15:50 -0400 Original-Received: by mail-wr1-x433.google.com with SMTP id v11so8496725wrm.9 for ; Thu, 12 Mar 2020 10:15:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=date:from:to:cc:subject:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=1gCRA5G/gHIePovXJHPpawi91O9dGDO2K82WIfGezpU=; b=CcyxPMQRmsKNcOdzzfcAfeFg97C8ypk5zvXJbwcZlDVbtQis+CLu91KxpnUk8mu+/N SYO0uIO2qJ1K5izR+AcEog6CawgZ0D4hxdOLa+g55Io4CIY9x8D/5+RVLypO8iTHNSi/ zQIPVCe+xnV5eEEEKj+k2WpCRe8a1KmsDDeTDNPjknqVUuC4mfeKiutvQY3OhRuGFNwl 5KdbR9Pzj4ujstJSvufpMwyjpdneQKn6ePLB5RwAJG6RmN38f8doy2ynXKt3nMz+REiH ESP9NZHhFpHYh5s7aNl0R4vGQZdamkG4pq9WgoqBeckUHAPFxYYHU55o1Y87lzFT+ECO HmYA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=1gCRA5G/gHIePovXJHPpawi91O9dGDO2K82WIfGezpU=; b=azFyIMRW8Gyzf5clBicHcoSgEc1msMSAEu5nYWifGnwJA/qdRG8ueYaGVvAfXyhvdx 1HeIdwEx0aaemmzqa57kY4kWHzOewkgQwkIOLTKeixEyO/MDyP/JkhcEmriLm+7OdoB/ /UjZQABXfihcQBT+Rn4FAhy420M0mdep+8uWXZZBoYqgTTV0LRYb6K50jueOX2EcTggJ V4fMd0/i+a6A2NMYJAC3VaQCFGP0voDpIc4lQVOTQcpyDtsOUyMOidkxHlq0bFRM3lWR HSX8n/PYsDSSBopsCTxPGhWIiTx+3A/oUTiOiwmtJ7RFzXr58p2jnoc9QNfbPvSK37Rh lLEg== X-Gm-Message-State: ANhLgQ02ZgPruY0fkZkVTtdPYhzii+2AeAsDkDgz6dbF3S18zps4Q2WC 11OEjHGspiY+BOoPypGhBog= X-Google-Smtp-Source: ADFU+vs0n5iUKQDwO7eTVKRCcQ6+XUNkbOtp8W5h2CpBfQA1P+JAtItoNZZzzSt6uzUM1deXvdbSEw== X-Received: by 2002:adf:b60f:: with SMTP id f15mr12624940wre.372.1584033349129; Thu, 12 Mar 2020 10:15:49 -0700 (PDT) Original-Received: from bother.homenet ([2.24.141.99]) by smtp.gmail.com with ESMTPSA id e7sm56196654wrt.70.2020.03.12.10.15.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 12 Mar 2020 10:15:48 -0700 (PDT) Original-Received: from bother.homenet (localhost [127.0.0.1]) by bother.homenet (Postfix) with SMTP id 983E226273B; Thu, 12 Mar 2020 17:16:18 +0000 (GMT) In-Reply-To: <87wo7pmxjk.fsf@elephly.net> X-Mailer: Sylpheed 3.7.0 (GTK+ 2.24.32; x86_64-unknown-linux-gnu) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::433 X-BeenThere: guile-user@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: General Guile related discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guile-user-bounces+guile-user=m.gmane-mx.org@gnu.org Original-Sender: "guile-user" Xref: news.gmane.io gmane.lisp.guile.user:16295 Archived-At: On Thu, 12 Mar 2020 15:56:47 +0100 Ricardo Wurmus wrote: > Chris Vine writes: > > On Wed, 11 Mar 2020 19:58:04 +0000 > > Sam Halliday wrote: > >> Hi all, > >> > >> I have read the Guile manual as my introduction to Guile. I am very > >> impressed at how mature this project is and was overwhelmed by the > >> feature set, which seems to be on-par with heavily invested technologies > >> like Java and the JVM. > >> > >> I am considering using Guile for a project because I love Emacs lisp and > >> know it very well. Emacs lisp has some limitations that I feel Guile > >> overcomes, e.g. multithreading, a superior regexp engine, a module > >> system, and parsers. > >> > >> However, there is one feature that is critical to the development of the > >> project and I was hoping to be able to implement it through a macro: sum > >> type pattern matching. > >> > >> By that, I mean in the sense of Haskell sum types, which I understand > >> are similar to C++ union types. Roughly translated into GOOP, and using > >> Scala's encoding of sum types, this would look like record types that > >> are all children of a superclass. I noticed that Guile has support for > >> discovering all direct subclasses at runtime, but is this facility > >> available at compiletime? > >> > >> An example of how I would want to use this feature can be described in > >> terms of the XML calculator in the Guile Manual. > >> https://www.gnu.org/software/guile/manual/html_node/sxml_002dmatch.html#Catamorphisms > >> which looks like > >> > >> (define simple-eval > >> (lambda (x) > >> (sxml-match x > >> [,i (guard (integer? i)) i] > >> [(plus ,x ,y) (+ (simple-eval x) (simple-eval y))] > >> [(times ,x ,y) (* (simple-eval x) (simple-eval y))] > >> [(minus ,x ,y) (- (simple-eval x) (simple-eval y))] > >> [(div ,x ,y) (/ (simple-eval x) (simple-eval y))] > >> [,otherwise (error "simple-eval: invalid expression" x)]))) > >> > >> If the sxml-match was aware that it was matching over a superclass of > >> plus, minus, times, div then the "otherwise" line would be redundant and > >> (most importantly) if I were to forget to match over one of the > >> subclasses I would get a compiler error. > >> > >> And that's basically my usecase in a nutshell: exhaustive pattern > >> matching over a tree-like structure (an AST, in fact). But I'll have > >> lots of different trees so I don't want to have to manually write a > >> pattern match macro every time I define a "sum type"... although that > >> said I do have some ideas on how to abstract that. But I don't really > >> want to go down a lisp macro rabbit hole at the very beginning... > > > > guile's built-in pattern matcher (ice-9 match) enables you to match on > > symbols, literals, pairs, lists, vectors and records, but I don't think > > it enables you to match on GOOPS objects - someone may contradict me on > > that, but at least I have never tried doing so (I don't like GOOPS nad > > I rarely use it). > > You can match on anything as long as there is a predicate for it. For a > GOOPS object that has a procedure “thing?” that returns #t when the > argument is of the expected type you can match with > > (? thing? thing) > > You cannot, as far as I know, use match to know at compile time that the > clauses are exhaustive. Ah OK. But if that is the use issue in hand, then you might as well use 'cond' (or 'if') rather than 'match'. Traditional pattern matching is mainly structural, because in a statically typed language the argument given to the matcher must normally be of the correct type to begin with. You can still do structural matching with the guile matcher. For example you can peel off a list with: (match lst (() ... ) ((head . tail) ...)) and extract values from a record or vector in a similar way. But scheme doesn't have variants (sum types) in the ordinary sense so you cannot extract values by matching on the case/constructor of a variant in the same way as with statically typed languages. As you say, you would have to use a predicate for something equivalent.