Como escrever uma função haskell sem IO no tipo sig, ocultando alterações de 'estado'
Pergunta
Eu escrevi uma função em haskell que usa alguns parâmetros como Word32, String (ignorar currying) e gera IO Word32.Agora, este é um função no verdadeiro sentido: para as mesmas entradas, a saída será sempre a mesma.Não tem efeitos colaterais.A razão pela qual a função retorna IO Word32 em vez de Word32 é que a função atualiza muitos registradores de deslocamento de feedback linear de 32 bits (lfsr) e outros registradores várias vezes em um loop para calcular a saída final do Word32.
Minha pergunta é esta:Dado que esta função efetivamente não tem efeitos colaterais, é possível ocultar essas atualizações de registro dentro da implementação da função para que a função retorne Word32 e não IO Word32?Se sim, como?
Solução
Sim!Haskell pode fazer isso.
A mônada ST
Se você realmente usa estados mutáveis (registros), que estão totalmente ocultos do observador fora da função, então você está em a mônada ST, uma mônada apenas para efeitos de memória.Você entra no mundo ST via runST
, e quando você sai da função, é garantido que todos os efeitos não estarão visíveis.
É precisamente o ambiente computacional certo para trabalhar com estado local e mutável.
Estado puramente funcional:a mônada do Estado
Se, no entanto, você não estiver realmente alterando registros ou células, mas sim atualizando um valor puramente funcional muitas vezes, um ambiente mais simples estará disponível: a mônada do Estado.Isto não permite estado mutável, mas dá uma ilusão de estado local.
IO e inseguroPerformIO
Finalmente, se você tiver efeitos locais e mutáveis, como no ST
mônada, mas por algum motivo ou outro, você precisará de operações IO nesse estado (como por meio de uma chamada FFI), poderá simular o ST
mônada, com quase a mesma segurança, usando unsafePerformIO
, em vez de runST
, para introduzir um ambiente IO local.Como a mônada IO não possui tipos legais para impor a abstração, você precisará garantir manualmente que os efeitos colaterais não serão observáveis.
Outras dicas
Se você importou essa função usando o FFI, basta remover o IO
do tipo de retorno.Caso contrário, use unsafePerformIO :: IO a -> a
de System.IO.Unsafe
.Observe que esta função é uma das funções mais perigosas em Haskell.Não o use se não tiver certeza das consequências.Mas para o seu propósito, parece bom.
Sim, este seria um uso legítimo de insensível. Mas é só ok se você tem certeza de que não há efeitos visíveis.