{"action":"created","issue":{"url":"https://api.github.com/repos/elm-lang/elm-compiler/issues/789","labels_url":"https://api.github.com/repos/elm-lang/elm-compiler/issues/789/labels{/name}","comments_url":"https://api.github.com/repos/elm-lang/elm-compiler/issues/789/comments","events_url":"https://api.github.com/repos/elm-lang/elm-compiler/issues/789/events","html_url":"https://github.com/elm-lang/elm-compiler/issues/789","id":42897534,"number":789,"title":"Optimize self tailcalls","user":{"login":"pchiusano","id":11074,"avatar_url":"https://avatars.githubusercontent.com/u/11074?v=3","gravatar_id":"","url":"https://api.github.com/users/pchiusano","html_url":"https://github.com/pchiusano","followers_url":"https://api.github.com/users/pchiusano/followers","following_url":"https://api.github.com/users/pchiusano/following{/other_user}","gists_url":"https://api.github.com/users/pchiusano/gists{/gist_id}","starred_url":"https://api.github.com/users/pchiusano/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pchiusano/subscriptions","organizations_url":"https://api.github.com/users/pchiusano/orgs","repos_url":"https://api.github.com/users/pchiusano/repos","events_url":"https://api.github.com/users/pchiusano/events{/privacy}","received_events_url":"https://api.github.com/users/pchiusano/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2014-09-16T15:45:16Z","updated_at":"2015-01-24T17:48:03Z","closed_at":null,"body":"Feature request, per [this thread](https://groups.google.com/forum/#!searchin/elm-discuss/loops/elm-discuss/uyO0IPQYQXw/IpEUHi0WqBwJ), this example explodes:\r\n\r\n~~~ Haskell\r\ngo acc n = \r\n  if n == 0 \r\n  then acc\r\n  else go (acc+1) (n-1)\r\n  \r\nmain = plainText (show (go 0 100000))\r\n~~~\r\n\r\nNot having a way of writing loops in pure Elm is a huge limitation. Anyone who writes a nontrivial application in Elm will hit this issue sooner or later!"},"comment":{"url":"https://api.github.com/repos/elm-lang/elm-compiler/issues/comments/71329098","html_url":"https://github.com/elm-lang/elm-compiler/issues/789#issuecomment-71329098","issue_url":"https://api.github.com/repos/elm-lang/elm-compiler/issues/789","id":71329098,"user":{"login":"TheSeamau5","id":3227869,"avatar_url":"https://avatars.githubusercontent.com/u/3227869?v=3","gravatar_id":"","url":"https://api.github.com/users/TheSeamau5","html_url":"https://github.com/TheSeamau5","followers_url":"https://api.github.com/users/TheSeamau5/followers","following_url":"https://api.github.com/users/TheSeamau5/following{/other_user}","gists_url":"https://api.github.com/users/TheSeamau5/gists{/gist_id}","starred_url":"https://api.github.com/users/TheSeamau5/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/TheSeamau5/subscriptions","organizations_url":"https://api.github.com/users/TheSeamau5/orgs","repos_url":"https://api.github.com/users/TheSeamau5/repos","events_url":"https://api.github.com/users/TheSeamau5/events{/privacy}","received_events_url":"https://api.github.com/users/TheSeamau5/received_events","type":"User","site_admin":false},"created_at":"2015-01-24T17:48:03Z","updated_at":"2015-01-24T17:48:03Z","body":"Well, you can use this construct I just came up with by using trampolines:\r\n\r\n```elm\r\nimport Trampoline (..)\r\n\r\n{-| The loop function. \r\n    It takes an initial state for the variables in the loop, \r\n    a stopping condition,  and a function that updates the state \r\n    of the variables in the loop. It outputs the final state \r\n    of those variables. \r\n-}\r\nloop : a -> (a -> Bool) -> (a -> a) -> a\r\nloop start condition update = \r\n  trampoline <|\r\n    loop' start condition update\r\n    \r\n{-| This is how the loop function is actually implemented. \r\n    This trampoline business makes the loops bounded in space.\r\n    So, no more exploding of the call stack or memory.\r\n-}\r\nloop' : a -> (a -> Bool) -> (a -> a) -> Trampoline a\r\nloop' start condition update = \r\n  case condition start of \r\n    True -> Done start\r\n    False ->\r\n      Continue (\\() -> \r\n        loop' (update start) condition update\r\n      )\r\n      \r\n{-| This is how you'd write your go function given the above construct -}\r\ngo acc n = \r\n  .acc <|\r\n    loop {acc = acc, n = n} (\\{n} -> n == 0) (\\{acc, n} -> {acc = acc + 1, n = n - 1})\r\n\r\n```\r\n\r\nTo break down the `go` function: \r\n\r\n```elm\r\ngo acc n = \r\n  .acc <|\r\n    loop {acc = acc, n = n} (\\{n} -> n == 0) (\\{acc, n} -> {acc = acc + 1, n = n - 1})\r\n\r\n-- The .acc part is because in your go function you just want to return the acc\r\n\r\n {acc = acc, n = n} -- is the initial state of the variable. \r\n-- I just save the whole thing as a record.\r\n-- It makes it easy to bundle a whole bunch of variables\r\n\r\n\r\n(\\{n} -> n == 0) --  is the stopping condition\r\n-- since the state is passed in as a record, we just pick out n and check if it is\r\n-- equal to 0\r\n-- Alternatively, this could be written as:\r\n(\\variables -> variables.n == 0)\r\n\r\n\r\n(\\{acc, n} -> {acc = acc + 1, n = n - 1}) --is how to update the variables\r\n-- This is analogous to doing x++ and x-- and stuff in the imperative world\r\n\r\n```\r\n\r\nAlternatively, we could further modify the loop function to not have to write `.acc` before as follows:\r\n\r\n```\r\nloop : a -> (a -> Bool) -> (a -> a) -> (a -> b) -> b\r\nloop start condition update return = \r\n  trampoline <|\r\n    loop' start condition update return\r\n    \r\n    \r\nloop' : a -> (a -> Bool) -> (a -> a) -> (a -> b) -> Trampoline b\r\nloop' start condition update return = \r\n  case condition start of \r\n    True -> Done (return start)\r\n    False ->\r\n      Continue (\\() -> \r\n        loop' (update start) condition update return\r\n      )\r\n      \r\n\r\ngo acc n = \r\n  loop {acc = acc, n = n}  -- Initial state of variables\r\n       (\\{n} -> n == 0) -- stopping condition\r\n       (\\{acc, n} -> {acc = acc + 1, n = n - 1}) -- update variables\r\n       .acc -- return function\r\n```\r\n\r\nNow, you can safely write:\r\n\r\n```elm\r\nmain = asText (go 0 100000) \r\n```\r\nand all will be well"}}