Infix to Postfix form in Haskell - list

I'm a beginner in Haskell and i'm kind of lost on what to use to make this program work. What i have to do is get a String like this: "a+(b/c)" <with letters, not numbers> and turn it into its postfix form, which would be like this: "abc/+".
The question also says that i can't use the following words: "words, putStr, putStrLn, readLn, print"
First thing i managed to separate the letters from the symbols, and get them together afterwards:
isLetter :: String -> String
isLetter [] = []
isLetter (a:as) | a `elem` "abcdefghijklmnopqrstuvwxyz" = a : isLetter as
| otherwise = isLetter as
isOperator :: String -> String
isOperator [] = []
isOperator (a:as) | a `elem` "+-*/^" = a : isOperator as
| otherwise = isOperator as
onp :: String -> String
onp [] = []
onp str = isLetter str ++ isOperator str
The problem is that it just puts the operators after the letters, not minding the order that it should actually follow.
So i did a little research on how to transform it and i thought that i should first check which is an operator and which is a letter and, based on the rules of transforming infix to postfix, i would be putting them together in another string. So i created two functions that would tell whether it's a letter or an operator.
It's a mess, but it is like this:
isLetHelp :: Char -> Bool
isLetHelp ch | ch `elem` "abcdefghijklmnopqrstuvwxyz" = True
| otherwise = False
isOpHelp :: Char -> Bool
isOpHelp a | a `elem` "()+-*/^" = True
| otherwise = False
isOperator :: String -> String
isOperator [] = []
isOperator (a:as) | a `elem` "+-*/^" = a : isOperator as
| otherwise = isOperator as
getSymbol :: String -> String
getSymbol [] = []
getSymbol (a:as) | isOpHelp == True = isOperator
| isLetHelp == True = a : getSymbol as
This last function 'getSymbol' would be responsible to get the symbols and organize them the right way, but i have no clue how to do it.

It’s not clear from your example a+(b/c), but I assume you need to account for operator precedence, so that a+b/c parses as a+(b/c) (not (a+b)/c), and thus also evaluates to abc/+ (not ab+c/).
There are perhaps simpler or more idiomatic ways of going about this, but as an educational task this is a good way to learn about working with just basic recursive functions. There are two main ways to solve this task this way:
Recursive descent parsing
The shunting yard algorithm, which is specifically for converting infix to postfix
The former is more flexible and ultimately the basis of what an idiomatic Haskell solution would look like (using parser combinators), but the shunting yard algorithm has the distinct advantage here of being a simpler algorithm specifically for this task of infix/postfix conversion.
What I’ll do is sketch out and describe the structure of the implementation, to help you get unstuck on the general method, and give you the task of filling in the details.
The algorithm maintains two pieces of state, a stack of operators, and a queue of output. We can represent both as a list of characters:
type ShuntingYardState = ([Char], [Char])
To push an element to the stack or enqueue an element in the output, you’ll cons : it onto the front of the list; to pop an element from the stack, you can use pattern matching. The output queue is strictly an accumulator for results; we never dequeue from it.
To convert an infix expression string to postfix, you start this algorithm with the initial state of an empty operator stack and empty output queue:
expression :: String -> String
expression input = shuntingYard ([], []) input
The algorithm itself has five main cases and one error case for you to handle:
shuntingYard
:: ShuntingYardState
-> String
-> String
shuntingYard
state#(operatorStack, outputQueue)
(current : rest)
-- 1. A variable term: push it to the output and proceed.
| isVariable current
= shuntingYard (variable current state) rest
-- 2. An operator: process operator precedence and proceed.
| isOperator current
= shuntingYard (operator current state) rest
-- 3. A left parenthesis: push it onto the operator stack.
| current == '('
= shuntingYard (leftParenthesis state) rest
-- 4. A right parenthesis: process grouping and proceed.
| current == ')'
= shuntingYard (rightParenthesis state) rest
-- 5. An unrecognized token: raise an error.
| otherwise
= error $ "unrecognized input: " ++ show rest
-- 6. No more input: finalize the result.
shuntingYard state []
= endOfInput state
You need to fill in the definitions of the functions implementing each case above, marked in bold. Here are their signatures and a description of their function.
Identifies a variable token, like your isLetHelp:
isVariable :: Char -> Bool
Identifies an operator token (not a parenthesis), like your isOpHelp:
isOperator :: Char -> Bool
Pushes a variable to the output queue:
variable :: Char -> ShuntingYardState -> ShuntingYardState
Processes an operator. This function has two cases, sketched below. In the first case, it moves operators from the operator stack to the output queue as long as they have either greater precedence than the current token (for right-associative operators like ^), or greater or equal precedence (for left-associative operators like * and -). In the second case, it simply pushes the current operator token to the operator stack.
operator :: Char -> ShuntingYardState -> ShuntingYardState
operator current (op : operatorStack, outputQueue)
| op /= '('
, … -- Compare precedence & associativity.
= operator … -- Repeat.
operator current (operatorStack, outputQueue)
= … -- Push the operator and return.
Processes a left parenthesis by pushing it to the operator stack.
leftParenthesis :: ShuntingYardState -> ShuntingYardState
Processing a right parenthesis likewise has two cases: as long as there are operators remaining, move them to the output; if there are none, then expect a matching left parenthesis, or else raise an error.
rightParenthesis :: ShuntingYardState -> ShuntingYardState
rightParenthesis (op : operatorStack, outputQueue)
| op /= '('
= rightParenthesis … -- Move operator to output.
| otherwise
= … -- Reached matching left parenthesis; return.
rightParenthesis ([], outputQueue)
= … -- Mismatched right parenthesis; error.
Finally, when reaching the end of input, there are three cases. If the operator stack is empty, you can convert the queue to the final output string. Otherwise, if there are operators remaining, move them one by one to the output; if any parentheses remain, they’re missing matching right parentheses, so this is an error.
endOfInput
:: ShuntingYardState
-> String
endOfInput ([], outputQueue)
= … -- Success! Return the final result.
endOfInput (op : operatorStack, outputQueue)
| op == '('
= … -- Mismatched left parenthesis; error.
| otherwise
= … -- Operator remaining; move to output and repeat.

