From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Taylan Kammer Newsgroups: gmane.lisp.guile.user Subject: Re: Pure (side-effect-free) calls into c/c++? Date: Sat, 11 Jan 2020 22:56:00 +0100 Message-ID: <7c06af2b-3ae7-d233-8ac9-5aabb9dff2de@gmail.com> References: Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="503"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Thunderbird/68.3.1 Cc: Guile User To: linasvepstas@gmail.com, Matt Wette Original-X-From: guile-user-bounces+guile-user=m.gmane-mx.org@gnu.org Sat Jan 11 22:56:33 2020 Return-path: Envelope-to: guile-user@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1iqOk3-0013ca-GF for guile-user@m.gmane-mx.org; Sat, 11 Jan 2020 22:56:23 +0100 Original-Received: from localhost ([::1]:32904 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iqOk2-00059E-CH for guile-user@m.gmane-mx.org; Sat, 11 Jan 2020 16:56:22 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:55994) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1iqOjo-00054x-Om for guile-user@gnu.org; Sat, 11 Jan 2020 16:56:10 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1iqOjn-0001iw-9o for guile-user@gnu.org; Sat, 11 Jan 2020 16:56:08 -0500 Original-Received: from mail-wr1-x429.google.com ([2a00:1450:4864:20::429]:44097) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1iqOjm-0001ZZ-VY for guile-user@gnu.org; Sat, 11 Jan 2020 16:56:07 -0500 Original-Received: by mail-wr1-x429.google.com with SMTP id q10so4977636wrm.11 for ; Sat, 11 Jan 2020 13:56:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=subject:to:cc:references:from:message-id:date:user-agent :mime-version:in-reply-to:content-language:content-transfer-encoding; bh=kKl7MD34VQC7oGIQ6pjD1gpnO5NcDluwT/IZVpZJI7M=; b=uk1kfxINZ17ATvFrQ1ejTANJ68Cg2eRTEnM/toC7ELHgvzpzQ1gqK7N3paa2np1K9H b80QIfbSiaYSOq378Pd89XZ/qYKTfrh5oPL2w6OJ7Ds0aPMvbi+CfgN96yq3/lifZGve 5iZgWPEVLTmvmWSIW2VdBLsam/LiO4lgER7yjs6OW/LfyvpUbJyYuNRwAAOnr2cXu9xD syirypgPebQ61aSeLT1NdX3SgFF3TLkmbFtZ2JZ0/emeKaNXevI/eWdJv89hoa7r+NLs Zh/DpAZu9QlHnFT2qbtpMRqwzJ0nj4iFbiJvqUF1JrhRbGi1OjLyFbx+ueV/HEmRNbe2 pTDA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:subject:to:cc:references:from:message-id:date :user-agent:mime-version:in-reply-to:content-language :content-transfer-encoding; bh=kKl7MD34VQC7oGIQ6pjD1gpnO5NcDluwT/IZVpZJI7M=; b=clA0Bom4+G7MEvcovtoLwJvjEkQqRwvFcfJfafaiDosuXthoIg/pnRgvNl1jUB4zE4 oJNaoqNW9Mr1ZeLZGW0ye1+CH1Hi2bukz80qvx6N34hmgOMm2NFHuc5OGXZASFPVd/4b INlf0GES0RC9PlZ9zR8NeSGmqlA399/2I6Fm6VKV3xmVyoD/yh8TzM5/pN8SSY0JIUjU mtUPijji4rtWiYmvBb3ptTJlYgaIZSuKZ0z7UX7SxyLdanv15hiBziquRL8haINQm9Ns QRnQ6Wz2QMZu3yd+AVxI7YWFeRZi9TZtaiR4l46wIUZkDUDhwAkzzeHH51ZnQXE0MEWE x4Kw== X-Gm-Message-State: APjAAAVhFaMIOV3tbF7Y3j3vM6JNN+ThZX6kmIDOGPF5ZWmCk2EtucrS yI18+uJN4TChgkMf1ALi9uXz8Fl4 X-Google-Smtp-Source: APXvYqwWFl0plWnZ4yNxgtzU8piMBSGoSzeZPmDpMHuAeC8KM8d3xHX1Hq9xzrE2ussOgit5fP5KCg== X-Received: by 2002:a5d:608e:: with SMTP id w14mr10625755wrt.256.1578779762454; Sat, 11 Jan 2020 13:56:02 -0800 (PST) Original-Received: from ?IPv6:2a02:908:c70:52c0:795c:7930:3d3d:e8cf? ([2a02:908:c70:52c0:795c:7930:3d3d:e8cf]) by smtp.gmail.com with ESMTPSA id d16sm8343745wrg.27.2020.01.11.13.56.01 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sat, 11 Jan 2020 13:56:01 -0800 (PST) In-Reply-To: Content-Language: en-US X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::429 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.org gmane.lisp.guile.user:16034 Archived-At: On 11.01.2020 19:52, Linas Vepstas wrote: > Or, thinking aloud a bit: boxes and symbols.... > > So, for example, if I was able to tell apart calls (f 42) from calls (f x) > where x is a "symbol" (or "variable", *see below*) referencing an integer, > then, for the former case, I could create a new symbol (in guile) and > attach it to a box, fill that box with whatever (f 42) would have returned. > Thence-forward, any call site in the guile code that had (f 42) in it would > get replaced by the symbol (or the unboxed value)... > > At the moment, I don't know how to tell apart 42, the literal number, from > x, a symbol that references a number. (Somehow, I can't make symbol? work > ...) I also don't know how to "edit" the call site (the cell, the box?) > that has (f 42) as the call-target, and replace it by a constant (or a > boxed constant). > > But my naive thinking fails: > (define x 0) > (symbol? x) => #f > (variable? x) => #f > > So I guess that x is not a symbol, from the guile point of view!? This is > .. confusing. What is x, then, if not a symbol? The issue here is that the expression "(symbol? x)" first evaluates the expressions "symbol?" and "x" and then uses their values to go on. So it ends up being: ( ) So by the time the procedure behind "symbol?" is called, it neither knows that it was called "symbol?" nor does it know that the value it received, i.e. the integer 0, came from a variable called "x". What you want to do is delve down to the macro layer so to say, by using "define-syntax" and ideally "syntax-case". Here's a demonstration: (define-syntax symbol-syntax? (lambda (stx) (syntax-case stx () ((_ x) (if (symbol? (syntax->datum #'x)) #'(display "yep\n") #'(display "nope\n")))))) scheme> (symbol-syntax? blah) yep scheme> (symbol-syntax? (blah)) nope What happens here is the following. Going through it part by part. (define-syntax symbol-syntax? (lambda (stx) ... You register a procedure (lambda (stx) ...) as a macro which you bind to "symbol-syntax?". Now the expression "(symbol-syntax? blah)" will not be evaluated in the regular fashion, because Guile sees that "symbol-syntax?" is registered as a macro. Instead of trying to get the values of "symbol-syntax?" and "blah" like it happened with "(symbol? x)", this time Guile calls the procedure registered with "symbol-syntax?" immediately, and passes it a "syntax object" that represents the whole expression "(symbol-syntax? blah)". (Not just the "blah" argument but the whole expression, don't ask why.) (syntax-case stx () ((_ x) ... Within the procedure, we use "syntax-case" to do pattern-matching on the expression "(symbol-syntax? blah)" that is stored in the variable "stx". We know that the first thing in the expression is "symbol-syntax?" because otherwise we wouldn't have been invoked in the first place, so we want to ignore that, hence we use the pattern "(_ x)" which ignores the first thing (via the underscore) and binds the second thing to "x". That second thing is "blah" so "x" contains that now. (if (symbol? (syntax->datum #'x)) ... Now "x" contains the element "blah" but to your probable surprise, it's not a symbol but rather a syntax object. Thankfully we can just call "syntax->datum" to get the corresponding data value, which is going to be the symbol "blah". You're probably wondering why we wrote #'x instead of just x in our call to "syntax->datum" and to be honest I'm not 100% clear on the reason to this day, but it's how syntax-case expects you to use pattern variables. You're never allowed to reference them "bare". #'(display "yep\n") Finally, we use #' to create a whole new syntax object, containing the expression (display "yep\n"). That syntax object is the value returned from our procedure, so Guile puts it where "(symbol-syntax? blah)" was. When you compile the code, all that actually ends up in the program is "(display ...)" with no trace of the original "(symbol-syntax? ...)" expression being left. That's what macros do; they replace code at compile time and leave no trace of themselves. In the second call, "(symbol-syntax? (blah))", the pattern variable "x" ends up containing a syntax object representing "(blah)", and calling "syntax->datum" on that yields a list and not a symbol, hence we end up returning '(display "nope\n")' from the macro. ---------- All that might be daunting at first but after a while it becomes natural, and the power it gives the programmer is really like nothing else. :-) What you intend to do, which is traverse through a whole lambda body and find instances of "(f 42)" to replace them, might be a bit tricky. Let's say you've written a macro "my-define" which does that, then consider the following definition: (my-define (foo x) (let ((f 42)) (+ f x))) Now you probably don't want to turn that "(f 42)" into anything else, because it's not really a call to your "f". I've never written a macro yet which does something like that, so I'm not sure I can help, but I'm happy to respond to questions about the general workings of the macro system. - Taylan