Pretty-print expression recursively - sml

infix v;
infix &;
datatype s = P | Q | S
| ~ of s
| v of s * s
| & of s * s;
I made a function (s -> unit) to print type s as string
fun printS(P) = print "P"
| printS(Q) = print "Q"
| printS(P & Q) = print "P & Q";
My Question is how can I print s recursively if I have more complex s such as
P v ~ Q & P.

You can pretty-print an expression recursively by pattern-matching the sub-trees as variables and then refer to those sub-trees. In your example, you are only matching P & Q which is exactly one tree.
fun printS P = print "P"
| printS Q = print "Q"
| printS S = print "S"
| printS (p & q) = (print or printS ...; print or printS ...; ...)
By not referring to actual P and Q, but instead variables p and q, these could be any sub-expression. Since your function returns unit, you'd want to print multiple times. Except, perhaps, some of the things you want to print are recursive datatypes, so you could use your specialized printS instead.
I would probably convert this to a string and print the string once:
fun toString P = "P"
| toString Q = "Q"
| toString S = "S"
| toString (p & q) = "(" ^ toString p ^ " & " ^ toString q ^ ")"
| toString ... = ...
and then print it:
fun printS s = print (toString s)
The real challenge comes at printing the minimal amount of parentheses:
printS ((P v Q) & (Q v P))
should preferrably not print P v Q & Q v P, since those aren't the same expressions.

Related

Preorder traversal through Morse code BST

