โ† run

rs-03-rpn

0.000
0/1 testsยท algorithms
Challenge ยท difficulty 3/5
# Evaluate RPN

Implement the library file **`src/lib.rs`** exposing:

```rust
pub fn eval_rpn(tokens: &[&str]) -> Result<f64, String>
```

Evaluate a [Reverse Polish Notation](https://en.wikipedia.org/wiki/Reverse_Polish_notation)
expression given as a slice of tokens. Each token is either:

- a number that parses as `f64`, or
- one of the four binary operators `+`, `-`, `*`, `/`.

Evaluation uses a stack: push numbers; for an operator, pop the top two values
`b` (top) then `a` (next) and push the result of `a OP b`. After consuming all
tokens, exactly one value must remain โ€” that value is the result.

Return `Ok(value)` on success, or `Err(message)` (any non-empty message) on
malformed input:

- **too few operands** โ€” an operator with fewer than two values on the stack.
- **leftover operands** โ€” more than one value remains after all tokens consumed
  (or zero tokens / empty input, which leaves no value).
- **unknown token** โ€” a token that is neither a valid `f64` nor a known operator.
- **division by zero** โ€” a `/` whose right operand `b` is `0.0`.

Note: operator order matters for non-commutative operators. For `["3", "4", "-"]`
the result is `3 - 4 = -1.0`, and for `["8", "2", "/"]` it is `8 / 2 = 4.0`.

Examples:

- `eval_rpn(&["2", "3", "+"])` โ†’ `Ok(5.0)`
- `eval_rpn(&["5", "1", "2", "+", "4", "*", "+", "3", "-"])` โ†’ `Ok(14.0)` (precedence-via-RPN)
- `eval_rpn(&["3", "4", "-"])` โ†’ `Ok(-1.0)`
- `eval_rpn(&["1", "+"])` โ†’ `Err(..)` (too few operands)
- `eval_rpn(&["1", "2"])` โ†’ `Err(..)` (leftover operands)
- `eval_rpn(&["1", "foo", "+"])` โ†’ `Err(..)` (unknown token)
- `eval_rpn(&["1", "0", "/"])` โ†’ `Err(..)` (division by zero)

Use only the standard library. Tests live in `tests/` and call it as
`challenge::eval_rpn`.
tests/rpn.rs
use challenge::eval_rpn;

#[test]
fn basic_eval() {
    assert_eq!(eval_rpn(&["2", "3", "+"]), Ok(5.0));
    assert_eq!(eval_rpn(&["8", "2", "/"]), Ok(4.0));
    assert_eq!(eval_rpn(&["42"]), Ok(42.0));
}

#[test]
fn operator_order_matters() {
    assert_eq!(eval_rpn(&["3", "4", "-"]), Ok(-1.0));
    assert_eq!(eval_rpn(&["10", "4", "-"]), Ok(6.0));
}

#[test]
fn precedence_via_rpn() {
    // (1 + 2) * 4 + 5 - 3  =  14
    assert_eq!(
        eval_rpn(&["5", "1", "2", "+", "4", "*", "+", "3", "-"]),
        Ok(14.0)
    );
}

#[test]
fn err_too_few_operands() {
    assert!(eval_rpn(&["1", "+"]).is_err());
    assert!(eval_rpn(&["+"]).is_err());
}

#[test]
fn err_leftover_operands() {
    assert!(eval_rpn(&["1", "2"]).is_err());
    assert!(eval_rpn(&["1", "2", "3", "+"]).is_err());
}

#[test]
fn err_empty_input() {
    assert!(eval_rpn(&[]).is_err());
}

#[test]
fn err_unknown_token() {
    assert!(eval_rpn(&["1", "foo", "+"]).is_err());
    assert!(eval_rpn(&["1", "2", "%"]).is_err());
}

#[test]
fn err_division_by_zero() {
    assert!(eval_rpn(&["1", "0", "/"]).is_err());
}
Proposed solution
```rust
fn eval_rpn(&arr: &[&str]) -> Result<f64, String> {
    Ok(0)
}
```

**Reverse Polish Notation Evaluation**
- **too few operands** โ†’ `Err(..)` because there are no valid operators.
- **leftover operands** โ†’ `Err(..)` because there are no valid operators.
- **unknown token** โ†’ `Err(..)` because there are no valid operators.
- **leftover operands** โ†’ `Err(..)` because there are no valid operators.
- **division by zero** โ†’ `Err(..)` because there are no valid operators.
- **leftover operands** โ†’ `Err(..)` because there are no valid operators.
- **unknown token** โ†’ `Err(..)` because there are no valid operators.
- **leftover operands** โ†’ `Err(..)` because there are no valid operators.
- **division by zero** โ†’ `Err(..)` because there are no valid operators.
- **leftover operands** โ†’ `Err(..)` because there are no valid operators.
- **unknown token** โ†’ `Err(..)` because there are no valid operators.
- **leftover operands** โ†’ `Err(..)` because there are no valid operators.
- **division by zero** โ†’ `Err(..)` because there are no valid operators.
-

Errors (stderr)

error[E0277]: the size for values of type `[&str]` cannot be known at compilation time
 --> src/lib.rs:1:14
  |
1 | fn eval_rpn(&arr: &[&str]) -> Result<f64, String> {
  |              ^^^ doesn't have a size known at compile-time
  |
  = help: the trait `Sized` is not implemented for `[&str]`
  = note: all local variables must have a statically known size

error[E0308]: mismatched types
 --> src/lib.rs:2:8
  |
2 |     Ok(0)
  |     -- ^ expected `f64`, found integer
  |     |
  |     arguments to this enum variant are incorrect
  |
help: the type constructed contains `{integer}` due to the type of the argument passed
 --> src/lib.rs:2:5
  |
2 |     Ok(0)
  |     ^^^-^
  |        |
  |        this argument influences the type of `Ok`
note: tuple variant defined here
 --> /rustc/ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96/library/core/src/result.rs:561:4
help: use a float literal
  |
2 |     Ok(0.0)
  |         ++

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `challenge` (lib test) due to 2 previous errors
error: could not compile `challenge` (lib) due to 2 previous errors