From mboxrd@z Thu Jan 1 00:00:00 1970 From: Amirouche Boubekki Subject: Re: G expressions Date: Mon, 28 Apr 2014 16:03:50 +0200 Message-ID: References: <871twneldl.fsf@gnu.org> <87fvkxew6j.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary=20cf3011db9d1a0de504f81aca0e Return-path: Received: from eggs.gnu.org ([2001:4830:134:3::10]:42851) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1WemAJ-0000Xg-9m for guix-devel@gnu.org; Mon, 28 Apr 2014 10:04:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1WemAF-00035w-WF for guix-devel@gnu.org; Mon, 28 Apr 2014 10:04:15 -0400 In-Reply-To: <87fvkxew6j.fsf@gnu.org> List-Id: "Development of GNU Guix and the GNU System distribution." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-devel-bounces+gcggd-guix-devel=m.gmane.org@gnu.org Sender: guix-devel-bounces+gcggd-guix-devel=m.gmane.org@gnu.org To: =?UTF-8?Q?Ludovic_Court=C3=A8s?= Cc: guix-devel@gnu.org --20cf3011db9d1a0de504f81aca0e Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable 2014-04-28 9:43 GMT+02:00 Ludovic Court=C3=A8s : # Hello! # 1. The Problem # =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D H=C3=A9llo! I was going to learn a bit of emacs lisp then... a duck got in my way. # There=E2=80=99s a recurrent problem that we need to communicate the file = name of # store items to Scheme code that is going to live in another process: # expressions to build a derivation, Scheme files that are to be loaded by # other processes, etc. This seems to be a referential transparency problem. Probably the Funarg problem. Quoting http://en.wikipedia.org/wiki/Funarg_problem: :w: The difficulty only arises if the body of a [[nested function]] refers directly :w: (i.e., not via argument passing) to identifiers defined in the environm= ent :w: in which the function is defined, but not in the environment of the fun= ction :w: call. :w: [http://portal.acm.org/citation.cfm?id=3D1093411 :w: ''The function of FUNCTION in LISP or why the FUNARG problem should b= e :w: called the environment problem'', :w: :w: by Joel Moses, in: ACM SIGSAM Bulletin 17 (July 1970), pp. 13-27] :w: [Two] standard resolutions are to either forbid such references or to :w: create [[closure (computer science)|closure]]s. :w: [http://portal.acm.org/citation.cfm?id=3D1093420.1093422 :w: ''A proposed solution to the FUNARG problem'', :w: by Erik Sandewall, in: ACM SIGSAM Bulletin 17 (Jan. 1971), pp. 29-42] :w: It's a scoping issue due to the context of where the call is really done. I= n Guile arguments are passed as value. So, the procedure loose the context of the value. It's just a "thunk" or log. # This had been partly addressed by having =E2=80=98build-expression->deriv= ation=E2=80=99 # install two global variables in the build code: =E2=80=98%build-inputs=E2= =80=99 and # =E2=80=98%outputs=E2=80=99. I don't like globals but I have no good reasons, except that it "pollutes" the environment. IRL, it's a problem when you want to move to "higher level"s. # However, for generated Scheme files (as in (gnu system) and related # modules), there=E2=80=99s no such mechanism. Thus, either we use somethi= ng # like: # (mlet %store-monad ((ls (package-file coreutils "bin/ls"))) # (text-file "foo" (object->string `(system* ,ls)))) cf. https://www.gnu.org/software/guix/manual/guix.html#The-Store-Monad # but then the problem is that the resulting text file doesn=E2=80=99t hold= a # reference to Coreutils, which is wrong. Or, we do something like: # (text-file* "foo" "(system* \"" coreutils "/bin/ls\")") # The resulting file does have a reference to Coreutils, but the approach # obviously sucks. # Besides, =E2=80=98%build-inputs=E2=80=99 is not particularly elegant eith= er, and it=E2=80=99s # error-prone (if you refer to an input by the wrong name, you only notice # when building, with an obscure wrong-type-arg error.) That=E2=80=99s bee= n OK as # it=E2=80=99s only used occasionally in package recipes. I can not make justice to the style (it's ugly!). I don't have enough exper= ience in scheme/fp/guile to distinguish between a good solution and workaround -- something. AFAIK, both process don't share the same memory, so it's even more difficult to share data, in the broad sens. In this case, writring sex= p directly allows to keep some of the information, but not all of it, because the values are evaluated. This evaluation thing troubles me a lot. That's one of the reasons I starte= d scheme: macros. I did not write, consciously, a single macro, yet. .. python:: https://github.com/lihaoyi/macropy In python, there is a *run* *time*. That is all. Some time you take care of *import* *time*. But then you forget about it. So far, my understanding of scheme led me to think _that anything anywhere could be something else i= n reality_. In particular, it's possible to provide procedures to the parser called macros that are evaluated when sexps are parsed. In the particular case of guix why not send to just data? So that context can not be /overriden/. Like I said, I don't understand fully macros nor monads and I stumbled upon http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictu= res.html I understand that the article explains what does it mean that Haskell is ty= ped. I understand that haskell has "higher order" procedures, that are not readi= ly available in imperative languages plus some extras for being self aware of = that fact. In fact, what /functors/, /applicatives/ and /monads/ do, is possible in al= l languages. If they are not used often so far, it's because people were miss= ing something... Those /higher level/ procedures that can be found in Haskell are *forbidden* in imperative languages: GOTO, monkey-patching, metaclasses= or grossly ineficient like callbacks for dealing with asynchronous behaviors a= nd otherwise. .. seealso:: (url [Callbacks as our Generations' Go To Statement] http://tirania.org/blog/archive/2013/Aug-15.html) IMO the article explains different *patterns* that dynamically change the runtime. It's like a bestiary of some sort, see http://en.wikibooks.org/wiki/Haskell/Understanding_arrows In the end it's just a procedure call, a combinatory logic, to make somethi= ng that looked like http://community.schemewiki.org/?amb, more discrete (and more human?). I don't say there is no interest in this approach(!). .. seealso:: (url [Combinatorial Generation Using Coroutines With Examples in Python] https://news.ycombinator.com/item?id=3D7655488) At least the above, lead me to (quote gexp). # 2. G Expressions # =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D # =E2=80=9CG-expressions=E2=80=9D, or gexps, are meant to address these two= issues # mentioned above: Passing parameters by *intent* instead of by value? # 1. Replacing a reference to a package or derivation by its output file # name; cf. https://www.gnu.org/software/guix/manual/guix.html#Derivations # 2. Keeping track of the derivations it refers to. I interpret this as: =C2=ABIt must be possible to (back)trace anywhere, anytime... anything= =C2=BB Out of the context of guix, that could be better or worse misunderstanding = :) # In addition, the substitution in (1) must be done lazily, so that you # get the output file name for the =E2=80=98%current-system=E2=80=99 value = when the gexp # is used. # The =E2=80=98gexp=E2=80=99 form is essentially like =E2=80=98quasiquote= =E2=80=99, with =E2=80=98ungexp=E2=80=99 as the # counterpart of =E2=80=98unquote=E2=80=99: # (gexp (system* (string-append (ungexp coreutils) "/bin/ls"))) What about the following: ;; (quote (system* (string-append (coreutils "/bin/ls")))) I don't understand the difference with classic macro. Is it a problem of nesting? Something like that isn't possible: ;; (quote (system* (string-append (coreutils (:somekind-of-sexp-parser-hook-eval: program-path)))) # That gexp can then be passed to =E2=80=98gexp->file=E2=80=99, which retur= ns a derivation # that builds a file containing: It is passed to the server ie. the guix builder? # (system* (string-append "/gnu/store/=E2=80=A6" "/bin/ls")) # And it can also be used to describe derivation builds: # (gexp->derivation "foo" # (gexp # (begin # (mkdir (ungexp output)) # (chdir (ungexp output)) # (symlink (ungexp coreutils) "cu")))) # Note that we don=E2=80=99t need #:inputs here, because the gexp embeds th= at # info. So eventually, we could even get rid of the label in the =E2=80=98= inputs=E2=80=99 # field of packages (not a priority, though.) # We could use some sugar to make it more concise (suggestions welcome): # (gexp->derivation "foo" # #~(begin # (mkdir #$output) # (chdir #$output) # (symlink #$coreutils "cu"))) - It's possible to parse variable names in macros? - I don't like #~ or #$ I prefer an infix notation with *words* as it is more readable: ;; (gexp (gexp.begin (make.directory ungexp.output) (change.directory ungexp.output) (symlink ungexp.coreutils "cu"))) I added some fioritures that you will probably find pointless. IMHO it's significant. # 3. Conclusion # =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D # I think gexps can be helpful to serialize Scheme code that refers to # packages/derivations. Preliminary work is in =E2=80=98wip-gexp=E2=80=99. # What do you think? It's seems to me that it's yet another /upward & downard funarg/. # 4. Related Work :-) # =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D # HOP has a quotation mechanism to introduce client-side code in server # code and vice-versa: # (