Tuesday, May 13, 2008

Is it just me?

I can do what I want in Python and I can do it in C++ but I'm having trouble doing it in Scala. (Replace A and B with HandInfo etc. from the previous post and you get my use-case.)

Suppose we have classes A and B, functions int fa(A&) and int fb(B&), and a class env with public instance members

struct env
{
A a;
B b;
}

Define "evaluation of fa or fb in the environment provided by env x" to mean f(x.a) when f is fa and f(x.b) when f is fb.

Problem: create a type which is able to hold references to fa or fb and, given an instance of env, is able to evaluate the held function.


#include <string>
#include <iostream>

using namespace std;

// Setup for the problem.

struct A
{
int member;
};

struct B
{
std::string member;
};

struct env
{
A a;
B b;
};

int fa(A& a)
{
cout << "fa called on an A with member = " << a.member << endl;
return a.member;
}

int fb(B& b)
{
cout << "fb called on a B with member = " << b.member << endl;
return int(b.member.length());
}

// First define a generic way to extract the member of type T from
// an instance of env. Note that this is non-intrusive: whatever
// the definition of env is, if it is possible to get an A and a B
// from it, the specialisations of tselect can do so.

template <class T>
struct tselect
{
};

template <>
struct tselect<A>
{
static A& member(env& x) { return x.a; }
};

template <>
struct tselect<B>
{
static B& member(env& x) { return x.b; }
};

// Check tselect performs as intended..

void test0(env& x)
{
cout << "a is " << tselect<A>::member(x).member << endl;
cout << "b is " << tselect<B>::member(x).member << endl;
}

// Interface for a held function.

class FuncHolder
{
public:
virtual ~FuncHolder() {}

virtual int invokeInEnv(env& x) const = 0;
};

// Generic implementation. This scales well:
// if we later want to add C,D,E and F we don't
// need to write any new code here.

template <class T>
class FuncHolderImpl : public FuncHolder
{
public:
typedef int (*funcT)(T&);

funcT func_;

FuncHolderImpl(funcT func) : func_(func) {}

virtual int invokeInEnv(env& x) const
{
return func_(tselect<T>::member(x));
}
};

// Convenience function for creating FuncHolders.
// In the event that fa or fb were overloaded we'd
// have to fall back on explicitly choosing the
// type of the implementation class to construct.

template <class T>
FuncHolder* makeNewHolder(int (*func)(T&))
{
return new FuncHolderImpl<T>(func);
}

// And here it is..

int main()
{
env e;
e.a.member = 1;
e.b.member = "hello";

test0(e);

FuncHolder* fha = makeNewHolder(&fa);
FuncHolder* fhb = makeNewHolder(&fb);

fha->invokeInEnv(e);
fhb->invokeInEnv(e);

return 0;
}

When compiled and run this produces

a is 1
b is hello
fa called on an A with member = 1
fb called on a B with member = hello

Templates keep track of all the type information. They know that fa needs an A and the tselect template knows how to go off and find one.

How about Python, a language in which templates are not needed because there are no static types to worry about? We need to give it just a tiny bit of help because fa can't tell us it needs an A: it doesn't know itself.


class A:
def __init__(self, m):
self.m = m

class B:
def __init__(self, n):
self.n = n

def fa(a):
print 'fa called on a with a.m = ', a.m

def fb(b):
print 'fb called on b with b.n = ', b.n

class env:
def __init__(self, a, b):
self.a = a
self.b = b

class FuncHolder:
def __init__(self, func, argTypeKey):
self.func = func
self.argTypeKey = argTypeKey

def invokeInEnv(self, e):
return self.func(e.__dict__[self.argTypeKey])

fha = FuncHolder(fa, 'a')
fhb = FuncHolder(fb, 'b')

e = env(A(1), B('hello'))

fha.invokeInEnv(e)
fhb.invokeInEnv(e)

No doubt there are ways to make this cleaner and slicker but even as it stands it's usable and fairly concise. We give the FuncHolder a key telling it what type the function it is holding requires as an argument.

So what goes wrong when I try to write this in Scala using type parametrization? Firstly, because of type erasure, a generic FuncHolderImpl[T] can't decide what to do on the basis of the type of T because this is not known (inside the object). The only way it can change what it does is if it has an object of type T or related to it: then it can call an overridden member of some base of T to get it to do the work that varies. So we have to give it some kind of type marker (or at least that's what seemed like a possible solution).

But then we run into the second problem. Nowhere can we write code like this:

if (...)
f(e.a)
else
f(e.b)

One branch or the other won't typecheck. Making a common base doesn't work unless, for each and every function, we write a second version which takes the base but expects the right subclass and casts to it (via pattern matching).

I've tried all sorts of other permutations but for some reason which I can't quite put my finger on, this seems to be hard to do. Suggested solutions in Scala or Java are most welcome.

