From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Hongyi Zhao Newsgroups: gmane.emacs.help Subject: Re: Closures in Emacs and their usage scenarios. Date: Tue, 28 Sep 2021 22:50:08 +0800 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="14870"; mail-complaints-to="usenet@ciao.gmane.io" Cc: Stefan Monnier via Users list for the GNU Emacs text editor , Stefan Monnier To: Arthur Miller Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane-mx.org@gnu.org Tue Sep 28 16:51:21 2021 Return-path: Envelope-to: geh-help-gnu-emacs@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 1mVES0-0003dm-Jl for geh-help-gnu-emacs@m.gmane-mx.org; Tue, 28 Sep 2021 16:51:20 +0200 Original-Received: from localhost ([::1]:45876 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mVERz-0007Lq-1h for geh-help-gnu-emacs@m.gmane-mx.org; Tue, 28 Sep 2021 10:51:19 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:37810) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mVER8-0007KH-Gm for help-gnu-emacs@gnu.org; Tue, 28 Sep 2021 10:50:26 -0400 Original-Received: from mail-vs1-xe2f.google.com ([2607:f8b0:4864:20::e2f]:34785) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mVER4-0001ZC-DF for help-gnu-emacs@gnu.org; Tue, 28 Sep 2021 10:50:24 -0400 Original-Received: by mail-vs1-xe2f.google.com with SMTP id u8so22388479vsp.1 for ; Tue, 28 Sep 2021 07:50:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=bgRegrR9x5oVeHQER5Y5Zoh0Ph1DVXKpcBwleizNPEw=; b=Me7pmdP9z7FgjBuT40O79Le6SGsV9qimAI/wLZ7auUdLamZDa08iKElHuKvBR1Z91c YF2peiMLD7OwZeHwbVfHOskNK+M5zgqz+7tkXDN136xa6wd68DWszvKWk59KYJ7ORP1R SgumVTKUEI/W1hPPwkZ6lLgxaVu6KVSC23aA7iUHkQybyVp5RlkbtKsMpofdOoU8tT+A TZXjjqZUGiufIvggmDtbhlbOaBn8keAcwmtRVOklkpBAbl3zlgskFSt/GqkiWSRuQQoo 1wHLq5RPOlBppkxV9cbhYwQ2pVLO3lahh+IDsoBsyLfNy3EArZnuOGl6HnQR+yST2WCc NktQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=bgRegrR9x5oVeHQER5Y5Zoh0Ph1DVXKpcBwleizNPEw=; b=7IJ0ySlM+Up4Y6iILtk1YmfCcDgmqwmau8slOOB8w4aR62zYeqNHZzZzl54wtF5F5q d/M2kItDQSunv3G5i1XXuZJ7Vfkg56gyfi3HIeNzQc+HhDpnbawhwyokRxCgcYfDC3WW E3PnhU/68Lb4mNq5OING66sppNDm4jJ0PZU9uhpAzeppf/rLqzytDj6a8aVjegvklXZN VIiR3ezSodbPVsbpHhnYrSeZI3lSAEUyueLPOLVKxMx89Xo6N3X4janPZhcc246/+pak QWY6rAKj7hfvx0zR83axio1/0hqIzBnQBslr9YlUhhIK6H2tKP2N2bW5IOv47Sn2XhQB HxGQ== X-Gm-Message-State: AOAM533KH+3dBOhCDUai8DRr/44076nc8X1FWDbkx5m7mKoqWdi14u3I MoGXkPG/FVVhcezTgvnXyC04X3yr4f12uahK+8o= X-Google-Smtp-Source: ABdhPJyuhC3VeXXs7bSZWWVOX/KhlhSoHIkiJErXY5rH/Chi+/I6GBIkHP/QvD7CNF8nMqXaOkwGZeODuFB8j88mj7U= X-Received: by 2002:a67:3157:: with SMTP id x84mr5395721vsx.51.1632840619849; Tue, 28 Sep 2021 07:50:19 -0700 (PDT) In-Reply-To: Received-SPF: pass client-ip=2607:f8b0:4864:20::e2f; envelope-from=hongyi.zhao@gmail.com; helo=mail-vs1-xe2f.google.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "help-gnu-emacs" Xref: news.gmane.io gmane.emacs.help:133356 Archived-At: On Tue, Sep 28, 2021 at 7:53 PM Arthur Miller wrote: > > Stefan Monnier via Users list for the GNU Emacs text editor > writes: > > >> I noticed the document on closure here [1] implemented in Emacs/Elisp currently. > >> But it's only a very concise and short introduction, and I want to > >> know more about the closures in Emacs and their usage scenarios. > >> Any helpful tips are welcome. > > > > Maybe a good starting point is > > > > https://en.wikipedia.org/wiki/Closure_(computer_programming) > > Chapter 2 from "On Lisp" by P. Graham has also very nice and accessible intro to > functions and closures: > > https://sep.yimg.com/ty/cdn/paulgraham/onlisp.pdf?t=1595850613& > > So has also "Let Over Lambda" by D. Hoyte: > > https://letoverlambda.com/index.cl/guest/chap2.html > > Chapter 2 is an entire chapter on closures and using them; if one is not scared > by subtitles like: "Let Over Lambda Over Let Over Lambda" :). I have excerpted all relevant discussions as follows from there [1]: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Let Over Lambda Over Let Over Lambda Users of object systems store values they want shared between all objects of a certain class into so-called class variables or static variables8. In lisp, this concept of sharing state between closures is handled by environments in the same way that closures themselves store state. Since an environment is accessible indefinitely, as long as it is still possible to reference it, we are guaranteed that it will be available as long as is needed. If we want to maintain a global direction for all counters, up to increment each closure's counter and down to decrement, then we might want to use a let over lambda over let over lambda pattern: (let ((direction 'up)) (defun toggle-counter-direction () (setq direction (if (eq direction 'up) 'down 'up))) (defun counter-class () (let ((counter 0)) (lambda () (if (eq direction 'up) (incf counter) (decf counter)))))) In the above example, we have extended counter-class from the previous section. Now calling closures created with counter-class will either increment its counter binding or decrement it, depending on the value of the direction binding which is shared between all counters. Notice that we also take advantage of another lambda inside the direction environment by creating a function called toggle-counter-direction which changes the current direction for all counters. While this combination of let and lambda is so useful that other languages have adopted it in the form of class or static variables, there exist other combinations of let and lambda that allow you to structure code and state in ways that don't have direct analogs in object systems9. Object systems are a formalisation of a subset of let and lambda combinations, sometimes with gimmicks like inheritance bolted on10. Because of this, lisp programmers often don't think in terms of classes and objects. Let and lambda are fundamental; objects and classes are derivatives. As Steele says, the "object" need not be a primitive notion in programming languages. Once assignable value cells and good old lambda expressions are available, object systems are, at best, occasionally useful abstractions and, at worst, special-case and redundant. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; But TBF, these contents are still not so easy for me to understand. [1] https://letoverlambda.com/textmode.cl/guest/chap2.html HZ