What is combinator parsing? Give an explanation of the concept, but do not explain about it's history or information which is irrelevant to developing or using a combinator parsing library.
Combinator parsing is a technique used in computer science to build parsers for formal languages. It involves combining small parsing functions, called combinators, to create more complex parsers that can handle a wide range of input patterns.

In combinator parsing, a parser is essentially a function that takes an input string and produces a parse tree or some other form of structured representation of the input. Combinators are higher-order functions that take parsers as input and return a new parser as output. They allow parsers to be combined and composed in a modular and flexible way.

There are different types of combinators used in combinator parsing, including:

1. Sequence Combinators: These combinators allow parsers to be executed sequentially. For example, a sequence combinator might take two parsers as input and return a new parser that matches the first parser, followed by the second parser.

2. Choice Combinators: Choice combinators allow parsers to match one of several alternatives. For example, a choice combinator might take two parsers as input and return a new parser that matches either the first parser or the second parser.

3. Transformation Combinators: Transformation combinators modify the output of a parser. They can be used to convert the parsed input into a different representation or perform other transformations on the parsed data.

By combining these basic combinators, complex parsers can be built that can handle a variety of input patterns and grammars. Combinator parsing libraries provide a set of predefined combinators along with mechanisms for creating custom combinators.

The advantage of combinator parsing is its simplicity and modularity. Combinator parsers are often easy to understand and maintain because they are built from small, reusable components. Combinator parsing also allows for incremental development, as parsers can be built step by step by combining and refining smaller parsers.

Combinator parsing is widely used in the development of programming language compilers, interpreters, and other systems that require parsing and analyzing input languages. It provides a flexible and expressive approach to parsing that can accommodate a wide range of language grammars and input patterns.
That's great, just what I asked for.  Now, can you give me some examples?
Certainly! Let's illustrate combinator parsing with some simple examples using pseudo-code. We'll assume a basic understanding of programming concepts and notation.

Example 1: Parsing Integers

Let's say we want to parse integers from an input string. We can define a combinator `digit` that matches a single digit character, and another combinator `integer` that matches a sequence of one or more digits.

```pseudo-code
# Combinator for matching a single digit
function digit(input):
    if input is empty:
        return FAILURE
    if input[0] is a digit:
        return (input[0], input[1:])
    else:
        return FAILURE

# Combinator for matching an integer
function integer(input):
    result = []
    while true:
        (digit_value, remaining_input) = digit(input)
        if digit_value is not FAILURE:
            result.append(digit_value)
            input = remaining_input
        else:
            break
    if not result:
        return FAILURE
    else:
        return (convert_to_integer(result), remaining_input)
```

Example 2: Parsing Arithmetic Expressions

Now, let's build a more complex combinator for parsing simple arithmetic expressions with addition and multiplication.

```pseudo-code
# Combinator for matching a number (similar to the integer combinator from Example 1)
function number(input):
    # ... (implementation similar to integer combinator)

# Combinator for matching an addition operation
function addition(input):
    left = number(input)
    if left is FAILURE or left[1] does not start with '+':
        return FAILURE
    right = expression(left[1][1:])
    if right is FAILURE:
        return FAILURE
    return ('+', left[0], right[0], right[1])

# Combinator for matching a multiplication operation
function multiplication(input):
    left = number(input)
    if left is FAILURE or left[1] does not start with '*':
        return FAILURE
    right = expression(left[1][1:])
    if right is FAILURE:
        return FAILURE
    return ('*', left[0], right[0], right[1])

# Combinator for matching an arithmetic expression
function expression(input):
    result = addition(input)
    if result is not FAILURE:
        return result
    result = multiplication(input)
    if result is not FAILURE:
        return result
    return number(input)
```

In these examples, we have created basic combinators (`digit` and `number`) and combined them to build more complex combinators (`integer`, `addition`, `multiplication`, and `expression`). The `expression` combinator can handle simple arithmetic expressions like 3+5 and 2*4+7 by recursively combining addition and multiplication operations.

These examples demonstrate how combinator parsing allows us to build parsers in a modular and flexible way, combining small building blocks to handle more complex input patterns and grammars. In real-world implementations, the combinators would be written in a programming language, and additional error handling and other features would be added for robustness and usability.