Looking for help with homework assignment

Bridge is a great game. I play with an 80 something y/o lady and it's good to be able to look around the room and feel like one of the young ones. (Sad too, I won't have anyone left to play with once I'm her age.)

One thing which separates the great players from the rest is the ability to count the hand: after a few rounds of cards have been played and one or two people have failed to follow suit it is often possible to tell exactly how many cards are left in each suit, in each of the hidden hands. I can't do it, it takes too much effort and concentration. And if I tried it too often in a real game, people would tell me to get a move on before the director comes and takes the cards away.

So to get practice I thought I'd play against Bridge Baron. (Nowadays there are probably much better programs out there.) Didn't work. I am so impatient with the stupid program, and hate losing to it so much, that first I forget about counting and just try to win, then I get tired and start losing (my partner's fault) and eventually give up in disgust. Sigh.

So I set myself a homework assignment: write a program which plays the cards as if we were playing a hand but doesn't know anything about trying to win so it won't sucker me into thinking about that side of it. The program allows me to say at any point how many cards are in each hand and tells me how clever I am if I get it right.

I wrote that in Python and wrote a retro gui for it using curses. All good fun. Practiced for a while. Eventually it got boring and still I wasn't much better at counting the hands.

Something was missing. Mostly in real games you get a lot of help from the bidding: declarer opened 1S so he has at least 5 of them. That means partner has at most one, so play my ace and give partner a ruff. My program was missing out on this much more satisfying aspect of counting.

Homework assignment #2: write a simple-minded bit of code to bid the hands so I can make inferences about the distribution and get much more realistic counting practice.

Actually, it's hard. (I found it hard. If anyone has any smart ideas how to make it easy..)

Here is where I started heading: each hand has a shape (4 numbers with sum 13) and a number of high-card points (hcp). That's enough to do some simple bidding with. To select an opening bid you need some rules that look a bit like this:

3 < hcp < 10 -> open pre_empt(longest)
6 < hcp < 12 and suits_maxlen == 6 -> open weak_two(longest)
16 <= hcp <=18 and !5cardmajor -> open 1NT
12 <= hcp < 21 -> open one(5cardmajor ? longest : longest-minor)
...

Lovely. And that's just the opening bid. The rules for partner to respond are different and depend very much on what was opened. The rules for the people to the left or right of the opener are different again and equally sensitive to what bidding has gone before.

So let's take a step back and see what we need. It looks like we need shape and points for the hand we're bidding (a HandInfo class), information from the auction up to this point (an Auction class) and inferences from the auction as to the shape and strength of partner's hand and the opponents (if we trust their bidding!) so a HandInferences class maybe. (Theoretically that's all derivable from the current Auction object (and the bidding system being used) but it is going to involve significant work to calculate it, so we'll make it a separate class.)

Then we'll have expressions like the ones above to define the bidding system. At each point in the auction the program will have to evaluate various boolean valued expressions to determine what bid to choose. The decision tree selected for evaluation will depend on the bidder's CurrentRole, which would be something like "opener" before anyone has bid, "responder" for the partner of the opening bidder and so on.

In our expressions each (integer valued) symbol, other than a constant, will take its value from one of the three objects of type HandInfo, Auction and HandInferences. The hcp symbol comes from the HandInfo object; a partners_suit would come from the Auction object; partners_length(suit) (a function symbol) would need to use the HandInferences object.

One more thing about the HandInferences is that we have to get them by analysing the Auction and the bidding rules. For that reason we can't simply express the rules as code: we have to be able to traverse the expression tree in one way to evaluate it and in another way to infer from the selected bid what constraints apply to hand shape and high-card points. (Code as data sounds very lisp-like and perhaps I will find I have to go there to solve my homework assignment eventually.)

There's more but let's forget about bridge now: we have an expression tree representing arithmetic and boolean values and we have objects which form part of the evaluation environment. We want certain leaves of the expression tree to take values from objects in the environment.

My first stab at doing this was in Python. The expressions were just in strings and I used eval(expr_text, environment) to evaluate them. I had to do some text parsing to analyse the expressions for computing the hand inferences and it kind of worked but it was getting to the point where eval() on strings was becoming a liability. Then I got a job and had no spare time any more so it got shelved for a while.

Two years later. I've learned a lot of about C++, JavaScript and C#. I've lurked on Artima and played with fun stuff like Ruby and Erlang. The latest language to sound exciting is Scala and I decided to resurrect my bridge bidding project and rewrite it in Scala as a way to learn the language. There is a lot to like about the language and really, I've only scratched the surface, so don't come here for a deep critique. I did run into a curious an frustrating problem though which I'll describe in my next post.

They told me to do it

so I'm doing it.

I'm going to want to post code.. lemme see now

#include <cstdio>

int main()
{
printf("hello world\n");
return 0;
}
Yay!!

Thank you to Guogang Hu.