1

I have written code like this

import System.Environment
import Control.Exception
import Data.List

f :: String -> [String] -> IO ()
f str []       =
    putStrLn "String 2"
f str (x : xs) =
    putStrLn "String 1"

main :: IO ()
main = do
    xs <- getArgs
    let str = head xs
    let xs = tail xs
    f str xs
    return ()

but when I compile it and trying to run I always have only answer <<loop>>

ghc run.hs
./run some_string some_over_arguments
run: <<loop>>

What's wrong with this code? I've tryed to hoogle <<loop>> but found nothing. If I pass to f not str xs but str [some_hardcoded_list] this code works fine, so I guess this is something wrong with xs.

5
  • So what input args are you using? This is what gets assigned to xs. Please paste the whole run command. Commented Nov 14, 2015 at 10:37
  • @KLibby for example $ ./run my_string any_argument this is exactly what I tiped Commented Nov 14, 2015 at 10:39
  • Possible duplicate of infinite loop in Haskell when binding variables Commented Nov 14, 2015 at 10:57
  • 2
    You should compile with -Wall; when you do, the compiler will warn you when these things happen. And just a by the way: instead of binding the head and then the tail you can just pattern match the _:_ constructor. It's easier to write and if you do, the compiler will also warn you about the second potential problem in your code (inexhaustive pattern match -- what if xs is []?). And besides that incomplete functions like head & tail are just bad :P Commented Nov 14, 2015 at 11:08
  • @MasterMastic thanks, I did not know that -Wall exists in haskell. Commented Nov 14, 2015 at 11:17

2 Answers 2

6

to you see the part where you declare

let xs = tail xs

this says you want xs to be a list that is the tail of itself and this causes an infinte loop (which ghc seems to notice ;)) (seen as an definition every constant list repeat c would suffice here - technically of course you just get a plain infinite-loop)

so just change it to something like

main :: IO ()
main = do
    xs <- getArgs
    let str = head xs
    let xs' = tail xs
    f str xs'
    return ()

and your code should work as expected ;)

Sign up to request clarification or add additional context in comments.

Comments

3

Others have already answered. I just want to add that enabling warnings will point out redefinitions of existing bindings. This also covers this kind of unwanted recursion:

> :set -Wall
> xs <- return [1..10::Int]
> let xs = tail xs

<interactive>:11:5: Warning:
    This binding for ‘xs’ shadows the existing binding
      defined at <interactive>:10:1

Now, one could think "but in this case I really intend to shadow the previous binding", and would be completely correct. Still, renaming the new binding incidentally avoids the problem.

One more reason to add {-# OPTIONS -Wall #-} at the top of your source file. (Or enabling warning in your .cabal file, or whatever other build system)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.