today I read a lot about Haskell but this formating is driving me crazy. I want to understand my basic errors as soon as possible so I can start coding normally. The function here should return a string that starts with the next "math Sign" example string (2sdwds+asd)+3
should return +asd)+3
. Here is the code
getToNextSign :: String -> String
getToNextSign str = do
let mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
let a = head str
if a `elem` mathSigns
then str
else if tail str /= []
then getToNextSign $ tail str
else []
main = do
putStrLn $ getToNextSign "(2sdwds+asd)+3"
It gives me " parse error on input = ". I am also not sure about how exactly to call it in the main and do I really need the putStrLn function. I don't think I need it but I tried like 2874 different ways to write this and now I just gave up and need help.
Besides the improvement to formatting that Stephen Diehl provided, there are other improvements you can make. As Carl points out, you can replace the if-else if-else with guards, like so:
getToNextSign :: String -> String
getToNextSign str
| a `elem` mathSigns = str
| tail str /= [] = getToNextSign $ tail str
| otherwise = []
where
a = head str
mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
When you're at it, you can also replace the head/tail with pattern matching, as in
getToNextSign :: String -> String
getToNextSign (c:cs)
| c `elem` mathSigns = c:cs
| not (null cs) = getToNextSign cs
| otherwise = []
where
mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
and if you're gonna do pattern matching, you can just as well take it all the way.
getToNextSign :: String -> String
getToNextSign str = case str of
c:_ | c `elem` mathSigns -> str
c:[] -> []
_:cs -> getToNextSign cs
where mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
and when you do it like this, you realise that you haven't really handled the case when getToNextSign
gets an empty list as an argument, which is perhaps something you want to do.
Here is a simpler alternative to your problem using the Prelude list functions, dropWhile
and elem
, which has a type sig (a -> Bool) -> [a] -> [a]
. It takes a function which will drop the elements from a list as long as the condition provided by the function is true.
Hence, your function can be rewritten as follows.
let getNextSign x = dropWhile ( not . `elem` "+-*/^)" ) x
Try to avoid explicit recursion when possible and put them higher order functions to good use. And the Prelude has tons of list manipulation functions which come in handy all the time.
Haskell, being whitespace sensitive, has to have the body of the function indented beyond the toplevel. An direct fix for your original code would be:
getToNextSign :: String -> String
getToNextSign str = do
let mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
let a = head str
if a `elem` mathSigns
then str
else if tail str /= []
then getToNextSign $ tail str
else []
main = do
putStrLn $ getToNextSign "(2sdwds+asd)+3"
As pointed out in the comments you don't need do notation here since you aren't using a monad. The let statements can be instead be written as where statements.
getToNextSign :: String -> String
getToNextSign str =
if a `elem` mathSigns
then str
else if tail str /= []
then getToNextSign $ tail str
else []
where
a = head str
mathSigns = ['+' , '-' , '*' , '/' , '^' , ')']
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.