0

I'm trying to understand why the first main does not terminate when c is not valid, while the second terminates. From the description here main is just an unevaluated thunk, and executing it is just building up the data structure. I'm trying to apply the same principle here and see why the first main does not terminate. If someone can help me understand this part, or give me pointers to understanding this would be great. Apart from this, why is GHCI not able to recognize this as TCO ? does is not fit the definition?

main = loop                                                                     
  where                                                                         
   loop =  do                                                                   
     c <- getChar                                                               
     case valid c of                                                            
       Nothing -> return ()                                                     
       Just b  -> print b                                                       
     print c                                                                    
     loop                                                                       

> main :: IO ()
> main = loop
>   where
>   loop =  do
>     c <- getChar
>     case validate c of
>       Nothing -> return ()
>       Just b  -> do
>         print b
>         loop

Thanks.

Community
  • 1
  • 1
user3169543
  • 1,499
  • 1
  • 10
  • 16
  • 1
    You realise that [`return`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Control-Monad-Instances.html#v:return) is just a library function, and works quite differently from the `return` keyword in procedural languages? – leftaroundabout Sep 10 '16 at 13:27
  • @leftaroundabout : realized that "something" about this is not correct, as I was hitting "POST", then saw this comment immediately. Thanks. – user3169543 Sep 10 '16 at 13:31
  • there is no way to 'close' a question other than accepting an answer? if so, I need to wait for sometime before I can accept an answer. Will read the stackoverflow documentation. For now, to accept I've to wait 7 more minutes :-) . – user3169543 Sep 10 '16 at 13:33
  • @user3169543 There is no rush to accept an answer. Upvote answers that you find useful and come back, say tomorrow, and accept the one you deem best. Accepting early means that you are less likely to receive very good answers since answerers may lose interest in the question, and often the first answer may not be correct (or as correct) or complete (or as complete) as following answers. – Bakuriu Sep 10 '16 at 13:37

1 Answers1

5

Tail-call optimization has nothing to do with this behaviour. The problem is simply that the first code contains an infinite loop while the second doesn't.

Your first code is similar to the imperative (python-like):

def loop():
    c = getChar()
    if valid c:
        do_something()
    else:
        do_something_else()

    print(c)
    loop()

While the latter is similar to:

def loop():
    c = getChar()
    if valid c:
        do_something()
    else:
        do_something_else()
        print(c)
        loop()

Note how in the latter case the call to loop() is inside the branch else while in the former it's outside and thus is called at every loop invocation.

Also note that return in Haskell does not terminate the function calls. It's just an IO action that has a certain value and no side-effects.

For example:

main = do
    c <- return 1
    print c

In the above code the return does not prevent the output from print.

Bakuriu
  • 98,325
  • 22
  • 197
  • 231