Related

Process a string using foldr where '#' means deleting the previous character

I need to process a string using foldr where '#' means deleting the previous character. For example:
>backspace "abc#d##c"
"ac"
>backspace "#####"
""
It needs to be done using foldr through one pass of the list, without using reverse and/or (++).
Here what I have got so far:
backspace :: String -> String
backspace xs = foldr func [] xs where
func c cs | c /= '#' = c:cs
| otherwise = cs
But it just filter the '#' from the string. I thought about deleting the last element of current answer every time c == '#' and got something like that
backspace :: String -> String
backspace xs = foldr func [] xs where
func c cs | c /= '#' = c:cs
| cs /= [] = init cs
| otherwise = cs
but it is not working properly,
ghci> backspace "abc#d##c"
"abc"
You can use (Int, String) as state for your foldr where the first Int is the number of backspaces, and the String is the current string constructed.
This thus means that you can work with:
backspace :: String -> String
backspace = snd . foldr func (0, [])
where func '#' (n, cs) = (n+1, cs)
func c (n, cs)
| n > 0 = … -- (1)
| otherwise = … -- (2)
In case we have a character that is not a #, but n > 0 it means we need to remove that character, and thus ignore c and decrement n. In case n == 0 we can add c to the String.
I leave filling in the … parts as an exercise.

How to re-arrange a list based on a set of steps?

