2011-01-08 14 views
6

Me gustaría tener una función como:¿Hay alguna forma sensata de descomprimir la mónada de estado?

unzipState :: (MonadState s m) => m (a, b) -> (m a, m b) 

que tendría un cálculo (stateful) que devuelve una tupla, y volvería dos cálculos (dependientes).

La dificultad está, por supuesto, en que la extracción de valores de uno u otro cálculo debe actualizar el estado en el otro.

Un útil (y motivador) aplicación es la mónada aleatoria, expresado como

{-# LANGUAGE Rank2types #-} 
import qualified System.Random as SR 
import Control.Monad.State 

type Random a = forall r. (State RandomGen r) => State r a 

Y digamos que usted tiene:

normal :: Random Double 
-- implementation skipped 

correlateWith :: Double -> Random (Double, Double) -> Random (Double, Double) 
correlateWith rho w = do 
         (u, v) <- w 
         return $ (u, p * u + (1 - p * p) * v) 

sería muy natural a ser capaz de escribir:

let x = normal 
    y = normal 
    (u, v) = unzipState $ correlateWith 0.5 $ liftM2 (,) x y 
    ... now I am able to perform computation on u and v as correlated random variables 

¿Hay una manera sensata de hacerlo? Luché un poco, pero no logré llegar a nada. Hoogle tampoco fue de ayuda.

edición

Grandes respuestas me han mostrado mi problema está mal definido. Sin embargo, ¿alguien me puede explicar por qué la siguiente implementación en python (que creo que es correcta, pero no he probado mucho) no se puede traducir en Haskell (con la magia de STrefs, cierres y otras cosas, admito que no comprensión ;-)):

def unzipState(p): 
    flist, glist = [], [] 
    def f(state): 
     if not flist: 
      (fvalue, gvalue), newstate = p(state) 
      glist.insert(0, gvalue) 
      return (fvalue, newstate) 
     else: 
      fvalue = flist.pop() 
      return (fvalue, state) 
    def g(state): 
     if not glist: 
      (fvalue, gvalue), newstate = p(state) 
      flist.insert(0, fvalue) 
      return (fvalue, newstate) 
     else: 
      gvalue = glist.pop() 
      return (gvalue, state) 
    return (f, g) 

no es que yo estoy diciendo que el código de estado se puede traducir en Haskell, pero me siento como la comprensión qué y cuando (incluso en un ejemplo) que no se puede hacer lo haría mejorar mi comprensión mucho.

Edit2

Ahora bien, es claro como el cristal. Las funciones f y g obviamente no son puras, ya que su salida no depende únicamente del valor del estado.

¡Gracias nuevamente!

Respuesta

5

Es imposible para construir una función general unzipState que hace lo que quiere, aunque solo sea porque probablemente no puede proporcionar una especificación formal para el efecto deseado. En otras palabras, suponga que ha implementado alguna función unzipState. ¿Cómo sabes que es correcto? Debería probar que satisface ciertas leyes/ecuaciones, pero el problema aquí es encontrar estas leyes en primer lugar.


Aunque creo que entiendo lo que quiere hacer, la mónada Random también hace evidente por qué no se puede hacer. Para ver esto, usted tiene que deshacerse de la aplicación concreta type Random a = ... y considerar la interpretación abstracta dada por

v :: Random a significa que v es una distribución probabilidad de valores de tipo a

El "atar" la operación (>>=) :: Random a -> (a -> Random b) -> Random b es simplemente una forma de construir una nueva distribución de probabilidad a partir de una distribución de probabilidad antigua.

Ahora, esto significa que unzipState simplemente devuelve un par de distribuciones de probabilidad, que se pueden usar para construir otras distribuciones de probabilidad. El punto es que mientras que la sintaxis do parece muy sugestiva, pero no muestra las variables aleatorias, simplemente calcula las distribuciones de probabilidad. Las variables aleatorias se pueden correlacionar, pero las distribuciones de probabilidad no se pueden correlacionar.


Tenga en cuenta que es posible crear una mónada diferente RandomVariable a que corresponda a variables aleatorias. Sin embargo, debe arreglar el espacio de muestra Ω por adelantado. La aplicación es

type RandomVariable a = Ω -> a 



Si se desea que ambas variables aleatorias y la posibilidad de ampliar el espacio de muestra de forma automática, es probable que tenga dos operaciones de enlace

bind1 :: Random Ω a -> (a -> Random Ω b) -> Random Ω b 
bind2 :: Random Ω1 a -> (a -> Random Ω2 b) -> Random (Ω1,Ω2) b 

y algunos dependientes escriba magia para hacer frente a la proliferación de productos como (Ω1,(Ω2,Ω3)).

+0

No creo que (Random a) realmente se pueda interpretar como distribuciones de probabilidad porque en ese caso, debe ser capaz de definir omega como un espacio probalizado, lo cual es bastante difícil. Además, no es porque los dos objetos de Random a tengan la misma distribución que son iguales (toma dos u = uniforme; v = uniforme, no tienes u = v). Una interpretación más humilde es entenderla como realizaciones (más específicamente, como funciones que operan en realizaciones) de variables aleatorias, que deberían ser isomórficas para las transmisiones, por lo que creo que la operación de descompresión está bien definida). – LeMiz

+0

No. Si 'u = uniform :: Random A' y' v = uniform :: Random A', entonces es trivialmente cierto que 'u = v = uniform'. Tenga en cuenta que aquí hay dos nociones diferentes: variables aleatorias derivadas de un espacio de muestra Ω y colecciones de valores de tipo 'a' ponderados con una probabilidad (= distribución de probabilidad). Su mónada 'Random a' corresponde a la última, no a la primera. También es posible implementarlo como 'Random a = [(a, Probability)]'. [Me temo que es un poco complicado discutir esto sin una formalización de la mónada 'Random a' y el efecto particular que estás buscando.] –

+0

estás perfectamente en el punto de igualdad, estaba confundido. Gracias ! – LeMiz

3

No tengo muy claro cómo te gustaría que esto funcione, ya que correlateWith funciona en una tupla, ¿qué significado tendrían las variables correlacionadas independientemente? Digamos que hace esto:

let x = normal 
    y = normal 
    (u, v) = unzipState $ correlateWith 0.5 $ liftM2 (,) x y 
in do u1 <- u 
     v1 <- v 
     u2 <- u 
     u3 <- u 
     -- etc... 

Qué relación debe existir entre u1, u2 y u3?

Además, una "variable aleatoria" como esta se puede convertir en una secuencia perezosa infinita de manera directa. ¿Cuál sería el significado de lo siguiente?

let x = normal 
    y = normal 
    (u, v) = unzipState $ correlateWith 0.5 $ liftM2 (,) x y 
in do vs <- generateStream v 
     u1 <- u 
     if someCondition u1 then u else return u1 
     -- etc... 

Debido a que el número de valores muestreados de u cambios basados ​​en u1, esto parece sugerir que el valor no monádico con destino a vs sería retroactiva dependerá de alguna manera en u1 así, que suena sospechosamente a la clase de espeluznante acción a una distancia que Haskell evita.

Me atrevo a adivinar que lo que está tratando de lograr no se puede simplemente actualizar sobre una simple mónada de estado de PRNG, pero puede haber otras opciones.

+0

Supongo que la semántica sería exactamente la misma que para Streams: datos Stream a = a: (a: LeMiz

+0

en el anterior comentario, por favor, lea (u1, v1) están correlacionados en lugar de (u1, u2) están correlacionados. – LeMiz

0

Hay muchas cosas relacionadas con las mónadas bayesianas en Haskell.He aquí una referencia: http://www.randomhacks.net/articles/2007/02/22/bayes-rule-and-drug-tests

Véase también "programación no determinista perezoso puramente funcional", disponible en esta página: http://www.cs.rutgers.edu/~ccshan/

Editar: también no veo por qué no puede simplemente dar correlateWith la siguiente declaración de tipo, y ejecutarlo dentro del bloque do directamente en lugar de tratar de "empujar" el estado aleatorio dentro de un enlace de let. correlateWith :: Double -> Random Double -> Random Double -> Random (Double, Double)

+0

Es un material interesante, pero ¿puede indicarme cómo se relaciona con mi problema? – LeMiz

+0

Muestra cómo hacer mónadas de probabilidad reales, en lugar de simplemente sobrecargar aleatoriamente y fallar. – sclv

Cuestiones relacionadas