From debbugs-submit-bounces@debbugs.gnu.org Fri Jan 22 09:47:50 2021 Received: (at submit) by debbugs.gnu.org; 22 Jan 2021 14:47:50 +0000 Received: from localhost ([127.0.0.1]:60262 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1l2xj0-0004YG-2C for submit@debbugs.gnu.org; Fri, 22 Jan 2021 09:47:50 -0500 Received: from lists.gnu.org ([209.51.188.17]:36814) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1l2xiy-0004Y9-9f for submit@debbugs.gnu.org; Fri, 22 Jan 2021 09:47:44 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]:55486) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1l2xiy-0005o5-23 for bug-guile@gnu.org; Fri, 22 Jan 2021 09:47:44 -0500 Received: from mx1.dismail.de ([78.46.223.134]:8253) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1l2xin-00066M-J5 for bug-guile@gnu.org; Fri, 22 Jan 2021 09:47:43 -0500 Received: from mx1.dismail.de (localhost [127.0.0.1]) by mx1.dismail.de (OpenSMTPD) with ESMTP id 98d885d8; Fri, 22 Jan 2021 15:47:29 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed; d=dismail.de; h=from:to:cc :subject:references:date:in-reply-to:message-id:mime-version :content-type:content-transfer-encoding; s=20190914; bh=K2EZR464 tZk2lyg8s0Ftdu4et19li+UZVpkCUgS/0x4=; b=ZjkgM66z1kmsBF/Xbu3ElIfr t+t2IjUyiWDHX7Zba8QXbnCI4d1AZp9YnZwmOr/HxmXG0pMnYuN2dD3PXhZMj9bk uuXk3YBSdqE+sPIQa3AIMCWFnblhB9eouiZ6+QyS0ovfB/nroEd1agIjce0GaZOF DbHsxz0gXNcgQEDyeyz3a/eEAWW88yCzmas8IQIfhjU26rjwFxF3GHGT6jhE+8e9 wIwvCbeZwU+CQwYh+uknDuV1rCtJIOgsbpfyB4pcyw+7AXSXGAqxXhYYFMWvnjy/ rp0+4mEyYg0d98VmLZ0IJ0qhiap0yR0Apqg0GKdyQMN4sS6PwEm2QqwxnoPVMA== Received: from smtp2.dismail.de ( [10.240.26.12]) by mx1.dismail.de (OpenSMTPD) with ESMTP id 4ab318b5; Fri, 22 Jan 2021 15:47:28 +0100 (CET) Received: from smtp2.dismail.de (localhost [127.0.0.1]) by smtp2.dismail.de (OpenSMTPD) with ESMTP id d3cf5317; Fri, 22 Jan 2021 15:47:28 +0100 (CET) Received: by dismail.de (OpenSMTPD) with ESMTPSA id 067f0767 (TLSv1.3:AEAD-AES256-GCM-SHA384:256:NO); Fri, 22 Jan 2021 15:47:27 +0100 (CET) From: Joshua Branson To: Ricardo Wurmus Subject: Re: bug#46014: (define (thunk) (lambda (x) x)) should be a compile error? References: <87h7nb3v0g.fsf@dismail.de> <87bldil7fo.fsf@elephly.net> <87eeie2gs1.fsf@dismail.de> <878s8mkjsk.fsf@elephly.net> Date: Fri, 22 Jan 2021 09:47:24 -0500 In-Reply-To: <878s8mkjsk.fsf@elephly.net> (Ricardo Wurmus's message of "Thu, 21 Jan 2021 23:27:23 +0100") Message-ID: <87o8hhyqo3.fsf@dismail.de> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.1 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Received-SPF: pass client-ip=78.46.223.134; envelope-from=jbranso@dismail.de; helo=mx1.dismail.de X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 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, RCVD_IN_DNSWL_MED=-2.3, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -1.4 (-) X-Debbugs-Envelope-To: submit Cc: bug-guile@gnu.org, 46014@debbugs.gnu.org X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -0.1 (/) Ricardo Wurmus writes: > Hi Joshua, > >> When I look at >> >> #+BEGIN_SRC scheme >> (define (thunk) >> (lambda (x) >> x)) >> #+END_SRC > > [=E2=80=A6] > >> My thought is, this is clearly a mistake. This person needs to change >> the above code. > > How is this clearly a mistake? The definition of =E2=80=9Cthunk=E2=80=9D= above is > perfectly fine and also common. Thanks again for responding. I'm still learning scheme, and it's cool that this email chain has helped clarify some things. :) Ahh. I see now that the proper way to call thunk is to do this: ((thunk) "the") $1 =3D "the" I had assumed that every time one called thunk, it would result in a runtime error. I did not realize that there was a way to properly call thunk. Wow. Scheme is truly impressive. Interestingly, I had wrongly assumed that #+BEGIN_SRC scheme (thunk "test\n") ;; I assumed program execution would stop here (display "Hello World\n") #+END_SRC program execution would stop at (thunk "test\n"). But it actually caries on with execution of the program: #+BEGIN_SRC scheme :5:0: warning: possibly wrong number of arguments to `thunk' ice-9/boot-9.scm:1669:16: In procedure raise-exception: Wrong number of arguments to # Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. Hello World #+END_SRC I'm not certain if it is a good or bad thing that scheme continues program execution after a runtime error. I know I've built toy web applications in guile... Sometimes the input to a form is bad data, and the web-server emits a runtime error, but keeps running. Maybe it would be better if the program halted on every runtime error. It would be a way of saying, "Hey your web-server hasn't really handled dealing with bad data properly. You need to fix it, because I will crash at every run time error." For fun I also thought about how else I could write thunk. Continue reading at your own peril. #+BEGIN_SRC scheme ;; This procedure doesn't work the way I thought it would. The way to ;; print a string with this procedure is to do this: ;; ((thunk "the") "the") (define (thunk x) (lambda (x) x)) ;; obvious. This is equivalent to ;; (define (thunk x) x) (define thunk (lambda (x) x)) ;; This ones nice because neither (thunk) nor (thunk "the") result in a ;; runtime error. (define* (thunk #:optional x) x) (define* (thunk #:optional x) (lambda* (#:optional x) x)) #+END_SRC Are there some other really weird and convoluted ways of writing thunk that I'm missing? I'm guessing so. > > The above is equivalent to > > (define thunk > (lambda () > (lambda (x) x))) > > And that=E2=80=99s really okay and can be desired. The problem is not w= ith > this definition. If someone calls this wrongly, well, that=E2=80=99s a p= roblem > with the caller. And Guile=E2=80=99s compiler does tell you that you are > probably wrong in calling =E2=80=9Cthunk=E2=80=9D with an argument. > > Do I understand you correctly that you would like this warning to be an > error instead? No. Not anymore. Before I had assumed that any invocation of thunk would result in a runtime error. If that was the case, I figured guile should refuse to compile it. Now I realize that ((thunk "the") "the") works. > >> Gotcha. Thanks for explaining! I suppose what I meant to say is, >> should guile refuse to compile the above? In other languages, like C I >> suppose, writing a function simultaneous with one and two arguments >> would refuse to compile. The compiler would make you fix the code. > > Let me address this separately. In Scheme you *can* define a procedure > that takes a different number of arguments. Here=E2=80=99s one example f= rom the > manual: > > (define (make-accum n) > (case-lambda > (() n) > ((m) (set! n (+ n m)) n))) > > (define a (make-accum 20)) > (a) =E2=87=92 20 > (a 10) =E2=87=92 30 > (a) =E2=87=92 30 > > =E2=80=9Ccase-lambda=E2=80=9D specifies a procedure that can take argumen= ts in as many > different shapes as there are clauses. Here there are two clauses: one > for the case where no arguments are provided and another where one > argument (bound to =E2=80=9Cm=E2=80=9D) is provided. > > Furthermore, you can see here that this is a higher order procedure, as > =E2=80=9Cmake-accum=E2=80=9D takes an argument and returns a procedure (t= he > case-lambda). Oh wow! Man am I going to have fun with case-lambda! Thanks for pointing that out! > > Another example, also from the manual, is this: > > (lambda* (start #:optional (end (+ 10 start))) > (do ((i start (1+ i))) > ((> i end)) > (display i))) > > This procedure takes one or two arguments. Thanks again for explaining this to me. I've learned a lot from this interaction! Do you think there are some warnings in guile that should be escalated to errors that refuse to compile? How about this example? (later on I changed my mind and realized this example doesn't really prove my point). #+BEGIN_SRC scheme (use-modules (guix-records)) (define-record-type* lunch-time make-lunch-time lunch-time? (period lunch-time-period (default "10 min"))) (define-record-type* lunch make-lunch lunch? (food lunch-food (default "pizza")) (duration lunch-duration ;; here time should by lunch-time instead (default (time (period "30 min"))))) (lunch) #+END_SRC When I pasted this into the REPL, the result is: ;;; :26:0: warning: possibly unbound variable `time' ;;; :26:0: warning: possibly unbound variable `period' ice-9/boot-9.scm:1669:16: In procedure raise-exception: Unbound variable: time Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. This appears to me to be a case where, there is NO way to properly make a lunch record without creating a run time error. Whoops. Actually there is a proper way to make a lunch record: #+BEGIN_SRC scheme (make-lunch "sandwich" "one hour") #+END_SRC I suppose the moral of the story is that scheme is so expressive and flexible that there are ways of creating programs that can fail in weird ways. And it's really hard if not impossible to catch all possible runtime errors at compile time. This is because scheme values are only know at run-time AND NOT compile time. I was actually listening to a scheme talk recently about typed racket. The gentleman giving the talk explained that dynamic typing used to be all the rage, but there seems to be some people advocating for static typing because the compiler eliminates many trivial bugs. However, some elegant and correct dynamic programs would be eliminated by the compiler as causing errors. typed scheme | untyped scheme ---------------------------------------------------------------- - potentially faster | - potentially slower - a procedure's inputs | - more expressive and outputs are obvious | - more concise - catches trivial errors | - helps refactoring | - eliminates "correct" dynamic programs I suppose that what I am wanting (forcing the compiler to eliminate trivial bugs) may only be possible in a typed scheme. Is that correct? What are your thoughts? Typed or un-typed scheme? Thanks, Joshua -- Joshua Branson (joshuaBPMan in #guix) Sent from Emacs and Gnus https://gnucode.me https://video.hardlimit.com/accounts/joshua_branson/video-channels https://propernaming.org "You can have whatever you want, as long as you help enough other people get what they want." - Zig Ziglar