I'm trying to re-arrange a list based on these steps:
First move every operator (+,-,*) 1 index to the left by switching it with the element to the left.
Then find any '+' or '-' two indexes ahead of a *, and move the '+' or '-' to the index before the *.
Example
["a","-","2","*","b","+","c"]
["-","a","*","2","+","b","c"]
["-","a","+","*","2","b","c"]
I have an imperative programming background, so my initial idea was to have an iterator as an argument, and keep track of the position in the index like that, but I could not get it to work. My second idea was to embrace Haskell and use list comprehension with generators, but I struggled there as well. Any ideas or solutions are appreciated!
You can make use of explicit recursion. You can for example move elements one position to the left with:
isOperator :: String -> Bool
isOperator "+" = True
isOperator "-" = True
isOperator "*" = True
isOperator _ = False
stepOne :: [String] -> [String]
stepOne (x:xs#(o:xs'))
| isOperator o = o : x : stepOne xs'
| otherwise = x : stepOne xs
stepOne xa#[_] = xa
stepOne [] = []
Here the (x:xs#(o:xs')) pattern matches with lists with two or more elements. THe first element is x, the second is o, the remaining elements is stored in the xs' variable. xs is the tail of the "outer" cons. We check if o is an operator, if that is the case we swap with x and recurse on the tail xs'. If o is not an operator, we recurse on the tail xs'.
For the given sample data, we get:
Prelude> stepOne ["a","-","2","*","b","+","c"]
["-","a","*","2","+","b","c"]
I leave step two as an exercise.
That being said, one of the success stories of Haskell is probably parsing. Several libraries and tools exist like parsec [Hackage] and attoparsec [Hackage]. happy [haskell.org] is a compiler compiler that can construct a parser in Haskell based on a grammer. You thus do not per se need to perform infix-to-prefix conversion, but let tools do the work for you.

badarg to '++'operator - How to come around?

** Reason for termination =
** {badarg,[{erlang,'++',[<<>>,"</after></set></query></iq>"]},
{geoloc,get_nearby,1},
And the method was:
get_nearby({_Pid, DynVars})->
%Last = ts_dynvars:lookup(last, DynVars),
Last = lists:keysearch(last,1,DynVars),
{ok, Rad} = ts_dynvars:lookup(rad,DynVars),
{ok, Lat} = ts_dynvars:lookup(lat,DynVars),
{ok, Lon} = ts_dynvars:lookup(lon,DynVars),
if is_tuple(Last) ->
{value,{Key,After}} = Last,
if length(After) == 0 ->
After2 = "0";
true ->
After2 = After
end,
"<iq id=\"" ++ common:get_random_string(5,"abcdefghijklmnopqrstuvwxyz0123456789-+=") ++ "\" xmlns=\"http://xmpp.xgate.com.hk/plugins\" to=\"xmpp.xgate.hk.com\" type=\"get\"><query xmlns=\"jabber:iq:geoloc\"><geoloc><lat>" ++ Lat ++ "</lat><lon>" ++ Lon ++ "</lon><radius>" ++ Rad ++ "</radius></geoloc><set xmlns=\"http://jabber.org/protocol/rsm\"><max>" ++ integer_to_list(ran_max()) ++ "</max><after>" ++ After2 ++ "</after></set></query></iq>";
true -> % Last is boolean, namely the 'false' atom
ts_dynvars:set([rad, lat, lon], [Rad, Lat, Lon], DynVars),
"<iq id=\"" ++ common:get_random_string(5,"abcdefghijklmnopqrstuvwxyz0123456789-+=") ++ "\" xmlns=\"http://xmpp.xgate.com.hk/plugins\" to=\"xmpp.xgate.hk.com\" type=\"get\"><query xmlns=\"jabber:iq:geoloc\"><geoloc><lat>" ++ Lat ++ "</lat><lon>" ++ Lon ++ "</lon><radius>" ++ Rad ++ "</radius></geoloc><set xmlns=\"http://jabber.org/protocol/rsm\"><max>" ++ integer_to_list(ran_max()) ++ "</max></set></query></iq>"
end.
You are trying to concatenate a binary (<<>>) and a string, but ++ can only concatenate two strings (or lists - Erlang strings are actually lists).
That means that After2 is a binary, and consequently it received this value in the second clause of the if expression. Normally calling length(After) when After is not a list would cause a badarg exception, but as it appears in an if test it is treated as a guard test and exceptions are ignored, and therefore length(After) == 0 is treated as false. So the corresponding value was a binary already when you got it in DynVars.
A few suggestions:
To check whether a list is empty, it is somewhat wasteful to call length on it, as length needs to go through the entire list. Instead, write something like:
case After of
"" ->
After2 = "0";
[_|_] ->
After2 = After
end
[_|_] is a pattern that matches non-empty lists. In your case, the value of After would not match any of the clauses, and you'd have a case_clause error that tells you what value you actually got.
Of course, if you actually expect a binary here, check for <<>> and <<_/binary>> instead.
You're doing quite a few concatenations (++) there. In the expression A ++ B, the ++ operator needs to walk along the entire list in A, and thus the run time is proportional to the length of A.
There are two common alternatives to concatenation. First, often the function that will consume the result doesn't actually need a flat list, but would be equally happy with a "deep list" or "iolist" - instead of "foo" ++ "bar", write ["foo", "bar"]. Notably, if you're going to write the result to a file or send it to a socket, both file:write and gen_tcp:send accept both variants.
Second, you could use binaries instead of strings. Binaries are different from strings in many interesting ways (not the least how they behave with respect to garbage collection), but they do have the nice property that they can be concatenated efficiently. If A and B are binaries, and you write C = <<A/binary, B/binary>>, and the compiler can see that you only use C but not A after that, B will simply be concatenated to the memory area that held A. See the chapter on binary handling in the Efficiency Guide for more details.
The two lines starting with "<iq id=\"" are nearly identical, except that the first one inserts "<after>" ++ After2 ++ "</after>" in the middle. You could have the first case clause set MaybeAfter = "<after>" ++ After2 ++ "</after>" and the second case clause set MaybeAfter = "", and then have one single line that inserts the value of MaybeAfter in the right place. That would help making the code more readable.

OCaml function parameter pattern matching for strings

I tried to pass a string in to get a reversed string. Why can't I do this:
let rec reverse x =
match x with
| "" -> ""
| e ^ s -> (reverse s) ^ e;;
The compiler says it's a syntax error. Can't I use ^ to destructure parameters?
The reason for this is that strings are not represented as a datatype in the same way as lists are. Therefore, while cons (::) is a constructor, ^ is not. Instead, strings are represented as a lower level type without a recursive definition (as lists are). There is a way to match strings as a list of characters, using a function from SML (which you can write in OCaml) called explode and implode which -- respectively -- take a string to a char list and vice versa. Here's an example implementation of them.
As Kristopher Micinski explained, you can't decompose strings using pattern matching as you do with lists.
But you can convert them to lists, using explode. Here's your reverse function with pattern matching using explode and its counterpart implode:
let rec reverse str =
match explode str with
[] -> ""
| h::t -> reverse (implode t) ^ string_of_char h
Use it like this:
let () =
let text = "Stack Overflow ♥ OCaml" in
Printf.printf "Regular: %s\n" text;
Printf.printf "Reversed: %s\n" (reverse text)
Which shows that it works for single-byte characters but not for multi-byte ones.
And here are explode and implode along with a helper method:
let string_of_char c = String.make 1 c
(* Converts a string to a list of chars *)
let explode str =
let rec explode_inner cur_index chars =
if cur_index < String.length str then
let new_char = str.[cur_index] in
explode_inner (cur_index + 1) (chars # [new_char])
else chars in
explode_inner 0 []
(* Converts a list of chars to a string *)
let rec implode chars =
match chars with
[] -> ""
| h::t -> string_of_char h ^ (implode t)
When you write a pattern matching expression, you cannot use arbitrary functions in your patterns. You can only use constructors, which look like unevaluated functions. For example, the function "+" is defined on integers. So the expression 1+2 is evaluated and gives 3; the function "+" is evaluated, so you cannot match on x+y. Here is an attempt to define a function on natural numbers that checks whether the number is zero:
let f x = match x with
| 0 -> false
| a+1 -> true
;;
This cannot work! For the same reason, your example with strings cannot work. The function "^" is evaluated on strings, it is not a constructor.
The matching on x+1 would work only if numbers were unevaluated symbolic expressions made out of the unevaluated operator + and a symbolic constant 1. This is not the case in OCAML. Integers are implemented directly through machine numbers.
When you match a variant type, you match on constructors, which are unevaluated expressions. For example:
# let f x = match x with
| Some x -> x+1
| None -> 0
;;
val f : int option -> int = <fun>
This works because the 'a option type is made out of a symbolic expression, such as Some x. Here, Some is not a function that is evaluated and gives some other value, but rather a "constructor", which you can think of as a function that is never evaluated. The expression Some 3 is not evaluated any further; it remains as it is. It is only on such functions that you can pattern-match.
Lists are also symbolic, unevaluated expressions built out of constructors; the constructor is ::. The result of x :: y :: [] is an unevaluated expression, which is represented by the list [x;y] only for cosmetic convenience. For this reason, you can pattern-match on lists.

Standard definition of list

I have a problem with definition of list. Normally is list defined as data [a] = [] | a : [a]
but if I write something like this on my code concrete I will to define data T a = N | a -> (T a) the interpreter give me an error:
Malformed head of type or class declaration
Do you know what's wrong?
.
It looks like your problem is that you tried to use -> as an infix constructor like : (In order to build a list using a -> b -> N syntax). This isn't allowed because custom infix constructors in Haskell must begin with the : character.
The reason for your strange error message is because -> in Haskell is reserved for function types, as Jeff's answer explains
Try this instead:
-- Create a right-associative infix constructor.
data T a = N | a :-> (T a)
infixr :->
mylist :: T Int
mylist = 10 :-> 17 :-> N
--If we hadn't made the operator right associative,
-- we would need to use explicit parenthesis here
myotherlist :: T Int
myotherlist = 10 :-> (17 :-> N)
-- Example function
isempty :: T a -> Bool
isempty N = True
isempty (_ :-> _) = False
a -> T a would mean that a is a function that returns something of T a so I think that's the bit that's wrong. Try something like this.
data T a = N | R a (T a)
N is the empty list (equivalent of []) value and R is the value constructor (equivalent to :)
On the right hand side you need some way of carrying the a value around. You can now right lists like.
> N -- The empty List
> R 5 N -- a list with a single element and then the end
> R 7 (R 6 (R 5 N)) -- the list 7, 6, 5