简体   繁体   中英

Haskell syntax, parse errors for dummies

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM