1
(修訂版)如何從IO單子的值ASIGN到RankNType合格構造
我已使用Free Monad到一個通用的數據存儲的接口。我想將運行時用戶選擇的特定解釋器(:: DataStore a - > IO a)與其他一些信息一起放入狀態monad中。我似乎無法將任何東西放入數據結構的這個字段中。
我如何把一個值定義爲較高級別類型的字段?
下面是一個最小的例子:
{-# 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
當我嘗試這樣做GHC抱怨說:
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
[...]
UPDATE
我原來的小例子,是最小的。一些進一步的實驗表明,當我需要在IO monad中加載接口時出現問題,所以我可以閱讀命令行選項。我已更新示例以包含該問題。知道這一點,我可能能夠圍繞它進行編碼。
有趣的GHCI告訴我,IO (DataStore a -> IO a)
型函數的結果是DataStore GHC.Prim.Any -> IO GHC.Prim.Any
,這不是我所期望的。
也許我缺少明顯的東西,但你爲什麼不只是做'數據ProgramState A = {PS .. 。,storageInterface :: DataStore a - > IO a}'?我不認爲這打破了你粘貼在這裏的任何代碼... – Alec
無法複製該問題。 – Alec
Alec'不在範圍內:輸入變量'a' –