{"action":"created","issue":{"url":"https://api.github.com/repos/ocaml/ocaml/issues/185","repository_url":"https://api.github.com/repos/ocaml/ocaml","labels_url":"https://api.github.com/repos/ocaml/ocaml/issues/185/labels{/name}","comments_url":"https://api.github.com/repos/ocaml/ocaml/issues/185/comments","events_url":"https://api.github.com/repos/ocaml/ocaml/issues/185/events","html_url":"https://github.com/ocaml/ocaml/pull/185","id":75610006,"number":185,"title":"Support lazy local let-bindings.","user":{"login":"alainfrisch","id":3305274,"avatar_url":"https://avatars.githubusercontent.com/u/3305274?v=3","gravatar_id":"","url":"https://api.github.com/users/alainfrisch","html_url":"https://github.com/alainfrisch","followers_url":"https://api.github.com/users/alainfrisch/followers","following_url":"https://api.github.com/users/alainfrisch/following{/other_user}","gists_url":"https://api.github.com/users/alainfrisch/gists{/gist_id}","starred_url":"https://api.github.com/users/alainfrisch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alainfrisch/subscriptions","organizations_url":"https://api.github.com/users/alainfrisch/orgs","repos_url":"https://api.github.com/users/alainfrisch/repos","events_url":"https://api.github.com/users/alainfrisch/events{/privacy}","received_events_url":"https://api.github.com/users/alainfrisch/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":12,"created_at":"2015-05-12T13:47:41Z","updated_at":"2016-11-21T01:05:46Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/ocaml/ocaml/pulls/185","html_url":"https://github.com/ocaml/ocaml/pull/185","diff_url":"https://github.com/ocaml/ocaml/pull/185.diff","patch_url":"https://github.com/ocaml/ocaml/pull/185.patch"},"body":"This is a proposal to add lazy local let-bindings to OCaml.  We have been using this extension at LexiFi for years and are quite happy with it.  See:\n\n http://www.lexifi.com/blog/ocaml-extensions-lexifi-semi-implicit-laziness\n\nOne could argue that introducing implicit elimination of laziness hampers program readability, but this specific proposal keeps an explicit \"lazy\" keyword on the introduction site, and is restricted to local bindings, so the elimination remains quite \"close\" to the introduction.\n\nConcretely, this PR adds support for a new form a local let-binding:\n\n``` ocaml\nlazy let x = e in body\n```\n\n(multiple and/or recursive bindings are allowed as well, but only simple variable patterns are allowed -- at least for now).\n\nwhich behaves as:\n\n``` ocaml\nlet x = lazy e' in body'\n```\n\nwhere occurrences of `x` in `body` are replaced by `Lazy.force x` in `body'` (and also to produce `e'` from `e` in case of a `let rec`).\n\nA typical use case is to relax restrictions on recursive let bindings, for instance in the definition of GUI components where callback are attached on upon creation:\n\n``` ocaml\n  lazy let rec b = button \"Run\" ~onclick:(fun () -> b # disable; ...) in\n  hbox [ label \"...\"; b ]\n```\n\nWithout lazy bindings, one could write\n\n``` ocaml\n  let rec b = lazy (button \"Run\" ~onclick:(fun () -> (Lazy.force b) # disable; ...)) in\n  hbox [ label \"...\"; Lazy.force b ]\n```\n\nbut this is so heavy that this would discourage using this style of API in favor of a less functional approach (with callbacks attached as side-effects).\n\nThe implementation is quite light:  a new kind of value `Val_lazy` is used in place of `Val_reg` for local identifiers bound with a `lazy let`; the bound expression are type-checked by inserting a `lazy` on top of them; when a value identifier `x` refers to a lazy value, it is type-checked again as `Lazy.force x`, with an updated environment where `x` has kind `Val_reg`.  Consequently, the resulting Typedtree is the same as would be obtained by the manual expansion (explicit `lazy` and `Lazy.force`, no `Val_reg` in Texp_ident nodes), and the code generator is untouched.\n"},"comment":{"url":"https://api.github.com/repos/ocaml/ocaml/issues/comments/261820742","html_url":"https://github.com/ocaml/ocaml/pull/185#issuecomment-261820742","issue_url":"https://api.github.com/repos/ocaml/ocaml/issues/185","id":261820742,"user":{"login":"cakeplus","id":2566940,"avatar_url":"https://avatars.githubusercontent.com/u/2566940?v=3","gravatar_id":"","url":"https://api.github.com/users/cakeplus","html_url":"https://github.com/cakeplus","followers_url":"https://api.github.com/users/cakeplus/followers","following_url":"https://api.github.com/users/cakeplus/following{/other_user}","gists_url":"https://api.github.com/users/cakeplus/gists{/gist_id}","starred_url":"https://api.github.com/users/cakeplus/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cakeplus/subscriptions","organizations_url":"https://api.github.com/users/cakeplus/orgs","repos_url":"https://api.github.com/users/cakeplus/repos","events_url":"https://api.github.com/users/cakeplus/events{/privacy}","received_events_url":"https://api.github.com/users/cakeplus/received_events","type":"User","site_admin":false},"created_at":"2016-11-21T01:05:46Z","updated_at":"2016-11-21T01:05:46Z","body":"I have reviewed this PR as an exercise in understanding the typechecker, and the implementation seems solid, although it was non-trivial to verify. I couldn't invent a situation where it would fail.\r\n\r\nHowever, I have mixed feeling about the proposed language change. For once, it breaks an important property of OCaml -- that computation in syntactically explicit, in a context-independent way. Previously, looking at a lone identifier inside an expression, I could be sure that it's merely a reference that doesn't incur any computation. But with this change, things become mixed up. I could imagine myself being confused in a situation like this:\r\n\r\n``` ocaml\r\nlazy let a = (* costly thunk *) in\r\n\r\n(* lots of code *)\r\n\r\na (* suddenly, it forces a huge thunk *)\r\n```\r\n\r\nAlso, doesn't it break compatibility slightly? As of 4.04, the example above _is correct OCaml_.\r\n\r\nI also believe that the `!!` operator mentioned above is a good solution to the \"heaviness\" issue. Notably, it doesn't break the \"computational transparency\" property of OCaml. Could adding more hacks to the ridiculously complex typechecker be justified for the sake of this very minor feature, the effect of which can be easily mimicked by means of existing language?"}}
{"actor":{"display_login":"cakeplus"}}