
# Imagine an activity which may be performed either by a computer, or # by a human (alternatively, either locally, or remotely across a # network). From Haskell's type system's perspective, these two will # look completely different (most obviously, the human (or the # network) is wrapped in IO). How can they be made interchangeable ? # To demonstrate what I mean, I offer the following concrete toy # example, in Python. # It's a harness for playing the trivial higher-lower number guessing # game, with interchangeable strategies for either player. In this # example I provide two strategies (Computer / ask Human via IO) for # each role (asker and guesser). # How can this sort of interchangeability of computations which are # conceptually identical, but incompatible from the types perspective, # be expressed in Haskell? from random import randint # A simple game harness. It is given the two players, and mediates the # interaction between them. def game(asker, guesser): feedback = None count = 0 while not feedback == 0: guess = guesser(feedback) feedback = asker(guess) print "Guess: %s, Answer: %s" % (guess, feedback) count += 1 print "Got it in", count # A couple of decorators to smoothe the use of the generators which # are used to implement the players. def hide_send(generator_function): def proxy(*args, **kwds): return generator_function(*args, **kwds).send return proxy def advance(hidden_send_proxy): def proxy(*args, **kwds): send = hidden_send_proxy(*args, **kwds) send(None) return send return proxy # Artificial player who knows the secret @advance @hide_send def higher_lower_asker_C(low=0, high=100): secret = randint(low, high) guess = yield while True: guess = yield cmp(guess, secret) # Artificial player trying to guess the secret @hide_send def higher_lower_guesser_C(low=0, high=100): while True: guess = (low + high) // 2 feedback = yield guess if feedback < 0: low = guess else: high = guess # Interface to human who knows the secret @advance @hide_send def higher_lower_asker_H(): guess = yield # No feedback before first guess while True: print "My guess is", guess print "Please reply with one letter: is my guess (l)ow, (c)orrect or (h)igh ?" guess = yield {'l':-1, 'c':0, 'h':1 }[raw_input()] # Interface to human trying to guess @hide_send def higher_lower_guesser_H(): while True: feedback = yield input("What is your guess? ") print {-1:"Too low.", 0:"Correct!", +1:"Too high."}[feedback] # Given the above preparation, the game can now be played in all 4 # possible permutations of Computer/Human vs. Computer/Human. game(higher_lower_asker_C(), higher_lower_guesser_C()) game(higher_lower_asker_H(), higher_lower_guesser_C()) game(higher_lower_asker_C(), higher_lower_guesser_H()) game(higher_lower_asker_H(), higher_lower_guesser_H())