En el recursion-schemes
paquete se definen los siguientes tipos:
newtype Fix f = Fix (f (Fix f))
newtype Mu f = Mu (forall a. (f a -> a) -> a)
¿Son isomorfos? Si es así, ¿cómo lo demuestras?
En el recursion-schemes
paquete se definen los siguientes tipos:
newtype Fix f = Fix (f (Fix f))
newtype Mu f = Mu (forall a. (f a -> a) -> a)
¿Son isomorfos? Si es así, ¿cómo lo demuestras?
Mu f < Fix f < Nu f
Fix
-to-Mu
es esencialmentecata
, mientras queMu
-to-Fix
esmu2fix (Mu x) = x Fix
. La parte difícil es demostrar que estos son inversos mutuos, explotando la parametricidad.Fix
que no es representableMu
? ISTMFix
debería ser el más pequeño (intuitivamente porque es una "estructura de datos" y no puede contener fondos)Respuestas:
Sí, son isomórficos en Haskell. Vea ¿Cuál es la diferencia entre Fix, Mu y Nu en el paquete de esquema de recursión de Ed Kmett para algunos comentarios adicionales?
Comencemos definiendo funciones para realizar las conversiones:
Para mostrar que esas funciones son testigos de un isomorfismo, debemos mostrar que:
Desde
Fix
y hacia atrásUna de las direcciones del isomorfismo es algo más directa que la otra:
El pasaje final anterior,
cata Fix t = t
se puede verificar a través de la definición decata
:cata Fix t
, entonces, esFix (fmap (cata Fix) (unfix t))
. Podemos usar la inducción para mostrar que debe sert
, al menos para un finitot
(se vuelve más sutil con estructuras infinitas; vea el apéndice al final de esta respuesta). Hay dos posibilidades a considerar:unfix t :: f (Fix f)
está vacío, no tiene posiciones recursivas para cavar. En ese caso, debe ser igualfmap absurd z
para algunosz :: f Void
, y por lo tanto:unfix t
no está vacío. En ese caso, al menos sabemos quefmap (cata Fix)
no puede hacer nada más que aplicarcata Fix
en las posiciones recursivas. La hipótesis de inducción aquí es que hacerlo dejará esas posiciones sin cambios. Entonces tenemos:(En última instancia,
cata Fix = id
es un corolario deFix :: f (Fix f) -> Fix x
ser un álgebra F inicial. Recurrir directamente a ese hecho en el contexto de esta prueba probablemente sería demasiado atajo).Desde
Mu
y hacia atrásDado
muToFix . fixToMu = id
, para demostrar quefixToMu . muToFix = id
es suficiente probar:eso
muToFix
es inyectivo, oque
fixToMu
es sobreyectiva.Tomemos la segunda opción y revisemos las definiciones relevantes:
fixToMu
ser surjective, entonces, significa que, dado cualquier específicoFunctor
f
, todas las funciones de tipoforall a. (f a -> a) -> a
pueden definirse como\alg -> cata alg t
, para algunos específicost :: Fix f
. La tarea, entonces, se convierte en catalogar lasforall a. (f a -> a) -> a
funciones y ver si todas ellas pueden expresarse de esa forma.¿Cómo podríamos definir una
forall a. (f a -> a) -> a
función sin apoyarnosfixToMu
? No importa qué, debe implicar el uso delf a -> a
álgebra suministrada como argumento para obtener una
resultado. La ruta directa lo estaría aplicando a algúnf a
valor. Una advertencia importante es que, dado quea
es polimórfico, debemos ser capaces de conjurar dichof a
valor para cualquier elección dea
. Esa es una estrategia factible siempref
que existan valores. En ese caso, podemos hacer:Para aclarar la notación, definamos un tipo de cosas que podemos usar para definir
forall a. (f a -> a) -> a
funciones:Además de la ruta directa, solo hay otra posibilidad. Dado que
f
es unFunctor
, si de alguna manera tenemos unf (Moo f)
valor, podemos aplicar el álgebra dos veces, la primera aplicación está debajo de laf
capa externa , víafmap
yfromMoo
:Teniendo en cuenta que también podemos hacer
forall a. (f a -> a) -> a
def (Moo f)
los valores, que tiene sentido para agregarlos como un caso deMoo
:En consecuencia,
fromLayered
se puede incorporar afromMoo
:Tenga en cuenta que, al hacerlo, hemos pasado furtivamente de la aplicación
alg
bajo unaf
capa a la aplicación recursivaalg
bajo un número arbitrario def
capas.A continuación, podemos observar
f Void
que se puede inyectar un valor en elLayered
constructor:Eso significa que en realidad no necesitamos el
Empty
constructor:¿Qué pasa con el
Empty
casofromMoo
? La única diferencia entre los dos casos es que, en elEmpty
caso, tenemos enabsurd
lugar de\moo -> fromMoo moo alg
. Como todas lasVoid -> a
funciones sonabsurd
, tampoco necesitamos unEmpty
caso separado :Un posible ajuste cosmético es voltear los
fromMoo
argumentos, por lo que no necesitamos escribir el argumentofmap
como lambda:O, más libre de puntos:
En este punto, una segunda mirada a nuestras definiciones sugiere que es necesario cambiar el nombre:
Y ahí está: todas las
forall a. (f a -> a) -> a
funciones tienen la forma\alg -> cata alg t
para algunost :: Fix f
. Por lo tanto,fixToMu
es surjective, y tenemos el isomorfismo deseado.Apéndice
En los comentarios, se planteó una pregunta pertinente sobre la aplicabilidad del argumento de inducción en la
cata Fix t = t
derivación. Como mínimo, las leyes fundadoras y la paramétrica aseguran quefmap (cata Fix)
no creará trabajo adicional (por ejemplo, no aumentará la estructura ni introducirá posiciones recursivas adicionales para profundizar), lo que justifica por qué entrar en las posiciones recursivas es todo lo que importa en el paso inductivo de la derivación. Siendo así, si set
trata de una estructura finita, el caso base de un vacíof (Fix t)
finalmente se alcanzará, y todo está claro.t
Sin embargo, si permitimos ser infinitos, podemos seguir descendiendo sin cesar,fmap
despuésfmap
despuésfmap
, sin llegar nunca al caso base.Sin embargo, la situación con estructuras infinitas no es tan horrible como podría parecer al principio. La pereza, que es lo que hace viables las estructuras infinitas en primer lugar, nos permite consumir estructuras infinitas perezosamente:
Si bien la sucesión de posiciones recursivas se extiende infinitamente, podemos detenernos en cualquier punto y obtener resultados útiles de los
ListF
contextos funerarios circundantes . Tales contextos, vale la pena repetir, no se ven afectadosfmap
, por lo que cualquier segmento finito de la estructura que podamos consumir no se verá afectadocata Fix
.Este aplazamiento refleja cómo la pereza, como se menciona en esta discusión otra parte, la pereza colapsa la distinción entre los puntos fijos
Mu
,Fix
yNu
. Sin holgazanería,Fix
no es suficiente para codificar una curión productiva y, por lo tanto, tenemos que cambiar alNu
mayor punto fijo. Aquí hay una pequeña demostración de la diferencia:fuente
cata Fix t = t
? Asumir queFix f
es el álgebra inicialf
parece un poco un atajo. (La prueba vinculada a la respuesta relacionada parece evitar esto al usar la parametricidad en ambos sentidos.)fixToMu
la surjectivity. "si queremos definir un principio a. (fa -> a) -> una función desde cero" Eso no es lo que queremos. En cambio, vamosk :: forall a. (f a -> a) -> a
, tenemos que mostrar esok = \alg -> cata alg t
para algunost
.cata Fix
, tenemoscata Fix = Fix . fmap (cata Fix) . unfix
. Sit
no tiene posiciones recursivas,fmap (cata Fix)
no hará nada, y asícata Fix t = Fix (unfix t) = t
. Si tiene posiciones recursivas, todofmap (cata Fix)
lo que hará será aplicarlescata Fix
, lo que parece suficiente para resolver el problema por inducción.k
debe obtenerse aplicando directamente el álgebra (para el quef Void
se necesita un valor) o utilizandofmap
para aplicarlo recursivamente, y ambos casos pueden expresarse en la forma \ alg -> cata alg t`. Así que creo que he hecho lo que usted sugiere, aunque "desde cero" podría no haber sido la mejor opción de palabras para describirlo.cata Fix t = t
derivación (de hecho, dadas las similitudes entre los dos argumentos, ahora siento que presentarlo ayuda a preparar el terreno para la segunda parte de la respuesta) . Gracias por resaltar esos puntos para mejorar.