From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id 908987EE48 for ; Mon, 2 Mar 2015 10:18:53 +0100 (CET) Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of jordojw@gmail.com) identity=pra; client-ip=209.85.217.169; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="jordojw@gmail.com"; x-sender="jordojw@gmail.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of jordojw@gmail.com designates 209.85.217.169 as permitted sender) identity=mailfrom; client-ip=209.85.217.169; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="jordojw@gmail.com"; x-sender="jordojw@gmail.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@mail-lb0-f169.google.com) identity=helo; client-ip=209.85.217.169; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="jordojw@gmail.com"; x-sender="postmaster@mail-lb0-f169.google.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A0BrAQCvKfRUlKnZVdFag1ROEIMGrkmPZoVwAoEaB00BAQEBAQEQAQEBAQcLCwkSMIQPAQEBAwESEQQZARsSCwEDDAYFCw0CAgkdAgIhAQERAQUBChIGExIJB4d4AQMJCA2vTj4xiy6Ba4J3jiwKGScDClSEXwEBAQEBAQQBAQEBAQEWAQUOgROJcYJEgioHgmiBQwWEZwqFa4h8g2wzgUiBGhEoi3yCTYF0EiOBDAmCJRyBcR0xgkMBAQE X-IPAS-Result: A0BrAQCvKfRUlKnZVdFag1ROEIMGrkmPZoVwAoEaB00BAQEBAQEQAQEBAQcLCwkSMIQPAQEBAwESEQQZARsSCwEDDAYFCw0CAgkdAgIhAQERAQUBChIGExIJB4d4AQMJCA2vTj4xiy6Ba4J3jiwKGScDClSEXwEBAQEBAQQBAQEBAQEWAQUOgROJcYJEgioHgmiBQwWEZwqFa4h8g2wzgUiBGhEoi3yCTYF0EiOBDAmCJRyBcR0xgkMBAQE X-IronPort-AV: E=Sophos;i="5.09,674,1418079600"; d="scan'208";a="123934139" Received: from mail-lb0-f169.google.com ([209.85.217.169]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/RC4-SHA; 02 Mar 2015 10:18:52 +0100 Received: by lbjf15 with SMTP id f15so738109lbj.2 for ; Mon, 02 Mar 2015 01:18:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:in-reply-to:references:date:message-id:subject:from:to :cc:content-type; bh=geMzCgFmROVSa4r89Miw83asgHlKZNAfqLa5UwWZQ8A=; b=G3Dx0igp84DisTeQB+b3oYApL22XNDeGEvgvayFTvJ3wTKmFSBQNoGt2Xt5lktGeYD 8azui/Yj5uA2Wf0IAlhnPmT5VN0sxlmI0qM+XHn423ofzTOYqhB9S40kD03ZylRBj04F N5DXqxFy43muZYblOfo7JNU0ldABHlhZPRKYDqnAITDYU+fRRhV5du+4ZHZLNiVKzLWG rc5UKzMXuXEsm4NUMFuQJQAWiYKf+jRzHSp0//JkA47kxEmVgt7N2DyyFT71tbcgpKWr 5XOkVlFrIkN89ClEfzQACRfPuqfVa7PBo91CuCrW/DhU1Dwv0vSYoleTtOwrPYNaeFfc IOFQ== MIME-Version: 1.0 X-Received: by 10.152.22.200 with SMTP id g8mr20953958laf.96.1425287931891; Mon, 02 Mar 2015 01:18:51 -0800 (PST) Received: by 10.25.128.3 with HTTP; Mon, 2 Mar 2015 01:18:51 -0800 (PST) In-Reply-To: References: Date: Mon, 2 Mar 2015 01:18:51 -0800 Message-ID: From: Jordan W To: Gabriel Scherer Cc: "caml-list@inria.fr" Content-Type: text/plain; charset=UTF-8 X-Validation-by: jordojw@gmail.com Subject: Re: [Caml-list] Mutual recursion propagates individual recursion. Why? >> This is rarely useful when programming, but extremely useful when meta-programming, as it allows you to evaluate several different pieces of code in the same scope independently, without risk of variable shadowing I would have never considered that case, but now that you point it out, it absolutely makes sense. I can't think of many use cases for let/and (with no rec) beyond metaprogramming, but I do agree that the language wouldn't feel complete without it so I'm glad remains. let rec .. in let rec ... in E Several self-recursive, non-mutually recursive bindings, dependent environments. let rec ... and ... in E Several self-recursive, and mutually recursive bindings, "simultaneously polluted" environments. let ... and ... in E Several non-self-recursive, non-mutually recursive bindings with "simultaneously isolated" environments. let .. in let ... in E Several non-self-recursive, non-mutually recursive bindings with dependent environments. So is it correct to say that "and" acts in two completely different ways. A. For "let rec", assigns multiple bindings "simultaneously" such that each binding is in every binding's environment (including itself's). B. For "let", assigns multiple bindings "simultaneously" such that each binding is *not* in any other binding's environment (including itself's). I think two forms seems to be lacking: 1. The ability for even just one in a set of "simultaneous" bindings who are all in each other's environments (mutually recursive), to not be in its own environment (non-self-recursive). 2. The ability for even just one of these "simultaneous" bindings who are not in each other's environments (non-mutually recursive), to be in its own environment (self-recursive). I suspect #2 would benefit metaprogramming just as well as the `let .. and ` example. With metaprogramming, where we wish to isolate the environments of several bindings simultaneously, how does a *single* one of these bindings opt into self-recursiveness without forcing the others into self-recursiveness (and thus "polluting the environment")? For #1, here's a simplified/contrived (and nonsensical) example that I've taken it from a real example (but altered/simplified). type nodeType = {decrement: int; msg: unit -> string; subNode: nodeType option};; let rec sum n = 1 + (sum (n - node.decrement)) and node = { msg = (fun () -> "sum:" ^ (string_of_int (sum 10))); decrement = 1; subNode = Some node; (* Whoops - Cycle! *) };; For the `subNode` field, I might have wanted to refer to some other `node` in scope. But because `node` and `sum` needed to be mutually recursive, there was no choice but for the `node` record value to be self-recursive as well. I'm not yet suggesting a solution, but just trying to articulate my understanding of what is/isn't supported, though it would be great if there was a way to represent each of the possible cases intuitively. If the above explanation is correct, is there any documentation that explains this? On Sun, Mar 1, 2015 at 11:25 PM, Gabriel Scherer wrote: > let x1 = e1 and x2 = e2 and ... and xn = en in body > > Has the effect that the x1,x2,..,xn are bound "simultaneously" in body, and > not before. Unlike what "let x1 = e1 in let x2 = e2 in ..." does, x1 is not > visible in e2, etc. This is rarely useful when programming, but extremely > useful when meta-programming, as it allows you to evaluate several different > pieces of code in the same scope independently, without risk of variable > shadowing. > > For the record I don't find your feature suggestion particularly tempting. > Mutual recursion is more expressive than single-recursion, and I'm not sure > what would be the point of allowing the former and restricting the latter -- > the horse is already out of the barn. Instead of > > let rec fac = function > | 0 -> 1 > | n -> n * fac (n - 1) > > I can write > > let rec fac = function > | 0 -> 1 > | n -> n * f (n - 1) > and f n = fac n > > turning any self-recursion into mutual-recursion. > > I'm not sure I understand your point about accidental value recursion. Do > you have an example? > > Note that it is possible to use recursive modules as a way to have recursion > between phrases (structure items) without explicitly using "rec". It's a bad > idea in most situations, because using recursive modules makes you rely on > more complex (and accordinly more fragile) features of the language. > > On Mon, Mar 2, 2015 at 7:25 AM, Jordan W wrote: >> >> (Note: When trying any of these examples, make sure to kill/restart >> your top level between each examples - non-recursive bindings that >> should fail will appear to work because they use existing bindings in >> the environment). >> >> My understanding is that self-recursion in OCaml is introduced via the >> `let rec` binding keyword pair. >> >> let rec x a = x a >> >> >> A sequence of let bindings are made *both* mutually recursive, *and* >> individually self-recursive via a combination of `let rec` and the >> `and` keyword. >> >> (* Notice how y is made self recursive as well *) >> let rec x a = (x a + y a) and y a = (x a + y a);; >> >> The `and` keyword by itself is not sufficient to introduce mutual >> recursion, and not sufficient to introduce self-recursion for any of >> the bindings joined by the `and`. >> >> (* Does not work *) >> let x a = x a and y a = (x a + y a) >> (* Does not work *) >> let x a = y a and y a = x a >> >> >> My questions are: >> 1. Is there any effect to having the `and` keyword, without a `let >> rec` that initiates the let binding sequence? >> 2. Is there any way to introduce mutual recursion without also >> introducing self-recursion on *all* of the bindings? >> >> I would like self-recursion to be independent from mutual recursion. >> It would be nice to be able to create several mutually recursive >> bindings that are not individually self-recursive. I imagine the >> syntax to accomplish this would require each binding to be opened with >> "let" or "let rec" which would be totally reasonable. >> >> (* Three mutually recursive functions that are not self-recursive *) >> let rec thisOneIsSelfRecursive x = ... and >> let thisOneIsNotSelfRecursive y = ... and >> let rec thisOneIsAlsoSelfRecursive z = ...; >> >> This becomes more desirable when one of the mutually recursive >> bindings is a non-function value that you did not want to make >> self-recursive by accident (which causes cycles). >> >> Jordan >> >> -- >> Caml-list mailing list. Subscription management and archives: >> https://sympa.inria.fr/sympa/arc/caml-list >> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners >> Bug reports: http://caml.inria.fr/bin/caml-bugs > >