No recursion-schemes
pacote, os seguintes tipos são definidos:
newtype Fix f = Fix (f (Fix f))
newtype Mu f = Mu (forall a. (f a -> a) -> a)
Eles são isomórficos? Se sim, como você prova isso?
No recursion-schemes
pacote, os seguintes tipos são definidos:
newtype Fix f = Fix (f (Fix f))
newtype Mu f = Mu (forall a. (f a -> a) -> a)
Eles são isomórficos? Se sim, como você prova isso?
Mu f < Fix f < Nu f
Fix
-to-Mu
é essencialmentecata
, enquantoMu
-to-Fix
ému2fix (Mu x) = x Fix
. A parte complicada é provar que essas são inversas mútuas, explorando a parametridade.Fix
isso não representável porMu
? O ISTMFix
deve ser o menor (intuitivamente porque é uma "estrutura de dados" e não pode conterRespostas:
Sim, eles são isomórficos em Haskell. Consulte Qual é a diferença entre Fix, Mu e Nu no pacote do esquema de recursão de Ed Kmett para algumas observações adicionais.
Vamos começar definindo funções para realizar as conversões:
Para mostrar que essas funções testemunham um isomorfismo, devemos mostrar que:
De
Fix
e para trásUma das direções do isomorfismo sai um pouco mais direta do que a outra:
A passagem final acima,,
cata Fix t = t
pode ser verificada através da definição decata
:cata Fix t
, então éFix (fmap (cata Fix) (unfix t))
. Podemos usar a indução para mostrar que deve sert
, pelo menos para um finitot
(fica mais sutil com estruturas infinitas - veja o adendo no final desta resposta). Há duas possibilidades a considerar:unfix t :: f (Fix f)
está vazio, sem posições recursivas para cavar. Nesse caso, deve ser igual afmap absurd z
para algunsz :: f Void
, e assim:unfix t
não está vazio. Nesse caso, pelo menos sabemos quefmap (cata Fix)
não podemos fazer nada além de aplicarcata Fix
nas posições recursivas. A hipótese de indução aqui é que isso deixará essas posições inalteradas. Temos então:(Por fim,
cata Fix = id
é um corolário deFix :: f (Fix f) -> Fix x
ser uma álgebra inicial F. Recorrer diretamente a esse fato no contexto dessa prova provavelmente seria um atalho demais.)De
Mu
e para trásDado
muToFix . fixToMu = id
, para provar quefixToMu . muToFix = id
basta provar:aquele
muToFix
é injetivo, ouisso
fixToMu
é subjetivo.Vamos pegar a segunda opção e revisar as definições relevantes:
fixToMu
ser adjetivo significa, então, que, dado qualquer específicoFunctor
f
, todas as funções do tipoforall a. (f a -> a) -> a
podem ser definidas como\alg -> cata alg t
, para alguns específicost :: Fix f
. A tarefa, então, torna-se catalogar oforall a. (f a -> a) -> a
funções e verificar se todas elas podem ser expressas nessa forma.Como podemos definir uma
forall a. (f a -> a) -> a
função sem nos apoiarmosfixToMu
? Seja como for, deve envolver o uso daf a -> a
álgebra fornecida como argumento para obter uma
resultado. A rota direta seria aplicá-la a algumf a
valor. Uma ressalva importante é que, comoa
é polimórfico, devemos ser capazes de conjurar o referidof a
valor para qualquer escolhaa
. Essa é uma estratégia viável desde quef
existam valores. Nesse caso, podemos fazer:Para tornar a notação mais clara, vamos definir um tipo para itens que podemos usar para definir
forall a. (f a -> a) -> a
funções:Além da rota direta, há apenas uma outra possibilidade. Dado que
f
é aFunctor
, se de alguma forma tivermos umf (Moo f)
valor, podemos aplicar a álgebra duas vezes, sendo a primeira aplicação sob af
camada externa , viafmap
efromMoo
:Tendo em conta que nós também podemos fazer
forall a. (f a -> a) -> a
fora def (Moo f)
valores, faz sentido adicioná-los como um caso deMoo
:Por conseguinte,
fromLayered
pode ser incorporado afromMoo
:Observe que, ao fazer isso, passamos sorrateiramente da aplicação
alg
sob umaf
camada para a aplicação recursivaalg
sob um número arbitrário def
camadas.Em seguida, podemos observar que um
f Void
valor pode ser injetado noLayered
construtor:Isso significa que na verdade não precisamos do
Empty
construtor:E o
Empty
casofromMoo
? A única diferença entre os dois casos é que, noEmpty
caso, temos emabsurd
vez de\moo -> fromMoo moo alg
. Como todas asVoid -> a
funções sãoabsurd
, também não precisamos de umEmpty
caso separado :Um possível ajuste cosmético é inverter os
fromMoo
argumentos, para que não seja necessário escrever o argumentofmap
como lambda:Ou, mais pointfree:
Neste ponto, uma segunda olhada em nossas definições sugere que alguma renomeação esteja em ordem:
E aí está: todas as
forall a. (f a -> a) -> a
funções têm a forma\alg -> cata alg t
para algumast :: Fix f
. Portanto,fixToMu
é surjetivo, e temos o isomorfismo desejado.Termo aditivo
Nos comentários, uma questão pertinente foi levantada sobre a aplicabilidade do argumento de indução na
cata Fix t = t
derivação. No mínimo, as leis e a parametridade dos functores garantem quefmap (cata Fix)
não criarão trabalho extra (por exemplo, não ampliarão a estrutura ou introduzirão posições recursivas adicionais para serem exploradas), o que justifica por que entrar nas posições recursivas é tudo o que assuntos na etapa indutiva da derivação. Sendo assim, set
for uma estrutura finita, o caso base de um vaziof (Fix t)
será finalmente alcançado e tudo ficará claro. Se permitirmost
ser infinitos, no entanto, podemos continuar descendo sem parar,fmap
depoisfmap
depoisfmap
, sem nunca chegar ao caso base.A situação com estruturas infinitas, no entanto, não é tão terrível quanto possa parecer à primeira vista. A preguiça, que é o que viabiliza estruturas infinitas, em primeiro lugar, permite consumir estruturas infinitas preguiçosamente:
Enquanto a sucessão de posições recursivas se estende infinitamente, podemos parar a qualquer momento e obter resultados úteis nos
ListF
contextos funcionais circundantes . Vale a pena repetir que esses contextos não são afetadosfmap
e, portanto, qualquer segmento finito da estrutura que possamos consumir não será afetado porcata Fix
.Este adiamento preguiça reflete como, como mencionado em outro lugar nesta discussão, preguiça desaba a distinção entre os pontos fixos
Mu
,Fix
eNu
. Sem preguiça,Fix
não basta codificar a corecursão produtiva e, portanto, precisamos mudar paraNu
o maior ponto fixo. Aqui está uma pequena demonstração da diferença:fonte
cata Fix t = t
? Assumindo queFix f
é a álgebra inicial,f
parece um atalho. (A prova vinculada da resposta relacionada parece ignorar isso usando a parametridade nos dois sentidos.)fixToMu
subjetividade. "se queremos definir uma função a. (fa -> a) -> do zero" Não é isso que queremos. Em vez disso, vamosk :: forall a. (f a -> a) -> a
, precisamos mostrar issok = \alg -> cata alg t
para algunst
.cata Fix
, temoscata Fix = Fix . fmap (cata Fix) . unfix
. Set
não tiver posições recursivas,fmap (cata Fix)
não fará nada, e assimcata Fix t = Fix (unfix t) = t
. Se tiver posições recursivas, tudo ofmap (cata Fix)
que fará será aplicarcata Fix
a elas, o que parece suficiente para resolver o assunto por indução.k
deve ser obtido aplicando diretamente a álgebra (para a qual umf Void
valor é necessário) ou usando-afmap
para aplicá-la recursivamente, e ambos os casos podem ser expressa na forma \ alg -> cata alg t`. Portanto, acredito que fiz o que você sugere, embora "do zero" possa não ter sido a melhor escolha de palavras para descrevê-lo.cata Fix t = t
derivação (de fato, dadas as semelhanças entre os dois argumentos, agora acho que tê-lo apresentado ajuda a preparar o terreno para a segunda parte da resposta) . Obrigado por destacar esses pontos para melhorias.