<commit_before>---
title: RPN calculator
---

This example is for an [RPN][] calculator. The Squiggle version does not use any
predefined Squiggle functions, so it's easier to see the syntax translation.
Also, the Squiggle version contains more exception throwing, which is
automatically generated by Squiggle.

## rpn.js

    /// Consider that the JavaScript version contains far
    /// fewer assertions than the Squiggle version.
    /// Squiggle automatically asserts that a key is an own
    /// property of the object before retreiving it
    /// (e.g. x[0], foo.bar, keys must exist or it throws).
    /// Also, functions will throw unless called with the
    /// correct number of arguments.
    //// Arrays and objects created through Squiggle are
    /// also implicitly frozen,
    /// so you can't accidentally mutate them.

    var _ = require("lodash");

    var text = "2 3 4 * 3 - +";

    var table = {
      "+": function(a, b) { return a + b; },
      "-": function(a, b) { return a - b; },
      "*": function(a, b) { return a * b; },
      "/": function(a, b) { return a / b; },
    };

    function tokenize(text) {
        return text.split(" ").map(tokenValue);
    }

    function tokenValue(token) {
        if (table.hasOwnProperty(token)) {
            return table[token];
        } else {
            return Number(token);
        }
    }

    function evaluateWithStack(stack, values) {
        if (values.length === 0) {
            return stack[0];
        }
        var i = stack.length;
        var x = values[0];
        var v = values.slice(1);
        if (_.isFunction(x)) {
            var a = stack[i - 1];
            var b = stack[i - 2];
            var y = x(a, b);
            return evaluateWithStack(
                stack.slice(0, i - 2).concat([y]),
                v
            );
        } else {
            return evaluateWithStack(
                stack.concat([x]),
                v
            );
        }
    }

    function evaluate(text) {
        return evaluateWithStack([], tokenize(text));
    }

    console.log(evaluate(text));

## rpn.squiggle

    let isFunction = (require("lodash")).isFunction
    let Number = global.Number
    let text = "2 3 4 * 3 - +"

    # You have to explicitly ignore arguments
    # with an underscore in Squiggle.
    def tokenize(text) =
        text
            .split(" ")
            .map(fn(x, _i, _a) tokenValue(x))

    def tokenValue(token) =
        match token
        case "+" => fn(a, b) a + b
        case "-" => fn(a, b) a - b
        case "*" => fn(a, b) a * b
        case "/" => fn(a, b) a / b
        case num => Number(num)
        end

    def evaluateWithStack(stack, values) =
        match values
        case [] =>
            head(stack)
        case [x, ...xs] =>
            if isFunction(x) then
                let first = stack[0]
                let second = stack[1]
                let rest = stack.slice(2)
                let y = x(first, second)
                in evaluateWithStack([y] ++ rest, xs)
            else
                evaluateWithStack([x] ++ stack, xs)
        end

    def evaluate(text) =
        evaluateWithStack([], tokenize(text))

    in console.log(evaluate(text))

[rpn]: https://en.wikipedia.org/wiki/Reverse_Polish_notation<commit_msg>Updates RPN example<commit_after>---
title: RPN calculator
---

This example is for an [RPN][] calculator. The Squiggle version does not use any
predefined Squiggle functions, so it's easier to see the syntax translation.
Also, the Squiggle version contains more exception throwing, which is
automatically generated by Squiggle.

## rpn.js

    /// Consider that the JavaScript version contains far
    /// fewer assertions than the Squiggle version.
    /// Squiggle automatically asserts that a key is an own
    /// property of the object before retreiving it
    /// (e.g. x[0], foo.bar, keys must exist or it throws).
    /// Also, functions will throw unless called with the
    /// correct number of arguments.
    //// Arrays and objects created through Squiggle are
    /// also implicitly frozen,
    /// so you can't accidentally mutate them.

    var _ = require("lodash");

    var text = "2 3 4 * 3 - +";

    var table = {
      "+": function(a, b) { return a + b; },
      "-": function(a, b) { return a - b; },
      "*": function(a, b) { return a * b; },
      "/": function(a, b) { return a / b; },
    };

    function tokenize(text) {
        return text.split(" ").map(tokenValue);
    }

    function tokenValue(token) {
        if (table.hasOwnProperty(token)) {
            return table[token];
        } else {
            return Number(token);
        }
    }

    function evaluateWithStack(stack, values) {
        if (values.length === 0) {
            return stack[0];
        }
        var i = stack.length;
        var x = values[0];
        var v = values.slice(1);
        if (_.isFunction(x)) {
            var a = stack[i - 1];
            var b = stack[i - 2];
            var y = x(a, b);
            return evaluateWithStack(
                stack.slice(0, i - 2).concat([y]),
                v
            );
        } else {
            return evaluateWithStack(
                stack.concat([x]),
                v
            );
        }
    }

    function evaluate(text) {
        return evaluateWithStack([], tokenize(text));
    }

    console.log(evaluate(text));

## rpn.squiggle

    let L = require "lodash"
    let Number = global.Number
    let text = "2 3 4 * 3 - +"

    # You have to explicitly ignore arguments
    # with an underscore in Squiggle.
    def tokenize(text) =
        text
            .split(" ")
            .map(fn(x, _, _) tokenValue(x))

    def tokenValue(token) =
        match token
        case "+" => fn(a, b) a + b
        case "-" => fn(a, b) a - b
        case "*" => fn(a, b) a * b
        case "/" => fn(a, b) a / b
        case num => Number(num)
        end

    def evaluateWithStack(stack, values) =
        match values
        case [] =>
            head(stack)
        case [x, ...xs] =>
            if L.isFunction(x) then
                let first = stack[0]
                let second = stack[1]
                let rest = stack.slice(2)
                let y = x(first, second)
                in evaluateWithStack([y] ++ rest, xs)
            else
                evaluateWithStack([x] ++ stack, xs)
        end

    def evaluate(text) =
        evaluateWithStack([], tokenize(text))

    in console.log(evaluate(text))

[rpn]: https://en.wikipedia.org/wiki/Reverse_Polish_notation
{'fraction_non_alphanumeric': 0.12589326440626425, 'fraction_numerical': 0.006081800212863008, 'mean_word_length': 1.6936936936936937, 'pattern_counts': {'":': 8, '<': 3, '<?xml version=': 0, '>': 17, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '791921', 'n_tokens_mistral': 2017, 'n_tokens_neox': 1900, 'n_words': 610}