OO Traducción de la interfaz a Haskell

Mi problema específico en realidad no se trata de la traducción general de una interfaz OO a Haskell. Este es el mejor título que se me ocurrió. Sin embargo, estoy seguro de que mi problema se origina en una comprensión aún pobre del código de modelado con Haskell y una mentalidad aún ubicada en la tierra de los paradigmas de OO (todavía eres un principiante de haskell, ya ves).

Estoy escribiendo una simulación Mastermind (variación) para probar la idoneidad de varias estrategias Mastermind. De hecho, ya lo hice enJav y Lua y por lo tanto esteHaskell versión es solo un ejercicio para mí para aprender a programar en Haskell. Puede consultar el archivo Léame de la versión Lua / Java si está interesado en lo que estoy tratando de lograr al final.

Pero ahora para mi problema concreto (en resumen y en términos de OO): quiero proporcionar una interfaz para estrategias para que pueda poner indistintamente una estrategia que se adhiera a esa interfaz en la recursión de simulación (loop) y después de que haya terminado reciba algo datos sobre el desempeño de la estrategia. Además, quiero permitir que la estrategia mantenga un estado arbitrario y no me importa qué tipo de estado mantiene cada estrategia. Pero exactamente esta decisión, que es realmente esencial, complicó todo. Otro requisito, que condujo concretamente al problema que se describe a continuación, es que se puede proporcionar un nombre de estrategia como argumento de línea de comando y luego la simulación se ejecuta con esa estrategia específica.

Al principio, consideré una clase de tipo apropiada para estos requisitos, pero después de no haber tenido una idea real de cómo modelar el código de esta manera, abandoné la idea. Luego decidí un ADT, lo usé desde entonces y llegué relativamente lejos con el código, hasta ahora.

Entonces, la pregunta superficial es cómo resolver el problema que proporciono a continuación. La pregunta más profunda es cómo modelar mejor mis requisitos para una interfaz con estado arbitrario en Haskell.

Aquí hay un extracto reducido y adaptado de mi código:

-- reduced & simplified example
import Control.Monad.State

type Code = [Int]

data Answer = Answer { 
    blacks :: Int, 
    whites :: Int 
    } deriving (Eq, Show)

-- As you can see I decided for a type variable a that
-- represents the arbitrary state a strategy might carry
-- around. I wonder if this is the right way to do it.
-- | This is the interface for a strategy. A strategy must provide a method 
-- that, given a mastermind answer, returns the next guess, an initial state 
-- and the very first guess.
data Strategy a = Strategy {
    firstGuess :: Int -> Code,
    initialize :: Int -> a, -- a "constructor" in disguise
    guess      :: Answer -> State a Code
    }

dummy = Strategy {
    firstGuess   = firstGuess',
    initialize   = initialize', 
    guess        = guess'
    }

-- | The very first guess is always T0,T1,...,Tx, where x is the code length.
firstGuess' :: Int -> Code
firstGuess' length = [0..length-1]

-- | Memorize the code length
initialize' :: Int -> Int
initialize' = id

-- | Always return the same guess
guess' :: Answer -> State Int Code
guess' = const $ liftM firstGuess' get

-- HERE IS THE PROBLEM
-- I need this function since I'll get the name of a strategy
-- as a string from the command line and need to dispatch the
-- correct strategy to the simulation. Note, that there would
-- be of course more pattern matches for different strategies
-- with different accompanying states a.
nameToStrategy :: String -> Strategy a
nameToStrategy "dummy" = dummy

Ejecutar el archivo produce el siguiente mensaje de error:

Prelude> :l Problem.hs
[1 of 1] Compiling Main             ( Problem.hs, interpreted )

Problem.hs:37:25:
    Couldn't match expected type `a' against inferred type `Int'
      `a' is a rigid type variable bound by
          the type signature for `nameToStrategy' at Problem.hs:36:37
      Expected type: Strategy a
      Inferred type: Strategy Int
    In the expression: dummy
    In the definition of `nameToStrategy':
        nameToStrategy "dummy" = dummy
Failed, modules loaded: none.

De alguna manera puedo comprender intuitivamente el problema. El problema parece ser quenameToStrategy no puede simplemente devolver una Estrategia con algún estadoa. La variable tipo debe ser concreta, ya que si cambio el tipo denameToStrategy aString -> Strategy Int todo está bien. Pero esa no es una solución a mi problema.

Pensé que necesitaba relajar el tipo. Sin embargo, realmente no sé cómo hacerlo. Escuché sobreData.Dynamic y tipos existenciales y esos podrían ayudarme. Aún así, siento que con un mejor modelado de mi código no los necesitaría.

Edita: Después de todo, logré incorporar las sugerencias de sclv en el código y ahora es mucho mejor. El código para las estrategias es más claro ya que ya no necesito el caso especial para la primera suposición y puedo usar guardias para distinguir mejor entre el caso de una suposición correcta y una incorrecta. El manejo principal de la simulación no es tan elegante como la versión de sclv desde que pusestepState (y las funciones que usanstepState) en la IO Monad para medir el tiempo de cálculo y, por lo tanto, tener algo de "ruido de sintaxis monádica". La capacidad de simular fácilmente un par de pasos de simulación (que en realidad no era posible antes) me ayudó a encontrar un bucle infinito recursivo mutuo Ese error era extraño de entender). En general, el código se siente más discreto ahora. No hace falta decir que no necesito launsafeCoerce piratear más para enviar nombres a estrategias (o mejores "estrategias empaquetadas"). Espero que la forma funcional de pensar algún día sea algo natural para mí también.

Respuestas a la pregunta(2)

Su respuesta a la pregunta