Try yeti online

On this page you can evaluate yeti code online, by entering it in the below textarea.

Yeti is a simple, statically typed functional programming-language for the JVM. It features: HM-typeinference without the need for type declarations. structural typing; polymorphic structure and variant types; pattern-matching; lazy-lists; fast compilation; calling existing Java code (calling java code is restricted in this online evaluation).

The initial few evaluation-requests may take longer until the server-code has warmed up. For security reasons importing of classes and loading of modules is not allowed. The functions of the module yeti.lang.std and the functions print and println are preloaded.

Result:

Examples

  • ack

    ack m n =
        if m == 0 then
            n + 1
        elif n == 0 then
            ack (m - 1) 1
        else
            ack (m - 1) (ack m (n - 1))
        fi;
    
    println "ack 3 8 = \(ack 3 8)"
    
  • beer

    bottles =
       \case of
        0: "no more bottles of beer";
        1: "1 bottle of beer";
        n: "\(n) bottles of beer";
        esac;
    
    for (reverse [1 .. 99]) do n:
        println "\(bottles n) on the wall, \(bottles n)\n\
                "Take one down, pass it around,\n\
                "and there's \(bottles (n - 1)) on the wall!";
    done
    
  • bridge

    drawingAPI1 = {
        drawCircle x y radius =
            println "API1.circle at \(x):\(y) radius \(radius)"
    };
    
    drawingAPI2 = {
        drawCircle x y radius =
            println "API2.circle at \(x):\(y) radius \(radius)"
    };
    
    circleShape x y radius drawingAPI =
       (var currentRadius = radius;
        {
            draw () =
                drawingAPI.drawCircle x y currentRadius,
    
            resizeByPercentage pct =
                currentRadius := currentRadius * pct
        });
    
    shapes = [ circleShape 1 2 3 drawingAPI1,
               circleShape 5 7 11 drawingAPI2 ];
    for shapes do shape:
        shape.resizeByPercentage 2.5;
        shape.draw();
    done
    
    
  • btree

    insert t v =
        case t of
        Some {left, right, value}:
            if v < value then
                Some {left = insert left v, right, value}
            elif v > value then
                Some {left, right = insert right v, value}
            else
                t
            fi;
        None (): Some {left = none, right = none, value = v};
        esac;
    
    exists t v =
        case t of
        Some {left, right, value}:
            if v < value then
                exists left v
            else
                value == v or exists right v
            fi;
        None (): false
        esac;
    
  • curve

    zero = {x = 0, y = 0, z = 0};
    norm {x, y, z} = sqrt (x * x + y * y + z * z);
    (/^) p d = {x = p.x / d, y = p.y / d, z = p.z / d};
    normalize p = p /^ norm p;
    max' a b = {x = max a.x b.x, y = max a.y b.y, z = max a.z b.z};
    
    curvePoint n =
       (x = sin n;
        cn = cos n;
        {x, y = cn * 3, z = (x * x) / 2});
    
    curvePointArray len =
        map (normalize . curvePoint) [0 .. len - 1];
    
    arrayMax = fold max' zero;
    
    benchmark = println . arrayMax . curvePointArray;
    
    for [0 .. 7] do i:
        println "Run #\(i)";
        benchmark 5000;
    done
    
  • euler5

    gcd a b =
        if b == 0 then a else gcd b (a % b) fi;
    
    lcm a b =
        a div gcd a b * b;
    
    println (fold lcm 1 [1 .. 20]);
    
  • fact

    fact x =
        if x == 0 then
            1
        else
            x * fact (x - 1)
        fi;
    
    fact_ =
       (f acc x =
            if x == 0 then
                acc
            else
                f (acc * x) (x - 1)
            fi) 1;
    
    y f x = f (y f) x;
    yfact = y do rec x:
    	if x == 0 then 1 else x * rec (x - 1) fi
    done;
    
    println {fact = fact 5};
    println {fact_ = fact_ 5};
    println {yfact = yfact 5};
    println (fact_ 1000);
    
  • fib

    // memoizing algorithm
    fibs = [0: 0, 1: 1];
    setHashDefault fibs do x:
        res = fibs[x - 1] + fibs[x - 2];
        fibs[x] := res;
        res
    done;
    
    // function to get fib
    getFib = at fibs;
    
    println (getFib 1);
    getFib 10 |> println;
    
    
  • fizzbuzz

    for [1 .. 100] do i:
        println (array ["fizzbuzz", "fizz", "buzz", "\(i)"])[
                    index 0 [i%15, i%3, i%5, 0]]
    done
    
  • hello

    println "Hello world"
    
  • loop

    var i = 0;
    i < 5 loop (
        println i;
        i := i + 1;
    )
    
  • monad

    // Simple state monad using opaque types
    // (language support for Haskell do block alike would make it nicer).
    
    typedef opaque st<v,s> = s -> {fst is v, snd is s}
    
    st = {
        return = pair,
        bind mv f st =
           ({fst, snd} = mv st;
            f fst snd),
        getst st  = pair st st,
        setst v _ = pair () v,
        run = id,
    } as { // as cast to hide the implementation types
        return is 'a -> st<'a, 's>,
        bind is st<'b, 's> -> ('b -> st<'c, 's>) -> st<'c, 's>,
        getst is st<'s, 's>,
        setst is 's -> st<(), 's>,
        run is st<'d, 's> -> 's -> 'r
    };
    
    (>>=) = st.bind;
    {return, getst, setst} = st;
    
    println (st.run (return 'a') 10);
    
    println (st.run (setst 5 >>= (_ _ = getst >>= (_ x = return "a\(x)"))) 10);
    
    
  • multiple

    numLen n =
    	if n == 0 then 0 else numLen (n div 10) + 1 fi;
    
    pow10 n =
    	if n > 0 then pow10 (n - 1) * 10 else 1 fi;
    
    prod x y =
    	(n = max (numLen x) (numLen y);
    	if n < 3 then
    		x * y
    	else
    		m = pow10 (n div 2);
    		a = x div m;
    		b = x % m;
    		c = y div m;
    		d = y % m;
    		prod a c * m * m + (prod a d + prod b c) * m + b * d
    	fi);
    
    test x y =
    	(println "\(x) * \(y) = \(x * y)";
    	 println "prod \(x) \(y) = \(prod x y)");
    
    test 34 56;
    test 1234 4321;
    test 123456789 987654321;
    test 12345678987654321 98765432123456789;
    
    
  • opaquelist

    /**
     * Examples:
     * :
     * : v = create ["foo", "bar"];
     * :
     * : // for v println;
     * : for (values v) println;
     *
     * The commented out line trying to use v directly as a list would not compile.
     */
    
    typedef opaque magic<x> = list<x>;
    
    r = {
        create l is list<'a> -> list<'a> = l,
        values v is list<'a> -> list<'a> = v,
    } as {
        create is list<'a> -> magic<'a>,
        values is magic<'b> -> list<'b>,
    };
    
    r
    
  • peek

    showObj =
       \case of
        Number num:
            "number \(num)";
        String str:
            "string '\(str)'";
        Boolean bool:
            "boolean \(bool)";
        List l:
            "list [\(strJoin ", " (map showObj l))]";
        Struct st:
            field name =
                "\(name) = \(showObj (st.value name))";
            "struct {\(strJoin ", " (map field st.fields))}";
        Variant st:
            "\(st.tag) (\(st.value))";
        Hash h:
            item key value =
                "\(showObj key): \(showObj value)";
            "hash [\(strJoin ", " (mapHash item h))]";
        Object o:
            "Object(\(o))";
        esac;
    
    println (showObj (peekObject {
        foo = 12,
        bar = Some "sheep",
        baz = [37..42],
        tar = ["doh": 33, "wtf": 12],
        truth = false
    }))
    
    
  • primes

    sieve stream =
        head stream :. \(sieve (filter ((!= 0) . (% (head stream))) (tail stream)));
    
    primes = sieve (iterate (+1) 2);
    
    sieve2 limit =
       (numbers = array [0 .. limit];
        numbers[0] := -1;
        numbers[1] := -1;
        var primes = [];
        for numbers do i:
            if i != -1 then
                var j = i * 2;
                j <= limit loop
                   (numbers[j] := -1;
                    j := j + i);
                primes := i :: primes;
            fi
        done;
        reverse primes);
    
    println "lazy sieve  : \(takeWhile (<= 100) primes)";
    println "strict sieve: \(sieve2 100)";
    
  • prototype

    // simple point
    // printer is abstract callback method
    
    point printer = 
       (var x = 0;
        var y = 0;
        {
            show () =
                printer "at \(x),\(y)\n",
            move x' y' =
                x := x';
                y := y'
        });
    
    // alternative implementation would be to wrap the printer ;)
    // coloredPoint adds color accessor and overrides show method to print color
    coloredPoint color printer =
       (p = point printer;
        p with {
            color,
    
            show () =
                printer "\(color) ";
                p.show ()
        });
    
    // this "class" provides printer using standard print function
    coloredPrintPoint color =
        coloredPoint color print;
    
    // and it works...
    cp = coloredPrintPoint "red";
    cp.move 13 42;
    cp.show ();
    println "cp is \(cp.color)";
    
    
  • regex

    foo = "Saba 2";
    
    if foo =~ '[a-z]' then
        println 'contains small letter'
    fi;
    
    str = "kala, 33, pattern, 34, 123!";
    
    matcher = like 'pattern.*!' str;
    (
        match = matcher ();
        println match;
        not empty? match
    ) loop;
    
    for [
        strJoin '' (matchAll '\d+' do s: "\(number s[0] + 1)" done id str),
        strJoin '' (matchAll '\d+' (string . (+1) . number . head) id str),
        strJoin '' (matchAll ',\s+' \';' id str),
        substAll ',\s+' ';' str,
        "\(strSplit ',\s+' str)",
    ] println;
    
    
  • sort

    asort f less l =
       (a = array l;
        f less a;
        list a);
    
    selectionSort less a =
       (selectLess i j = if less a[i] a[j] then i else: j;
        swapMin i = swapAt a i (fold selectLess i [i + 1 .. length a - 1]);
        for [0 .. length a - 2] swapMin);
    
    combSort less a =
       (var gap = length a;
        var swapped = true;
        gap > 1 or swapped loop
           (gap := gap * 10 div 13;
            if gap == 10 or gap == 9 then
                gap := 11
            elif gap < 1 then
                gap := 1
            fi;
            swapped := false;
            gap = gap; // optimisation
            for [0 .. length a - gap - 1] do i:
                if less a[i + gap] a[i] then
                    swapAt a i (i + gap);
                    swapped := true
                fi
            done));
    
    shellSort less a is (^a -> ^a -> boolean) -> array<^a> -> () =
       (var inc = length a;
        (inc := if inc == 2 then 1 else: inc * 10 div 23; inc > 0) loop
           (var i = inc;
            i < length a loop
               (tmp = a[i];
                var j = i;
                j >= inc and less tmp a[j - inc] loop
                   (a[j] := a[j - inc];
                    j := j - inc);
                a[j] := tmp;
                i := i + 1)));
    
    // based on wikipedia pseudocode example
    heapSort less a =
       (for [1 .. length a - 1] do end:
            var child = end;
            child > 0 loop
               (parent = (child - 1) div 2;
                if less a[parent] a[child] then
                    swapAt a parent child;
                    child := parent
                else:
                    child := 0)
        done;
        for (reverse [0 .. length a - 2]) do end:
            swapAt a 0 (end + 1);
            var root = 0;
            root * 2 + 1 <= end loop // shiftdown
               (var child = root * 2 + 1;
                if child < end and less a[child] a[child + 1] then
                    child := child + 1
                fi;
                if less a[root] a[child] then
                    swapAt a root child;
                    root := child
                else:
                    root := end)
        done);
    
    qsort less a is (^a -> ^a -> boolean) -> array<^a> -> () =
       (sort l r =
           (var i = l;
            var j = r;
            x = a[(l + r) div 2];
               (less a[i] x loop i := i + 1;
                less x a[j] loop j := j - 1;
                if i <= j then
                    tmp = a[i];
                    a[i] := a[j];
                    a[j] := tmp;
                    i := i + 1;
                    j := j - 1;
                fi;
                i <= j) loop;
            if l < j then
                sort l j
            fi;
            if i < r then
                sort i r
            fi)) 0 (length a - 1);
    
    qsort2 less =
       (qsort l =
            case l of
            x :: xs: // could do with half of the compares
                qsort (filter ((not) . less x) xs)
                    ++ x :: qsort (filter (less x) xs);
            _: [];
            esac);
    
    merge less l a b =
        if empty? a then
            revAppend l b
        elif empty? b then
            revAppend l a
        elif head a `less` head b then
            merge less (head a :: l) (tail a) b
        else:
            merge less (head b :: l) a (tail b);
    
    splitList l fst snd =
        case l of
            h1 :: h2 :: t: splitList t (h1 :: fst) (h2 :: snd);
            h :: _: { fst, snd = h :: snd };
            _: { fst, snd };
        esac;
    
    mergeSort less l =
        case l of
        _::_::_:
            {fst, snd} = splitList l [] [];
            merge less [] (mergeSort less fst) (mergeSort less snd);
        _: l
        esac;
    
    insertionSort less l =
        fold do l e:
            {fst, snd} = splitBy ((not) . (`less` e)) l;
            fst ++ e :: snd
        done [] l;
    
    insertionSort2 less a =
        for [1 .. length a - 1] do i:
            v = a[i];
            var j = i - 1;
            j >= 0 and less v a[j] loop
               (a[j + 1] := a[j];
                j := j - 1);
            a[j + 1] := v
        done;
    
    
    test n slow =
       (l = map \(randomInt (n * 2)) [1..n];
        sorted = sort l;
    
        testSort name f =
           (var n = 0; // number of comparisions
            less x y = (n := n + 1; x < y);
            r = f less l;
            _ = length r; // force lists so n would have correct value
            if sorted != r then
                println "\(name): ERROR\n\(r) != \(sorted)"
            else:
                println "\(name)");
    
        testASort name f = testSort name (asort f);
    
        println "sorting array of \(length l) elements...";
        if slow then
            testASort "selection" selectionSort;
            testSort "insertion" insertionSort;
            testASort "insertion2" insertionSort2;
            testSort "qsort2" qsort2;
            testASort "heap" heapSort;
        fi;
        testASort "comb" combSort;
        testASort "shell" shellSort;
        testASort "qsort" qsort;
        testSort "merge" mergeSort;
        testSort "sortBy" sortBy);
    
    test 200 false;
    test 200 true;
    
    
  • trampoline

    {odd, even} = {
        even n =
            if n == 0 then
                Done true
            else
                Call \(odd (n - 1))
            fi,
        odd n =
            if n == 0 then
                Done false
            else
                Call \(even (n - 1))
            fi
    };
    
    trampoline =
       \case of
        Call f: trampoline (f ());
        Done v: v;
        esac;
    
    println (trampoline (even 98))
    
  • vrprod

    prod l1 l2 = concat (map (_ x = map (_ y = {x, y}) l2) l1);
    
    println (prod [1, 2] [5, 6]);
    println (prod [1, 2] []);
    println (prod [] []);
    println (map id []);