如何将 IO monad 中的值分配给 RankNType 限定的构造函数

2023-12-08

(更新)

我使用了一个界面自由单子到通用数据存储。我想将用户在运行时选择的特定解释器(:: DataStore a -> IO a)与一些其他信息一起放入状态单子中。我似乎无法将任何内容放入数据结构的该字段中。

如何将值放入定义为更高级别类型的字段中?

下面是一个最小的例子:

{-# 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) is DataStore GHC.Prim.Any -> IO GHC.Prim.Any这不是我所期望的。


这里的问题是

pickStorageInterface :: forall a. IO (DataStore a -> IO a)

虽然我们需要(命令式)类型

pickStorageInterface :: IO (forall a. DataStore a -> IO a)

使上面的代码能够工作。唉,谓语类型现在在 GHC 中处于糟糕的状态,最好避免。

您可以使用newtype通用量化类型的包装:

newtype SI = SI { runSI :: forall a. DataStore a -> IO a }

pickStorageInterface :: IO SI
pickStorageInterface = do
  opts <- parseOptions
  case (storage opts) of
     MemoryStorage -> 
       ms <- readAssetsFromDisk 
       return $ SI $ runMemory ms
     ...

main = do
  si <- pickStorageInterface
  let programState = PS { storageInterface = runSI si}
  ...
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 IO monad 中的值分配给 RankNType 限定的构造函数 的相关文章

随机推荐

  • 当前帧的绘制时间(以秒为单位),点后仅 2 位数字

    我找不到用点后仅两位数来绘制当前帧的时间 以秒为单位 的方法 我尝试了 drawtext 它做得很好 但是它给出了或 int 秒 或带有许多数字的浮点数 Use the eif绘制文本中的函数 这可用于计算表达式的值并将其打印为指定位数的整
  • Swift:尝试使用 UISlider 控制 AVAudioPlayerNode 中的时间

    我正在使用一个AVAudioPlayerNode附加到一个AVAudioEngine播放声音 为了获取玩家的当前时间 我正在这样做 extension AVAudioPlayerNode var currentTime TimeInterv
  • UIImageView|无法识别的选择器发送到实例 | Xcode 6.4 | iOS 8.4

    我是 Xcode 的新手 我的任务是将代码从iOS 6 1 至 8 4 但是有很多不推荐使用的方法 我解决了它们 我希望如此 但现在我遇到了一个新问题 我正在使用的代码是这样的 self clientImageView sd setImag
  • 从日期选择器中隐藏日期

    目前我正在使用本机日期选择器 但我想以一种只需要月份和年份的方式更改它 如何修改这个我的代码如下 Override protected Dialog onCreateDialog int id switch id case DATE DIA
  • 删除记录

    我有一个表 user logs 其中包含以下字段 username datetimelog 样本数据 user1 2011 06 28 08 49 01 user2 2011 06 28 08 59 38 user3 2011 06 28
  • Android 应用程序开发和 Web 服务器交互

    我刚刚学习 Android 开发 所以如果这本质上有点不对劲 请原谅 我想制作一个与我的网站上的数据库交互的应用程序 从某种意义上说 这两件事将互为补充 就这样 我正在尝试找出与服务器交互的最佳方式 我不想要一个在类似浏览器的环境中的应用程
  • 如何在开始时禁用绘图中的一行?

    我想显示这些行 但有些行被禁用 就像我正常显示它然后单击其名称来取消显示 禁用该行一样 我正在使用Python visible的属性trace as legendonly 使一条线按照您描述的方式运行 下面的代码生成一个figure10行
  • Spring-batch:如何在Spring Batch中使用skip方法捕获异常消息?

    我是spring批的新手 我的问题是如何使用 spring batch 中的skip方法捕获异常 据我所知 当Spring Batch中发生一些异常时 我们可以使用skip方法来跳过它们 但是如何使用skip方法获取异常消息呢 有人建议我使
  • 使用 LINQ 解析 Amazon Marketplace XML

    我有一系列来自 Amazon 的复杂 XML 文件 显示订单报告 XML 片段如下
  • Pandas 数学运算,以列值为条件

    我需要进行一个数学运算 该运算以第二列中的值为条件 这是设置 给定一个简单的数据框 df df pd DataFrame col1 A A B np nan D C col2 2 1 9 8 7 4 col3 0 1 9 4 2 3 In
  • 简单的JQuery嵌套列表遍历问题

    我有一个问题 我确信它非常简单 但我花了几个小时试图让它工作但无济于事 我试图在单击父列表项时显示嵌套列表 这是 JQuery 这是 HTML div ul li a href Database a li ul li a href view
  • 使用 case 语句创建触发器

    我有这两个表 USERS username role id COMMISSION RATES username commission rate users username是主键 commission rates username是外键 我
  • 使用 OpenCV 处理轮廓时错误:(-215:断言失败)npoints > 0

    当我运行这段代码时 import cv2 image cv2 imread screenshoot10 jpg cv2 imshow input image image gray cv2 cvtColor image cv2 COLOR B
  • 如何使用 Bootstrap 轮播显示上一张和下一张图像

    我正在寻找的效果如下图所示 它是一个包含 3 张图像的轮播 如何使 bootstrap 轮播显示不透明度为 0 7 的左右图像 以下是我的轮播模板 div class col md 10 center block img src img y
  • 如何通过测试正确设置和拆卸我的 pytest 类?

    我正在使用 selenium 进行端到端测试 但我不知道如何使用setup class and teardown class方法 我需要设置浏览器setup class方法 然后执行一系列定义为类方法的测试 最后退出浏览器teardown
  • Xpages 脱离服务器端缓存

    这个问题可能与非常具体的 Domino 版本有关 见下文 因此我从一些技术细节开始 有问题的服务器是虚拟化的 Windows 2008 R2 64 位计算机 多米诺骨牌发布是 IBM Domino r 服务器 64 位 适用于 Window
  • python 在 true 时重复程序 [重复]

    这个问题在这里已经有答案了 我试图让我的程序在用户输入 y n 时重复 但是我对如何在这种类型的输入中使用 while true 感到困惑 下面是一些代码 again input Would you like to play again e
  • 错误 C2664 和 E0167,难倒了

    我正在参加 C 初学者的远程课程 但无法解决此编译错误 它的编写方式与示例书中完全相同 当我兄弟将其剪切并粘贴到他的 VS2015 中时 它工作正常 但在我的 VS2017 中却不行 我已经卸载并重新安装VS2017社区无济于事 我只编码了
  • ExtJs 4 - 在记录保存时加载嵌套数据

    我有两个模型 掌握 Ext define App model Master extend Ext data Model fields name master name type string name id type int proxy t
  • 如何将 IO monad 中的值分配给 RankNType 限定的构造函数

    更新 我使用了一个界面自由单子到通用数据存储 我想将用户在运行时选择的特定解释器 DataStore a gt IO a 与一些其他信息一起放入状态单子中 我似乎无法将任何内容放入数据结构的该字段中 如何将值放入定义为更高级别类型的字段中