{"action":"created","issue":{"url":"https://api.github.com/repos/gkz/LiveScript/issues/728","labels_url":"https://api.github.com/repos/gkz/LiveScript/issues/728/labels{/name}","comments_url":"https://api.github.com/repos/gkz/LiveScript/issues/728/comments","events_url":"https://api.github.com/repos/gkz/LiveScript/issues/728/events","html_url":"https://github.com/gkz/LiveScript/issues/728","id":78015296,"number":728,"title":"Feature request: limited tail call optimization.","user":{"login":"impinball","id":4483844,"avatar_url":"https://avatars.githubusercontent.com/u/4483844?v=3","gravatar_id":"","url":"https://api.github.com/users/impinball","html_url":"https://github.com/impinball","followers_url":"https://api.github.com/users/impinball/followers","following_url":"https://api.github.com/users/impinball/following{/other_user}","gists_url":"https://api.github.com/users/impinball/gists{/gist_id}","starred_url":"https://api.github.com/users/impinball/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/impinball/subscriptions","organizations_url":"https://api.github.com/users/impinball/orgs","repos_url":"https://api.github.com/users/impinball/repos","events_url":"https://api.github.com/users/impinball/events{/privacy}","received_events_url":"https://api.github.com/users/impinball/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-05-19T09:40:22Z","updated_at":"2015-05-19T15:48:56Z","closed_at":null,"body":"It's part of ES6, and work is already going into implementing it in engines (although rather slowly). Also, it would be tremendously useful for a functional language like LiveScript. Here's what I think would be good constraints to ensure it would work:\r\n\r\n1. It must be at a place where an implicit return would be, although the implicit return itself may be suppressed. Examples:\r\n\r\n    ```ls\r\n    f = ->\r\n      # Here\r\n      f\r\n\r\n    f = (x) ->\r\n      if x == 0\r\n        1\r\n      else\r\n        # Here\r\n        f x - 1\r\n\r\n    f = (x) ->\r\n      if x == 0\r\n        # Here\r\n        f x - 1\r\n      else\r\n        1\r\n\r\n    f = (x) !->\r\n      try\r\n        g x\r\n      catch\r\n        # Here\r\n        f x - 1\r\n\r\n    fact = (x, acc = 1) ->\r\n      | x <= 1 => 1\r\n      | otherwise => fact x - 1, acc * x # Here\r\n\r\n    f = (x) ->\r\n      switch 1\r\n        case x then 1\r\n        case &2 then 3\r\n        case x % 2 then 2\r\n        case x % 3 then f x / 2, 2 # here\r\n        default then x\r\n    ```\r\n\r\n2. It must be only explicit self-recursion. Here's an example:\r\n\r\n    ```ls\r\n    # Good\r\n    f = (x) ->\r\n      | x == 0 => 0\r\n      | otherwise => f x - 1\r\n\r\n    # Bad\r\n    even = (x) ->\r\n      | x == 0 => true\r\n      | otherwise => odd x - 1\r\n\r\n    odd = (x) ->\r\n      | x == 0 => false\r\n      | otherwise => even x - 1\r\n    ```\r\n\r\n3. It cannot be modified in its scope. Example:\r\n\r\n    ```ls\r\n    # Good\r\n    f = (x) ->\r\n      | x == 0 => true\r\n      | otherwise => not f x - 1\r\n\r\n    fs.readFile file, 'utf8', (err, data) ->\r\n      f = (x) -> x == data\r\n      f data\r\n\r\n    # Good (compiler error if it's modified)\r\n    const f = (x) ->\r\n      | x == 0 => true\r\n      | otherwise => not f x - 1\r\n\r\n    # Bad\r\n    f = (x) ->\r\n      | x == 0 => true\r\n      | otherwise => not f x - 1\r\n\r\n    f = (x) -> x % 0 == 1\r\n\r\n    # Bad\r\n    f = (x) ->\r\n      | x == 0 => true\r\n      | otherwise => not f x - 1\r\n\r\n    fs.readFile file, 'utf8', (err, data) ->\r\n      f := (x) -> x == data\r\n      f data\r\n    ```\r\n\r\n[Babel has implemented it in its ES6 compiler](http://babeljs.io/repl/#?experimental=false&evaluate=false&loose=false&spec=false&playground=false&code=function%20skipWhile(cond)%20%7B%0A%20%20if%20(!hasNext()%20%7C%7C%20cond(current%2C%20last))%20return%3B%0A%20%20move()%3B%0A%20%20return%20skipWhile(cond)%3B%0A%7D), so it's definitely possible."},"comment":{"url":"https://api.github.com/repos/gkz/LiveScript/issues/comments/103559778","html_url":"https://github.com/gkz/LiveScript/issues/728#issuecomment-103559778","issue_url":"https://api.github.com/repos/gkz/LiveScript/issues/728","id":103559778,"user":{"login":"heavyk","id":1226324,"avatar_url":"https://avatars.githubusercontent.com/u/1226324?v=3","gravatar_id":"","url":"https://api.github.com/users/heavyk","html_url":"https://github.com/heavyk","followers_url":"https://api.github.com/users/heavyk/followers","following_url":"https://api.github.com/users/heavyk/following{/other_user}","gists_url":"https://api.github.com/users/heavyk/gists{/gist_id}","starred_url":"https://api.github.com/users/heavyk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/heavyk/subscriptions","organizations_url":"https://api.github.com/users/heavyk/orgs","repos_url":"https://api.github.com/users/heavyk/repos","events_url":"https://api.github.com/users/heavyk/events{/privacy}","received_events_url":"https://api.github.com/users/heavyk/received_events","type":"User","site_admin":false},"created_at":"2015-05-19T15:48:56Z","updated_at":"2015-05-19T15:48:56Z","body":"like @robotlolita said, not everything is optimized... I can't remember it ever giving erroneous results...\r\n\r\nit was just something I stardted to microbenchmark, and realized I was wasting far too much time on it. I've left it in for the most part. I think it works 100% properly, but I don't have enough knowlege to give any definite answers"}}