Anthony C. Hay

31 July 2012

Logo, Scheme, C++

Abstract

I re-implement a tiny Logo function in Scheme and C++; it's of no interest to anyone but me.

Logo

Brian Harvey, lecturer at UC Berkeley and coauthor of the book Simply Scheme, presented a little fragment of Logo. Here it is:

to choices :menu [:sofar []]
if emptyp :menu [print :sofar stop]
foreach first :menu [(choices butfirst :menu sentence :sofar ?)]
end

The Logo function may be called like this:

choices [[small medium large]
         [vanilla [ultra chocolate] lychee [rum raisin] ginger]
         [cone cup]]

small vanilla cone
small vanilla cup
small ultra chocolate cone
small ultra chocolate cup
small lychee cone
small lychee cup
small rum raisin cone
small rum raisin cup
small ginger cone
small ginger cup
medium vanilla cone
medium vanilla cup
medium ultra chocolate cone
medium ultra chocolate cup
medium lychee cone
medium lychee cup
medium rum raisin cone
medium rum raisin cup
medium ginger cone
medium ginger cup
large vanilla cone
large vanilla cup
large ultra chocolate cone
large ultra chocolate cup
large lychee cone
large lychee cup
large rum raisin cone
large rum raisin cup
large ginger cone
large ginger cup

Brian said "let's see you do that in four lines of Java, matey boy" (words to that effect). So I gave it a go...

Scheme

Here is my best effort to implement the same functionality in Scheme:

(define (choices menu)
    (define (print x)
        (display x)(newline))

    (define (sentence a b)
        (if (= (string-length a) 0)
            b
            (string-append a " " b)))

    (define (choices-helper menu sofar)
        (if (null? menu)
            (print sofar)
            (for-each (lambda (x) (choices-helper (cdr menu) (sentence sofar x))) (car menu)) ))

    (choices-helper menu ""))

Please note that I am a Scheme novice.

My solution only works if it is acceptable to change the input slightly to avoid parsing square brackets. Also I avoided symbol->string by making the items strings. Here is the function running under DrRacket:

(choices '(("small" "medium" "large")
           ("vanilla" "ultra chocolate" "lychee" "rum raisin" "ginger")
           ("cone" "cup")))
small vanilla cone
small vanilla cup
small ultra chocolate cone
small ultra chocolate cup
small lychee cone
small lychee cup
small rum raisin cone
small rum raisin cup
small ginger cone
small ginger cup
medium vanilla cone
medium vanilla cup
medium ultra chocolate cone
medium ultra chocolate cup
medium lychee cone
medium lychee cup
medium rum raisin cone
medium rum raisin cup
medium ginger cone
medium ginger cup
large vanilla cone
large vanilla cup
large ultra chocolate cone
large ultra chocolate cup
large lychee cone
large lychee cup
large rum raisin cone
large rum raisin cup
large ginger cone
large ginger cup

C++

And here is a way to do it in C++:

#include <iostream>
#include <string>

void choices(const char * * menu, const std::string & sofar = "")
{
    if (*menu == 0)
        std::cout << sofar << '\n';
    else {
        const char * * rest = menu;
        while (*rest++) // skip to the next group
            ;
        for (; *menu; ++menu)
            choices(rest, sofar.empty() ? *menu : sofar + ' ' + *menu);
    }
}

int main()
{
    const char * menu[] = {
        "small", "medium", "large", 0,
        "vanilla", "ultra chocolate", "lychee", "rum raisin", "ginger", 0,
        "cone", "cup", 0,
        0
    };

    choices(menu);
}

C:\>choices.exe
small vanilla cone
small vanilla cup
small ultra chocolate cone
small ultra chocolate cup
small lychee cone
small lychee cup
small rum raisin cone
small rum raisin cup
small ginger cone
small ginger cup
medium vanilla cone
medium vanilla cup
medium ultra chocolate cone
medium ultra chocolate cup
medium lychee cone
medium lychee cup
medium rum raisin cone
medium rum raisin cup
medium ginger cone
medium ginger cup
large vanilla cone
large vanilla cup
large ultra chocolate cone
large ultra chocolate cup
large lychee cone
large lychee cup
large rum raisin cone
large rum raisin cup
large ginger cone
large ginger cup

Again, I've assumed it is acceptable to change the input data to a native representation.

Big conclusion

So that's 4 lines of Logo, 12 lines of Scheme and 9 lines of C++. Depending on how you count the lines. (I don't count blank lines, comment-only lines or lines containing only an opening or closing curly brace.) Therefore, Logo is better than C++ and C++ is better than Scheme. ("You're joking, right?")

index of blog posts

No comments:

Post a Comment