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 mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by sympa.inria.fr (Postfix) with ESMTPS id 5332B7F75C for ; Thu, 11 Sep 2014 00:50:07 +0200 (CEST) Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of yallop@gmail.com) identity=pra; client-ip=74.125.82.47; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="yallop@gmail.com"; x-sender="yallop@gmail.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail3-smtp-sop.national.inria.fr: domain of yallop@gmail.com designates 74.125.82.47 as permitted sender) identity=mailfrom; client-ip=74.125.82.47; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="yallop@gmail.com"; x-sender="yallop@gmail.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of postmaster@mail-wg0-f47.google.com) identity=helo; client-ip=74.125.82.47; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="yallop@gmail.com"; x-sender="postmaster@mail-wg0-f47.google.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Aj8BAPvUEFRKfVIvm2dsb2JhbABgg2BNDoJ4x0eHTQGBCggWEAEBAQEBBgsLCRQqhAQBAQQSEQQZARsdAQMMBgULDQICJgICIQEBEQEFARwGEyKICwEDEQ2dYWuLMIFygxCJAAoZJw1mhXwBEQEFDoEei3SCLQeCeYFTBZV5hHOCEIFfjR2ESxgphRM8LwGCTgEBAQ X-IPAS-Result: Aj8BAPvUEFRKfVIvm2dsb2JhbABgg2BNDoJ4x0eHTQGBCggWEAEBAQEBBgsLCRQqhAQBAQQSEQQZARsdAQMMBgULDQICJgICIQEBEQEFARwGEyKICwEDEQ2dYWuLMIFygxCJAAoZJw1mhXwBEQEFDoEei3SCLQeCeYFTBZV5hHOCEIFfjR2ESxgphRM8LwGCTgEBAQ X-IronPort-AV: E=Sophos;i="5.04,501,1406584800"; d="scan'208";a="78494804" Received: from mail-wg0-f47.google.com ([74.125.82.47]) by mail3-smtp-sop.national.inria.fr with ESMTP/TLS/RC4-SHA; 11 Sep 2014 00:50:06 +0200 Received: by mail-wg0-f47.google.com with SMTP id y10so4871634wgg.30 for ; Wed, 10 Sep 2014 15:50:06 -0700 (PDT) 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=SXFzbU7UWlYZ6McwLDU5AFWzMyicZ1xSgElULEYiLfg=; b=C6Pv0vl+tDKhBJSMAZazWArRBsXhg2zKo4jhccMo4eHzJ4FHB3j1QRep1Eah1esJDS cCeDF94v+a0iiSuTWMuqfMfEefTF/zRi9lC/suJKzRNdWHrEFuc23S2FRxle4bZmjkBJ hU914l8ibzap488RLSxagL3n5kBTO0ZKNMUzAGRfMz7wmtwwKUEOven6OL3LCBsW3Xwa pQEdGJy5mkUsRdtygwtgYpD96B/zm5hL4ey74floJFKJG+AQ5CSecaPS1EJRA3R48SD2 HWcFPQV8QCSIn75Heg6V4DpNQ/JK6GPO4hN7uhpHb0dYxLfO/r+qdLmvZKZTqO5p6OhO DLpA== MIME-Version: 1.0 X-Received: by 10.194.59.201 with SMTP id b9mr53922802wjr.43.1410389406185; Wed, 10 Sep 2014 15:50:06 -0700 (PDT) Received: by 10.217.129.194 with HTTP; Wed, 10 Sep 2014 15:50:06 -0700 (PDT) In-Reply-To: References: Date: Wed, 10 Sep 2014 23:50:06 +0100 Message-ID: From: Jeremy Yallop To: Yotam Barnoy Cc: Ocaml Mailing List Content-Type: text/plain; charset=UTF-8 Subject: Re: [Caml-list] Undefined recursive module On 10 September 2014 23:26, Yotam Barnoy wrote: > On Wed, Sep 10, 2014 at 6:20 PM, Jeremy Yallop wrote: >> >> On 10 September 2014 21:32, Yotam Barnoy wrote: >> > I just encountered this nasty RUNTIME error in my code. What does it >> > mean? >> > How does it happen? >> >> The behaviour is documented in the manual: >> >> http://caml.inria.fr/pub/docs/manual-ocaml-400/manual021.html#toc75 >> >> See the paragraph beginning "Currently, the compiler requires [...]". > > Thanks. Does it make sense that changing a function definition from > point-free to an explicit definition should eliminate this exception? Yes, that's the expected behaviour. Initially the fields in a recursive module are bound to functions that raise an exception. The module initialization then overwrites each field with its actual value, which is determined by evaluating the expression on the right hand side of the field definition. If evaluating the right hand side involves reading one of the fields of the module that has not yet been overwritten then the field will resolve to the exception-raising function, which may lead to the runtime error that you've seen. Here's an example. Suppose you have a recursive module like this: module rec M1 : sig val x : unit -> unit end = struct let x = M1.x end Then the initial state of the module at runtime has x bound to a function that raises an exception: module rec M1 : sig val x : unit -> unit end = struct let x = fun _ -> raise Undefined_recursive_module end Module initialization then overwrites the field with the result of evaluating the right-hand side -- that is, by the result of evaluating M1.x: M1.x <- (fun _ -> raise Undefined_recursive_module) Calling M1.x will lead to the exception being raised: M1.x () => raise Undefined_recursive_module Now consider what happens when you eta-expand the definition of x. Here's the source program module rec M2 : sig val x : unit -> unit end = struct let x = fun e -> M2.x e end The initial state of the module at runtime is the same as for M1: module rec M2 : sig val x : unit -> unit end = struct let x = fun _ -> raise Undefined_recursive_module end end Once again, module initialization overwrites the field with the result of evaluating the right-hand side. This time, however, evaluating the right-hand side doesn't require resolving M2.x, since M2.x is under a 'fun' binding: M2.x <- (fun e -> M2.x e) When you come to call M2.x the recursive reference resolves to the new value of the field and evaluation proceeds as expected: M2.x () => M2.x () As the manual says, all of this is subject to change, and it's best not to rely on the current behaviour. I recommend that you avoid using recursive modules for value-level recursion, if possible.