Reputation: 390
I'm trying to write a helper function that takes in a string and if the string has multiple spaces it turns it into just one string. Here is the code:
getSpaces :: String -> String
getSpaces index =
if (length index) == 1 then index
else
if isInfixOf " " index then index = " "
else index
When I try to load my module into GHCI I get the error:
Prelude> :l Utilities
[1 of 1] Compiling Utilities ( Utilities.hs, interpreted )
Utilities.hs:55:42: error:
parse error on input ‘=’
Perhaps you need a 'let' in a 'do' block?
e.g. 'let x = 5' instead of 'x = 5'
|
55 | if isInfixOf " " index then index = " "
| ^
Failed, no modules loaded.
Why am I not able to reassign index to a single space?
Upvotes: 0
Views: 804
Reputation: 477641
Why am I not able to reassign index to a single space?
Because in Haskell you are unable to reassign anything. In fact you never even assign, you declare (that is something related, but different). Even in some cases where it might perhaps look like you reassign variables (like in do
blocks, you do not reassign, but you shadow variables by declaring a new one with the same name, again this is a bit related, but there are a lot of cases where we see different behavior, for example in a loop, we can not shadow the variable every iteration).
To answer your question, you probably want to return a string with one space, we can do that by writing:
getSpaces index = if (length index) == 1 then index else
if isInfixOf " " index then " " else index
But nevertheless this is still rather inelegant, as well as it is rather unsafe since in case of an infinite String
, this will start looping: the length
keeps looping until the list (of characters) is exhausted, and it is possible that this never happens. Furthermore even if it does not get stuck in an infinite loop, then still it is not advisable, since it runs in O(n) (with n the length of the list). So for long lists, this is inefficient.
Usually in Haskell, one uses a combination of patterns and guards to distinct between possible values. Your case can be mapped to:
getSpaces :: String -> String
getSpaces st@[_] = st
getSpaces st | isInfixOf " " st = st
| otherwise = " "
This will still loop however, in case the list has infinite size, sinze isInfixOf
keeps looking for a space, until it has found one, or the String
is exhausted.
Since isPrefixOf
with as search pattern a string with one character in fact means that we look if the string contains a space, we can replace that with elem
and look for the character ' '
:
getSpaces :: String -> String
getSpaces st@[_] = st
getSpaces st | elem ' ' st = st
| otherwise = " "
Upvotes: 8
Reputation: 390
I found a fix, instead of changing index, I am just returning a single space.
Insead of:
if isInfixOf " " index then index = " "
I did:
if isInfixOf " " index then " "
So I just return the space.
Upvotes: 1