In c++ I am working on two trees, 1 is alphabetical a-z with nums and characters 0-9 , . ?
The other tree is the equivalent of those characters in Morse code. I have to have the different trees in text files that should already be in the correct order for insert. In my normal alphabet, I worked out my balanced text file for preorder traversal looks like
P
H
D
B
A
C
F
E
G
L
J
I
K
N
M
O
2
X
T
R
Q
S
V
U
W
0
Y
Z
1
9
5
4
3
7
6
8
,
.
?
This text file prints out preorder traversal
,
.
0
1
2
3
4
5
6
7
8
9
?
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X
Y
Z
The problem I am having is with the Morse code textfile. I understand that the characters for Morse code are not the same for the normal alphabet. From lest to greatest, this is Morse code
- T
-- M
--- O
----- 0
----. 9
---.. 8
--. G
--.- Q
--.. Z
--..-- ,
--... 7
-. N
-.- K
-.-- Y
-.-. C
-.. D
-..- X
-... B
-.... 6
. E
.- A
.-- W
.--- J
.---- 1
.--. P
.-. R
.-.. L
.. I
..- U
..--- 2
..--.. ?
..-. F
... S
...- V
...-- 3
.... H
....- 4
..... 5
applying the same formula for the tree (so it has the same sequence as the alphabetical one above, my text file looks like
-.. D
--.- Q
----- 0
-- M
- T
--- O
---.. 8
----. 9
--. G
-. N
--..-- ,
--.. Z
--... 7
-.-- Y
-.- K
-.-. C
.. I
.---- 1
. E
-... B
-..- X
-.... 6
.-- W
.- A
.--- J
.-.-.- .
.--. P
.-. R
.-.. L
...-- 3
..--.. ?
..--- 2
..- U
... S
..-. F
...- V
....- 4
.... H
..... 5
But this also does not print out the tree in alphabetical order for Morse code for preorder.
This is how I am inserting into the tree
void BST::insert(BSTNode *&pTree, string morse)
{
if (pTree == NULL)
{
BSTNode *pMem = new BSTNode(morse);
pTree = pMem;
}
else if (morse < (pTree)->getMorse())
{
insert((pTree)->getLeft(), morse);
}
else if (morse > (pTree)->getMorse())
{
insert((pTree)->getRight(), morse);
}
}
And this is how I am printing out the results
void BST::print(BSTNode *&pTree, string id)
{
if (pTree != nullptr)
{
//cout << pTree->getMorse() << endl; // processed
print(pTree->getLeft(), id);
cout << pTree->getMorse() << endl; // processed
print(pTree->getRight(), id);
}
}
(the same code is for the alphabet except it uses chars and getLetter() but other than that it is identical)
If I am just approaching this incorrectly, I could use any help in the right direction.
Did you notice that your insert() method does not handle the case of "key-collision" (due to the missing else branch for the last if). This can be used to detect if a key shall be inserted which is already in tree. As it is, such duplicated inserts are simply ignored (which is IMHO not the worst possible behavior).
In my sample below, I decided for a different option: let insert() return a boolean value which reports about success of insertion.
Unfortunately, you didn't provide an MCVE.
Thus, I filled the gaps with own code where (for my personal joy) I involved templates. Hopefully, this won't bring in too much confusion.
However, after playing around with your sample data, I came to the conclusion that your code does probably the right – may be not, what you expected. Eventually, you have a false expectation. Or, you correctly solved the false problem. I re-read your question multiple times but didn't get I clear idea about this...
I used your last sample file as input (to build up the binary search tree) and let my application output preorder and inorder:
Preorder output corresponds to your last file.
Inorder output corresponds to your 3rd file.
The inorder output provides a sorted output according to the defined order of the tree – in this case the lexicographical order of Morse sequences (where - precedes . due to their respective ASCII values).
But this also does not print out the tree in alphabetical order for Morse code for preorder.
Hmmm. If you expected an alphabetical order, do you mean an order which considers the alpha-numerical characters (to which the Morse codes map)?
If so, this can hardly done by such a tree (as I cannot see how a possible order of Morse codes corresponds to a possible order of alpha-numerics). I.e. to achieve "Morse codes sorted by the associated alpha-numerics", the obvious (and IMHO only) way is to build a tree for the reverse mapping. You can easily built up another tree (e.g. from the first) where the assigned alpha-numeric values are used as key instead. (Actually, you already did first a binary search tree for alpha-numerics.)
This leaves me somehow puzzled. May be, I missed something and didn't get your actual problem...
However, below is the result of my fiddling:
// forward template declaration:
template <typename KEY, typename VALUE, typename COMP>
class BSTreeT;
/* provides a class template for a node in a binary search tree.
*
* KEY ... C++ type of the key values of nodes
* VALUE ... C++ type of the other values of nodes
*/
template <typename KEY, typename VALUE>
class BSTreeNodeT {
/* This friend shall ensure that the corresponding
* BSTreeT template class may access private _pLeft and _pRight.
*/
template <typename KEY_, typename VALUE_, typename COMP_>
friend class BSTreeT;
public:
// the key value of node (used to define an order)
const KEY key;
// other values of node
VALUE value;
private:
// pointers to left and right child nodes
BSTreeNodeT *_pLeft, *_pRight;
public:
// constructor.
BSTreeNodeT(const KEY &key, const VALUE &value):
key(key), value(value), _pLeft(nullptr), _pRight(nullptr)
{ }
// destructor.
~BSTreeNodeT() { delete _pLeft; delete _pRight; }
// disabled:
BSTreeNodeT(const BSTreeNodeT&) = delete;
BSTreeNodeT& operator=(const BSTreeNodeT&) = delete;
public:
// returns pointer to left child node (or nullptr if there is none).
const BSTreeNodeT* getLeft() const { return _pLeft; }
// returns pointer to right child node (or nullptr if there is none).
const BSTreeNodeT* getRight() const { return _pRight; }
};
/* provides a less functor which simply wraps operator < for a certain
* type
*
* VALUE ... C++ type of value to less-compare
*
* Note:
* This is actually, what std::less provides.
* I involved this functor for illustration.
*/
template <typename VALUE>
struct lessFunc {
bool operator()(const VALUE &value1, const VALUE &value2) const
{
return value1 < value2;
}
};
/* provides a class template for a binary search tree.
*
* KEY ... C++ type of the key values of nodes
* VALUE ... C++ type of the other values of nodes
* COMP ... C++ type of the less comparator
* to define an order of tree nodes
*/
template <typename KEY, typename VALUE, typename COMP = lessFunc<KEY> >
class BSTreeT {
public:
const COMP &comp;
private:
BSTreeNodeT<KEY, VALUE> *_pRoot;
public:
/* constructor.
*
* comp ... a less comparator to define order of nodes
*/
explicit BSTreeT(const COMP &comp = COMP()):
comp(comp), _pRoot(nullptr)
{ }
// destructor.
~BSTreeT() { delete _pRoot; }
// disabled:
BSTreeT(const BSTreeT&) = delete;
BSTreeT& operator=(const BSTreeT&) = delete;
public:
/* inserts a node.
*
* key ... the key value of node
* value ... the other value of node
* return: true ... key/value inserted
* false ... Error! Possible reasons:
* - duplicated key
* - allocation of node failed.
*/
bool insert(const KEY &key, const VALUE &value)
{
return insert(_pRoot, key, value);
}
/* provides a functor-like type which is applied to every node
* in traverse().
*
* If an instance of this class is provided the traverse() does nothing
* else than the pure traversal.
*/
struct Apply {
// pre-order access to node
virtual void preNode(BSTreeNodeT<KEY, VALUE> &node) { }
// in-order access to node
virtual void inNode(BSTreeNodeT<KEY, VALUE> &node) { }
// post-order access to node
virtual void postNode(BSTreeNodeT<KEY, VALUE> &node) { }
};
/* traverses the tree and applies the provided object to every node.
*
* apply ... the action object applied to every node
*/
void traverse(Apply &apply)
{
if (_pRoot) traverse(_pRoot, apply);
}
private:
// inserts a node.
bool insert(
BSTreeNodeT<KEY, VALUE> *&pTree, const KEY &key, const VALUE &value)
{ /* Every if-branch ends with return.
* Thus, no explict else is needed.
*/
if (!pTree) { /* (!pTree) ... (pTree == nullptr) */
return !!(pTree = new BSTreeNodeT<KEY, VALUE>(key, value));
}
if (comp(key, pTree->key)) return insert(pTree->_pLeft, key, value);
if (comp(pTree->key, key)) return insert(pTree->_pRight, key, value);
return false;
}
// traverses the tree.
void traverse(BSTreeNodeT<KEY, VALUE> *pTree, Apply &apply)
{
apply.preNode(*pTree);
if (pTree->_pLeft) traverse(pTree->_pLeft, apply);
apply.inNode(*pTree);
if (pTree->_pRight) traverse(pTree->_pRight, apply);
apply.postNode(*pTree);
}
};
// sample code:
#include <ctype.h>
#include <iostream>
#include <string>
using namespace std;
// template instances (for convenience)
typedef BSTreeNodeT<string, string> BSTNode;
typedef BSTreeT<string, string> BST;
/* a helper function to split a string into tow at the first occurence of
* (a sequence of) whitespaces.
*
* line ... input
* first ... returns first sub-string (might become empty)
* second ... returns second sub-string (might become empty)
*/
void split(const string &line, string &first, string &second)
{
size_t i0 = 0, n = line.length(), i;
for (i = i0; i < n && !isspace(line[i]); ++i);
first = line.substr(i0, i - i0);
for (i0 = i; i0 < n && isspace(line[i0]); ++i0);
for (i = i0; i < n && !isspace(line[i]); ++i);
second = line.substr(i0, i - i0);
}
/* a derived tree-traversal action
* for graphical (i.e. ASCII-art) output of tree
*/
struct PrintGraph: public BST::Apply {
string indent;
PrintGraph(): indent(" ") { }
virtual void preNode(BSTNode &node)
{
indent.pop_back(); char c = indent.back(); indent.pop_back();
cout << indent << "+-"
<< (node.getLeft() || node.getRight() ? '+' : '-')
<< "- ["
<< node.key << ": " << node.value
<< ']' << endl;
indent += c; indent += ' ';
indent += node.getRight() ? "| " : " ";
}
virtual void inNode(BSTNode &node)
{
indent.pop_back(); indent.pop_back();
indent += " ";
}
virtual void postNode(BSTNode &node)
{
indent.pop_back(); indent.pop_back();
}
};
/* a derived tree-traversal action
* for pre-order output of nodes
*/
struct PrintPreOrder: public BST::Apply {
virtual void preNode(BSTNode &node)
{
cout << node.key << ": " << node.value << endl;
}
};
/* a derived tree-traversal action
* for in-order output of nodes
*/
struct PrintInOrder: public BST::Apply {
virtual void inNode(BSTNode &node)
{
cout << node.key << ": " << node.value << endl;
}
};
/* a derived tree-traversal action
* to fill another tree with key and value of nodes swapped
*/
struct FillRevTree: public BST::Apply {
BST &tree; // destination tree to fill
FillRevTree(BST &tree): tree(tree) { }
virtual void preNode(BSTNode &node)
{
tree.insert(node.value, node.key);
}
};
// main function
int main()
{
BST tree;
// read tree from input
cout << "Read contents from input:" << endl;
for (string line; getline(cin, line);) {
string key, value; split(line, key, value);
if (!tree.insert(key, value)) {
cerr << "Error! Couldn't store the line:" << endl
<< "->" << line << endl;
}
}
cout << "End of input." << endl
<< endl;
// show tree
cout << "The tree:" << endl;
{ PrintGraph print; tree.traverse(print); }
cout << endl;
// print tree by pre-order traversal
cout << "Pre-Order Output:" << endl;
{ PrintPreOrder print; tree.traverse(print); }
cout << endl;
// print tree by in-order traversal
cout << "In-Order Output:" << endl;
{ PrintInOrder print; tree.traverse(print); }
cout << endl;
// re-built tree with keys and values swapped
BST treeRev;
{ FillRevTree fill(treeRev); tree.traverse(fill); }
// show reverse tree
cout << "The Rev. Tree:" << endl;
{ PrintGraph print; treeRev.traverse(print); }
cout << endl;
// print tree by in-order traversal
cout << "In-Order Output of Rev. Tree:" << endl;
{ PrintInOrder print; treeRev.traverse(print); }
cout << endl;
// done
cout << "That's it." << endl;
return 0;
}
Compile and run:
$ g++ -std=c++11 -o binary-search-tree binary-search-tree.cc
$ ./binary-search-tree <morse.txt
Read contents from input:
End of input.
The tree:
+-+- [-..: D]
+-+- [--.-: Q]
| +-+- [-----: 0]
| | +-+- [--: M]
| | | +--- [-: T]
| | | +--- [---: O]
| | +-+- [---..: 8]
| | +--- [----.: 9]
| | +--- [--.: G]
| +-+- [-.: N]
| +-+- [--..--: ,]
| | +--- [--..: Z]
| | +--- [--...: 7]
| +-+- [-.--: Y]
| +--- [-.-: K]
| +--- [-.-.: C]
+-+- [..: I]
+-+- [.----: 1]
| +-+- [.: E]
| | +-+- [-...: B]
| | | +--- [-..-: X]
| | | +--- [-....: 6]
| | +-+- [.--: W]
| | +--- [.-: A]
| | +--- [.---: J]
| +-+- [.-.-.-: .]
| +-+- [.--.: P]
| | +--- [.-.: R]
| +--- [.-..: L]
+-+- [...--: 3]
+-+- [..--..: ?]
| +-+- [..---: 2]
| | +--- [..-: U]
| +-+- [...: S]
| +--- [..-.: F]
| +--- [...-: V]
+-+- [....-: 4]
+--- [....: H]
+--- [.....: 5]
Pre-Order Output:
-..: D
--.-: Q
-----: 0
--: M
-: T
---: O
---..: 8
----.: 9
--.: G
-.: N
--..--: ,
--..: Z
--...: 7
-.--: Y
-.-: K
-.-.: C
..: I
.----: 1
.: E
-...: B
-..-: X
-....: 6
.--: W
.-: A
.---: J
.-.-.-: .
.--.: P
.-.: R
.-..: L
...--: 3
..--..: ?
..---: 2
..-: U
...: S
..-.: F
...-: V
....-: 4
....: H
.....: 5
In-Order Output:
-: T
--: M
---: O
-----: 0
----.: 9
---..: 8
--.: G
--.-: Q
--..: Z
--..--: ,
--...: 7
-.: N
-.-: K
-.--: Y
-.-.: C
-..: D
-..-: X
-...: B
-....: 6
.: E
.-: A
.--: W
.---: J
.----: 1
.--.: P
.-.: R
.-.-.-: .
.-..: L
..: I
..-: U
..---: 2
..--..: ?
..-.: F
...: S
...-: V
...--: 3
....: H
....-: 4
.....: 5
The Rev. Tree:
+-+- [D: -..]
+-+- [0: -----]
| +-+- [,: --..--]
| | +--- [.: .-.-.-]
| +-+- [8: ---..]
| +-+- [7: --...]
| | +-+- [1: .----]
| | +-+- [6: -....]
| | +-+- [3: ...--]
| | +--- [2: ..---]
| | +-+- [4: ....-]
| | +--- [5: .....]
| +-+- [9: ----.]
| +-+- [C: -.-.]
| +-+- [B: -...]
| +-+- [A: .-]
| +--- [?: ..--..]
+-+- [Q: --.-]
+-+- [M: --]
| +-+- [G: --.]
| | +-+- [E: .]
| | | +--- [F: ..-.]
| | +-+- [K: -.-]
| | +-+- [I: ..]
| | | +--- [H: ....]
| | | +--- [J: .---]
| | +--- [L: .-..]
| +-+- [O: ---]
| +--- [N: -.]
| +--- [P: .--.]
+-+- [T: -]
+-+- [R: .-.]
| +--- [S: ...]
+-+- [Z: --..]
+-+- [Y: -.--]
+-+- [X: -..-]
+-+- [W: .--]
+-+- [U: ..-]
+--- [V: ...-]
In-Order Output of Rev. Tree:
,: --..--
.: .-.-.-
0: -----
1: .----
2: ..---
3: ...--
4: ....-
5: .....
6: -....
7: --...
8: ---..
9: ----.
?: ..--..
A: .-
B: -...
C: -.-.
D: -..
E: .
F: ..-.
G: --.
H: ....
I: ..
J: .---
K: -.-
L: .-..
M: --
N: -.
O: ---
P: .--.
Q: --.-
R: .-.
S: ...
T: -
U: ..-
V: ...-
W: .--
X: -..-
Y: -.--
Z: --..
That's it.
$
Note:
I just recognized that the "reversed" tree is not well-balanced anymore.
Thus, the optimal worst-case time-complexity of O(ld(n)) cannot be achieved.

Parsing Logic Expressions with Pyparsing

To start of, this is not homework, I'm trying to learn pyparsing and I got stuck here.
My question is as follows, I'm trying to parse statements like (abc or def) or def)
My program goes to shit on an infix expression a or b, since both sides can be expressions themselves, which can again be infix expressions, the parser recurses until recursion depth is reached and no work gets done.
Code below:
# infix operators are automatically created and dealt with
infix_operators = ['and', '&', 'or', '|', 'implies', '->']
variable = Word(alphas)
infix_op = oneOf(infix_operators, caseless=True)
expr = Forward()
infix_expr = (expr + infix_op + expr)
complex_expr = nestedExpr('(', ')', content=expr)
expr << (infix_expr | complex_expr | variable)
print str(expr.parseString("(abc or def) or def)")[0])
My question is fairly simple; how would one go about avoiding an infinite loop in these kinds of situations?
The canonical solution is something that implements this BNF:
atom := variable | 'True' | 'False' | '(' expr ')'
factor := [ 'not' ]... atom
term := factor [ '&' factor ]...
expr := term [ '|' term ]...
The left-recursion problem is addressed because, even though expr eventually recurses through term -> factor -> atom, when it gets to expr, it first has to parse a leading '('. So an expr never has to first parse a deeper expr before parsing some other elements first.
This BNF translates almost directly to pyparsing as:
and_ = Keyword('and')
or_ = Keyword('or')
not_ = Keyword('not')
true_ = Keyword('true')
false_ = Keyword('false')
not_op = not_ | '~'
and_op = and_ | '&'
or_op = or_ | '|'
expr = Forward()
identifier = ~(and_ | or_ | not_ | true_ | false_) + Word(alphas)
atom = identifier | Group('(' + expr + ')')
factor = Group(ZeroOrMore(not_op) + atom)
term = Group(factor + ZeroOrMore(and_op + factor))
expr <<= Group(term + ZeroOrMore(or_op + term))
Or you can use pyparsing's infixNotation helper:
expr = infixNotation(true_ | false_ | identifier,
[
(not_op, 1, opAssoc.RIGHT),
(and_op, 2, opAssoc.LEFT),
(or_op, 2, opAssoc.LEFT),
])
infixNotation is constructed with a base operand (in this case, either an alpha variable name or one of the boolean literals true or false), followed by a list of (operator, arity, associativity) tuples, given in order of operator precedence. infixNotation takes care of all the recursion definitions, the parsing of right-associative vs. left-associative operators, and also does some lookahead for operators, to avoid extra nesting of operations for a given precedence level if there are no operators.
You can test this expression using pyparsing's runTests method:
expr.runTests("""
p and not q
not p or p
r and (p or q)
r and p or q
not q
q
""", fullDump=False)
Giving:
p and not q
[['p', 'and', ['not', 'q']]]
not p or p
[[['not', 'p'], 'or', 'p']]
r and (p or q)
[['r', 'and', ['p', 'or', 'q']]]
r and p or q
[[['r', 'and', 'p'], 'or', 'q']]
not q
[['not', 'q']]
q
['q']

Trying to get first word from character list

I have a character list [#"h", #"i", #" ", #"h", #"i"] which I want to get the first word from this (the first character sequence before each space).
I've written a function which gives me this warning:
stdIn:13.1-13.42 Warning: type vars not generalized because of value
restriction are instantiated to dummy types (X1,X2,...)
Here is my code:
fun next [] = ([], [])
| next (hd::tl) = if(not(ord(hd) >= 97 andalso ord(hd) <= 122)) then ([], (hd::tl))
else
let
fun getword [] = [] | getword (hd::tl) = if(ord(hd) >= 97 andalso ord(hd) <= 122) then [hd]#getword tl else [];
in
next (getword (hd::tl))
end;
EDIT:
Expected input and output
next [#"h", #"i", #" ", #"h", #"i"] => ([#"h", #"i"], [#" ", #"h", #"i"])
Can anybody help me with this solution? Thanks!
This functionality already exists within the standard library:
val nexts = String.tokens Char.isSpace
val nexts_test = nexts "hi hi hi" = ["hi", "hi", "hi"]
But if you were to build such a function anyway, it seems that you return ([], []) sometimes and a single list at other times. Normally in a recursive function, you can build the result by doing e.g. c :: recursive_f cs, but this is assuming your function returns a single list. If, instead, it returns a tuple, you suddenly have to unpack this tuple using e.g. pattern matching in a let-expression:
let val (x, y) = recursive_f cs
in (c :: x, y + ...) end
Or you could use an extra argument inside a helper function (since the extra argument would change the type of the function) to store the word you're extracting, instead. A consequence of doing that is that you end up with the word in reverse and have to reverse it back when you're done recursing.
fun isLegal c = ord c >= 97 andalso ord c <= 122 (* Only lowercase ASCII letters *)
(* But why not use one of the following:
fun isLegal c = Char.isAlpha c
fun isLegal c = not (Char.isSpace c) *)
fun next input =
let fun extract (c::cs) word =
if isLegal c
then extract cs (c::word)
else (rev word, c::cs)
| extract [] word = (rev word, [])
in extract input [] end
val next_test_1 =
let val (w, r) = next (explode "hello world")
in (implode w, implode r) = ("hello", " world")
end
val next_test_2 = next [] = ([], [])

Whats wrong with my anti_vowel program.It fails on "Hey look words"

def anti_vowel(text):
a = []
for i in str(text):
a.append(i)
print a
v = "aeiouAEIOU0"
for p in v:
for e in a:
if p == e:
a.remove(p)
print a
d = ""
for w in a:
d = d + str(w)
return d
The problem is that you are removing elements from a list while iterating that same list. The loop will "lose track" of its current position in the list and thus skip some elements.
Instead of first adding all the letters to the list, then removing the ones that are vowels, you should just add those that are not vowels in the first place. You can do this in a single line using a list comprehension and then using ''.join to join it to a string:
def anti_vowel(text):
return ''.join(a for a in text if a not in "aeiouAEIOU0")
This is roughly equivalent to
d = ""
for a in text:
if a not in "aeiouAEIOU0":
d += a

Where does many produce the empty string?

I am currently reading Programming in Haskell by Graham Hutton. I am stuck on the chapter of Parsers. In it there are two mutually recursive functions defined as:
many p = many1 p +++ return []
many1 p = do v <- p
vs <- many p
return (v:vs)
Where many is actually transformed into this form:
many1 p = p >>= (\ v -> many p >>= (\ vs -> return (v : vs)))
The >>= operator is defined as:
p >>= f = P (\inp -> case parse p inp of
[] -> []
[(v,out)] -> parse (f v) out)
The +++ operator is defined as:
p +++ q = P (\inp -> case parse p inp of
[] -> parse q inp
[(v,out)] -> [(v,out)])
The other functions relevant to this question are these:
parse :: Parser a -> String -> [(a,String)]
parse (P p) inp = p inp
sat p = do x <- item
if p x then return x else failure
digit = sat isDigit
failure = P (\inp -> [])
item = P (\inp -> case inp of
[] -> []
(x:xs) -> [(x,xs)])
return v = P (\inp -> [(v,inp)])
Now, when attempting to use many1 to parse digits from the string "a", like:
parse (many digit) "a"
the result is [("","a")].
When attempting to parse digits from the string "a" using many1 like:
parse (many1 digit) "a"
the result is [].
I think I understand why the second result. (many1 digit) attempts to parse the string "a", and so it calls digit "a" which fails since "a" is not a digit, and so the empty list is returned [].
However, I do not understand the first result when using (many digit). If (many1 digit) returns [] then obviously it failed, and so in the +++ operator, the second case expression is executed. But when I try to parse (return []) "a" the result I get back is [([], "a")].
I don't get it why the result of many is [("", "a")], when the result of many1 is [].
Any help is appreciated.
P.S. I have seen this question already, but it doesn't give me the answer I am looking for.
If your confusion is that you get back [("", "a")] when you expected [([], "a")]:
A string is a list of Chars. So "" is an empty list of Chars. Since [] is an empty list of any type, that means that "" is just a special case of []. In other words [] :: [Char] is completely equivalent to "".
So since your parser is expected to produce a string, the empty list is known to be of type [Char] and thus printed as "" instead of [].