Mailing list for all users of the OCaml language and system.
 help / color / mirror / Atom feed
From: Jordan W <jordojw@gmail.com>
To: Gabriel Scherer <gabriel.scherer@gmail.com>
Cc: "caml-list@inria.fr" <caml-list@inria.fr>
Subject: Re: [Caml-list] Mutual recursion propagates individual recursion. Why?
Date: Mon, 2 Mar 2015 01:18:51 -0800	[thread overview]
Message-ID: <CAPOA5_5-G-ura60Dr98xjfgja-GJ-B8_TMoqT7Gyx3ipF-cCqQ@mail.gmail.com> (raw)
In-Reply-To: <CAPFanBF1XfOSCNsj=zYFZN=SgKQnh47+ccyp+7Y+_=URRqW7pg@mail.gmail.com>

>> 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
<gabriel.scherer@gmail.com> 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 <jordojw@gmail.com> 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
>
>

  parent reply	other threads:[~2015-03-02  9:18 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-02  6:25 Jordan W
2015-03-02  7:25 ` Gabriel Scherer
2015-03-02  9:14   ` Ben Millwood
2015-03-02  9:18   ` Jordan W [this message]
2015-03-02  9:49     ` Ben Millwood

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CAPOA5_5-G-ura60Dr98xjfgja-GJ-B8_TMoqT7Gyx3ipF-cCqQ@mail.gmail.com \
    --to=jordojw@gmail.com \
    --cc=caml-list@inria.fr \
    --cc=gabriel.scherer@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox