[Haskell-cafe] Making type-incompatible strategies interchangeable
Jacek Generowicz
jacek.generowicz at cern.ch
Sat Dec 18 02:17:30 CET 2010
# 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())
More information about the Haskell-Cafe
mailing list