¿Por qué no puedo proporcionar una firma de tipo explícita a una acción ST local enlazada con let?
Tengo el siguiente programa simplificado que funciona bien:
{-# LANGUAGE Rank2Types #-}
module Temp where
import Control.Monad.ST
import Control.Monad
import Data.STRef
mystery :: Int -> Int
mystery start =
let
run :: ST s Int
run = do
count <- newSTRef (1::Int)
loop count start
readSTRef count
in
runST run
loop :: STRef s Int -> Int -> ST s ()
loop cnt n = when (n /= 1)
(modifySTRef cnt succ >>
if n `mod` 2 == 0
then loop cnt (n `div` 2)
else loop cnt (n * 3 + 1))
Muevo la definición de loop
dentro del bloque do
para poder utilizar el contador creado en run
de la siguiente manera:
mystery :: Int -> Int
mystery start =
let
run :: ST s Int
run = do
count <- newSTRef (1::Int)
let
loop :: Int -> ST s ()
loop n = when (n /= 1)
(modifySTRef count succ >>
if n `mod` 2 == 0
then loop (n `div` 2)
else loop (n * 3 + 1))
loop start
readSTRef count
in
runST run
Esto me da el siguiente error:
No se pudo hacer coincidir el tipo ‘s1’ con ‘s’
‘s1’ es una variable de tipo rígida delimitada por
la firma de tipo de:
loop :: forall s1. Int -> ST s1 ()
en ...
‘s’ es una variable de tipo rígida delimitada por
la firma de tipo de:
run :: forall s. ST s Int
en ...
Tipo esperado: ST s1 ()
Tipo real: ST s ()
En la expresión:
...
Entiendo que s
no está permitido escapar, pero según lo que veo, ¿no debería hacerlo? Además, cuando quito la firma de tipo para loop
, el problema desaparece. Supongo que eso indica que la firma de tipo es incorrecta de alguna manera, pero es igual que antes, excepto sin el contador y no tengo idea de qué debería ser.
Cambiar el nombre de s
para que coincida o no coincida con el s
mencionado en run
no hace ninguna diferencia.
davy.ai
El problema con el mensaje de error es que la firma de tipo para
loop
es demasiado general. Cuantifica sobre todos los posibles tipos de estados1
, pero necesita tener el mismo tipo de estado querun
, que está cuantificado en la encuadernaciónlet
circundante. La función corregida se vería así:Ten en cuenta que la firma de
loop
especifica el mismo tipo de estados
que enrun
, lo que lo convierte en una encuadernación monomórfica. Esta versión corregida debería compilarse sin errores.