4

I am trying to add a string to the end of a string in Haskell.

    albumStr = ""
main = do
 let albumStr = albumStr ++ "nothing"
 print albumStr

Whenever i run this it just gets stuck on " in the console and i have to terminate it.

Why? and how do i add a string to another string in this way?

Edit: How do i add multiple strings to the end of a current string without overwritting it.

Thanks

1
  • 1
    Remember that all data in Haskell is immutable—you cannot change a variable. When you write let str = str ++ "nothing", Haskell reads that as "Construct a new value called str, which has the property that str = str ++ "nothing"," in other words a never-ending recursive computation. Commented Apr 15, 2019 at 12:19

3 Answers 3

9

Unlike ML, Haskell does not have a rec keyword to mark recursive definitions. Instead all definitions can be recursive, meaning that in every variable definition, the defined variable is already in scope during its definition.

So in let albumStr = albumStr ++ "nothing", the albumStr on the right of the = refers to the one defined on the left of the = - not the one defined in line 1. Therefore the definition is infinitely recursive and loops forever.

If you want to define a variable based on another one, you have to give it a different name:

let localAlbumStr = albumStr ++ "nothing"
Sign up to request clarification or add additional context in comments.

1 Comment

you "have to" only if it's a let-binding. but not if it's a do-binding.
6

The equation

albumStr = albumStr ++ "nothing"

defines a string recursively, and does not use the globally defined albumStr at all. The recursion hangs immediately (it similar to an infinite loop).

Turning on warnings reports the shadowing of the global name.

If you do not want a recursive definition, use another variable name:

albumStr2 = albumStr ++ "nothing"

3 Comments

The problem is im trying to add a bunch of strings to the end of that string , so if i dont use recursion it will just overwrite everytime. Im very new to Haskell
@radrow Agreed, even if I'd rather have a let nonrec -- the non-recursive / shadowing definition let x = f x in ... is not that common (at least in Haskell). This is a very minor point, though.
@Deano Build a list of all the strings you want to append and then return albumStr ++ concat listOfStrings. Remember that you can't modify the global value of albumStr (probably you don't even need that), but only create a new string.
3

In do notation, you can write

do { albumStr <- pure (albumStr ++ "nothing") 
   ; ... 
   } 

and it would (seem to) work.

While let (and function) bindings in Haskell are recursive, do bindings are not.

Instead, a shadowing variable is automatically created, which is actually a new variable with the same name. The code to the right of <- lies in the scope above the binding; the code to the left of <- is in a new, wider scope (that includes the earlier one).

See also:

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.