Como atribuir um valor da monad IO a um construtor qualificado RankNType
(ATUALIZADA)
Eu fiz uma interface usando umMônada grátis para um armazenamento de dados genérico. Quero colocar o intérprete específico (:: DataStore a -> IO a) escolhido pelo usuário em tempo de execução em uma mônada de estado, juntamente com outras informações. Parece que não consigo colocar nada nesse campo na estrutura de dados.
Como coloco um valor em um campo definido como um tipo de classificação mais alta?
Abaixo está um exemplo mínimo:
{-# LANGUAGE RankNTypes, DeriveFunctor #-}
data ProgramState = PS { -- line 3
[...]
, storageInterface :: (forall a. DataStore a -> IO a)
}
data DataStoreF next =
Create Asset ( String -> next)
| Read String ( Asset -> next)
| Update Asset ( Bool -> next)
| UpdateAll [Asset] ( Bool -> next)
| [...]
deriving Functor
type DataStore = Free DataStoreF
runMemory :: (IORef (Map String Asset)) -> DataStore a -> IO a
runMemory ms (Pure a) = return a
runMemory ms (Free Create asset next) = [...]
runMemory ms (Free Read str next) = [...]
[...]
pickStorageInterface :: IO (DataStore a -> IO a)
pickStorageInterface = do
opts <- parseOptions
case (storage opts) of
MemoryStorage ->
ms <- readAssetsFromDisk
return $ runMemory ms
SomeOtherStorage -> [...]
restOfProgram :: StateT ProgramState IO
restOfProgram = [...]
main = do
si <- pickStorageInterface
let programState = PS { storageInterface = si} -- line 21
evalState restOfProgram programState
Quando tento fazer isso, o GHC reclama que:
Main.hs: << Line 21 >>
Couldn't match type `a0' with `a'
because type variable `a' would escape its scope
This (rigid, skolem) type variable is bound by
a type expected by the context: DataStore a -> IO a
at Main.hs <<line 3>>
Expected type: DataStore a -> IO a
Actual type: DataStore a0 -> IO a0
In the `storageInterface' field of a record
[...]
ATUALIZAR
Meu exemplo mínimo original foi o mínimo. Algumas experiências adicionais mostram que o problema surge quando preciso carregar a interface em uma mônada IO para que eu possa ler as opções da linha de comando. Atualizei o exemplo para incluir esse problema. Sabendo disso, talvez seja possível codificá-lo.
GHCI interessante me diz que os resultados de uma função do tipoIO (DataStore a -> IO a)
éDataStore GHC.Prim.Any -> IO GHC.Prim.Any
o que não é o que eu esperava.