如何实现index-core风格的索引状态monad?

2024-02-23

我试图理解中的索引单子index-core http://hackage.haskell.org/package/index-core风格。我陷入了一个悖论,即在构建一些示例之前我无法理解原理,而在理解原理之前我无法构建示例。

我正在尝试构建一个索引状态单子。到目前为止,我的直觉告诉我应该是这样的

type a :* b = forall i. (a i, b i)
newtype IState f a i = IState { runIState :: f i -> (a :* f) }

我可以通过设置恢复“受限”状态单子f = Identity并选择a适当地:

type IState' s s' a = IState Identity (a := s') s

但我感觉很失落。有人可以确认我的路线是正确的吗?

我在用着关于索引延续单子的类似问题 https://stackoverflow.com/questions/14014683/how-to-implement-index-core-style-indexed-continuation-monad作为指南,但我认为它还不够接近。


我们可以从索引中复制加布里埃尔的论点Cont答案已链接。如果标准索引状态 monad 是

State s s' a = s -> (a, s')

然后我们分阶段概括它。首先通过使用Identity反映具体类型s and s'作为索引类型空间中的纤维Identity.

State s s' a = s          -> (a, s')
             ~ Identity s -> (a, Identity s')

然后通过概括值类型a到索引类型以及“目标”索引,类型s'.

             ~ Identity s -> (a   , Identity s')
             ~ Identity s -> (a s', Identity s')

然后使用存在类型来擦除目标索引。我们稍后会恢复它。

data a :* b = forall i . P (a i) (b i)

  Identity s -> (a s', Identity s') 
~ Identity s -> P a Identity

最后,我们要注意的是Identity是状态空间的索引类型,a值空间的索引类型,所以我们可以写IState as

newtype IState s -- indexed state space
               a -- indexed value space
               i -- index
  = IState { runIState :: s i -> a :* s }
--   State { runState  :: s   -> (a, s) }        for comparison

为什么使用存在量化对而不是普遍量化对?第一个推动来自于以下事实:与a正在积极发生IState虽然它出现在负面ICont。第二个提示来自写作returnI。如果我们使用通用量化版本并尝试写returnI

newtype IState' s a i = IState' { runIState' :: s i -> (forall i . (a i, s i)) }

returnI :: a i -> IState' s a i
returnI a = IState' (\si -> (?forget a, ?forget si))

我们需要这个forget函数会忘记有关索引的所有信息。

然而,如果我们改为使用存在量化对,那么就取决于该返回对的构造函数,即IState值,来选择索引。这让我们实例化IFunctor and IMonad

instance IFunctor (IState s) where
  -- fmapI :: (a :-> b) -> IState s a :-> IState s b
  fmapI phi (IState go) = IState $ \si -> 
    case go si of 
      P ax sx -> P (phi ax) sx

instance IMonad (IState s) where
  -- returnI :: a :-> IState s a
  return ai = IState (\si -> P ai si)

  -- bindI :: (a :-> IState s b) -> (IState s a :-> IState s b)
  bindI f m = IState $ \s ->
    case runIState m s of
      P ax sx -> runIState (f ax) sx

使用这个存在对的唯一缺点是它......实际使用起来相当困难。例如,我们真的希望能够使用“pointed”索引类型构造函数(:=)为了修复已知的索引并从存在对中投影出来。

one :: (a := i :* b) -> a
two :: (a := i :* b) -> b i

不幸的是,即使我们知道存在主义是什么,Haskell 也不够聪明,无法强制存在主义,因此第二个预测的实现令人讨厌

one :: (a := i :* b) -> a
one (P (V a) _) = a

two :: (a := i :* b) -> b i
two (P _ s) = unsafeCoerce s

最后,证据就在布丁中。我们可以用IState实现我们习惯看到的状态效果的标准补充。

-- Higher order unit type
data U1 a = U1

put :: s i -> IState s U1 j
put s = IState (\_ -> P U1 s)

get :: IState s s i
get = IState (\s -> P s s)

并使用它们来实现一些通用的高阶组合器,例如修改(它需要显式类型签名,但您可以通过一些思考从实现中手动计算)

modify :: (s :-> s) -> IState s U1 i
modify f = get ?>= put . f

然而,除此之外,我们还有其他表示组合器的方法,由于限制,这些组合器的索引更加明确(:=)。这对于传递有关索引的更多信息很有用。

put' :: s i1 -> IState s (() := i1) i
put' s = IState (\_ -> P (V ()) s)

get' :: IState s (s i := i) i
get' = IState (\s -> P (V s) s)

modify' :: (s -> s) -> IState (s := j) (() := j) i
modify' f = get >>= put' . V . f

modify'' :: (s i -> s k) -> IState s (() := k) i
modify'' f = get' >>= put' . f

最后,我们可以使用所有这些来实现一个示例。例如,我们可以通过文件句柄状态构建索引类型,但这并不是非常有用。

data Open
data Closed
data Any a

data St where
  So :: Int -> St Open
  Sc ::        St Closed
  Sa :: a   -> St (Any a)

getAny :: St (Any a) -> a
getAny (Sa a) = a

然后我们就可以构建

open :: String -> File Closed Open ()
open name = put' (SOpen $ getHandle name) where
  getHandle = length

close :: File Open Closed ()
close = put' SClosed

getHandle :: File Open Open Int
getHandle = do
  SOpen i <- get'
  return i

putA :: a -> File x (Any a) ()
putA a = put' (SAny a)

where

open "foo" >> close                -- typechecks
open "foo" >> close >> close       -- fails
open "foo" >> getHandler >> close  -- typechecks
open "foo" >> close >> getHandler  -- fails

和类似的事情

> one $ runIState (do putA 4
                      sa <- get'
                      return (getAny sa)) Sc
4
> one $ runIState (do putA ()
                      sa <- get'
                      return (getAny sa)) Sc
()
> one $ runIState (do putA 4
                      putA ()
                      sa <- get'
                      return (getAny sa)) Sc
()

所有工作。

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

如何实现index-core风格的索引状态monad? 的相关文章

  • Python 比编译的 Haskell 更快?

    我有一个用 Python 和 Haskell 编写的简单脚本 它读取包含 1 000 000 个换行符分隔的整数的文件 将该文件解析为整数列表 对其进行快速排序 然后将其写入已排序的不同文件中 该文件与未排序的文件具有相同的格式 简单的 这
  • Haskell 为替代的 Either 数据类型定义 Functor 实例

    通过 Typeclassopedia 获得一些使用类型类的路由 想要替代Either的一个实例Functor 但即使检查定义Either作为一个例子Functor总是给我带来麻烦 有这个 但不会编译 data Alt a b Success
  • 在 Haskell 中调试时打印时间戳

    我仍在学习 Haskell 并调试一些函数 并且通常有一个时间戳函数来了解某些操作何时开始和停止 doSomeAction String gt IO doSomeAction arg1 do putStrLn lt lt makeTime
  • 函数式语言与语言实现的角度有何不同

    出现了全新的 函数式编程 范式 与过程式编程相比 它需要彻底改变思维模式 它使用高阶函数 纯度 单子等 我们通常在命令式和面向对象语言中不会看到这些 我的问题是如何执行这些语言与命令式或面向对象语言的不同之处在于 例如内存管理或指针等内部结
  • monadicIO 的工作原理

    我有以下代码 fastShuffle a gt IO a fastShuffle a
  • 浏览前奏的源代码会带来奇怪的情况

    我一直在寻找的定义seq并遇到了这个奇怪的事情 为什么所有这些函数都有相同 相似的定义 seq a gt b gt b seq let x x in x inline a gt a inline let x x in x lazy a gt
  • 带有参考的 Haskell 数据类型

    我正在实现 Ukkonen 的算法 该算法要求树的所有叶子都包含对同一整数的引用 并且我在 Haskell 中执行此操作是为了了解有关该语言的更多信息 但是 我很难编写出执行此操作的数据类型 Node has children indexe
  • 在不同上下文中使用的多态变量 haskell

    我有以下一段 Haskell 代码 foo Num a gt a gt a gt Either Integer Double gt Either Integer Double foo f x case x of Left i gt Left
  • 非单射封闭型族

    我确实有一段人为设计的代码 LANGUAGE DataKinds TypeFamilies data Foo Foo type family Id n Foo a where Id Foo a a data Bar n Foo Bar cl
  • 将List中的相邻元素放入元组中

    给定一个元素列表 xs a b c d z where a b c等是任意值的占位符 我想实现一个功能adjacents a gt a a 产生 adjacentValues a b b c c d y z 在 Haskell 中 递归定义
  • Show for String的实例是怎么写的?

    我有一个关于定义类型类实例的基本问题 我使用 Show 类型类作为示例 并且只考虑类中的 show 函数 像 Bool 这样的具体类型的 Show 实例很简单 instance Show Bool where show x function
  • kind 类型的函子和应用词 (* -> *) -> *

    我遇到了一种情况 我的代码将受益于使用Functor and Applicative 类似抽象 但针对种类类型 gt gt 定义一个更高种类的函子可以通过RankNTypes像这样 class HFunctor f where hfmap
  • 我可以在线性时间内检查有界列表是否包含重复项吗?

    假设我有一个Int列表 其中元素已知是有界的 并且列表已知不长于它们的范围 因此它完全有可能不包含重复项 如何才能最快地测试是否是这种情况 我知道nubOrd https hackage haskell org package contai
  • 如何使用范围内的约束族来证明表达式主体内的实例?

    这是后续我之前的问题 https stackoverflow com questions 70075414 how can i derive typeclass instances from constraint families that
  • 在 GHCi 中,为什么我不能在 REPL 中显示 `pure 1`?

    我尝试将提升值分配给a gt m Control Applicative gt let a pure 1 当我评价的时候a在 REPL 中 它打印1 gt a 1 因此 我认为可能会实施show for a 并尝试了这个 gt show a
  • Haskell:去掉 liftM2 中的括号

    如何去掉标有的括号 而不引入新名称 如果能分成多行就更好了 liftM2 somefunc arg1 get arg2 somefunc arg3 get arg3 您可以使用以下方法删除最后一个 但另一个显然不能在不引入新名称的情况下被删
  • 测试列表是否已排序

    在 haskell 中找到最小列表确实很容易 foldl1 min 9 5 7 3 7 4 6 10 给我3 我更换了min with lt 测试列表是否已排序 foldl1 lt 9 5 7 3 7 4 6 10 我收到此错误消息 No
  • 哈斯克尔状态单子

    是否putState Monad 的函数会更新实际状态还是仅返回具有新值的新状态 我的问题是 State Monad 可以在命令式设置中像 全局变量 一样使用吗 并且确实put修改 全局变量 我的理解是 不 它不会修改初始状态 但是使用单子
  • 当单态限制打开*时,如何解决歧义问题?

    因此 在学习 Haskell 时 我很快就遇到了可怕的单态限制 在 ghci 中 Prelude gt let f print show Prelude gt f 5
  • Haskell:如何创建将函数应用于元组项的最通用函数

    这是一个个人练习 旨在更好地理解 Haskell 类型系统的局限性 我想创建最通用的函数 将某些函数应用于 2 条目元组中的每个条目 例如 applyToTuple fn a b fn a fn b 我试图让这个函数在以下每种情况下都起作用

随机推荐

  • 我可以使用 JavaScript 停止元刷新吗?

    以下代码允许用户停止元刷新的发生 并且它成功删除了meta refresh从页面 但浏览器仍然刷新页面 知道如何让它发挥作用吗
  • 无法在 python 3.7 中安装 Matplotlib

    在 Windows 10 64 位机器中安装 matplotlib 时出现错误显示 python setup py egg info failed with error code 1 in C Users Animus AppData Lo
  • Systemd 启用的服务不再在启动时启动

    我很久以前制作了一些自定义的 systemd 服务 它们都具有相同的配置 当然 ExecStart 除外 这个配置工作了很多年 我从 18 04 LTS 版本开始就已经启动并运行了 ubuntu 但现在看起来其中一些 systemd 服务根
  • 如何订阅“/scan”主题、修改消息并发布到新主题?

    我想通过订阅message ranges来改进turtlebot3的LDS 01传感器 通过应用一些算法修改messange ranges并将其发布到新主题 如下所示 但是当我运行编码时出现错误 错误是 遇到溢出的情况 错误是 运行时警告
  • 重绘canvas html5而不闪烁

    我的屏幕每 25 毫秒重绘一次 并且图像闪烁 这是我的代码 var FRAME RATE 40 var intervalTime 1000 FRAME RATE gameLoop function gameLoop context clea
  • 使用装饰器进行 Python 日志记录

    这是我们面对装饰器时遇到的第一个例子 但我无法意识到我到底想要什么 一个名为 LOG 的简单装饰器 它应该像这样工作 LOG def f a b 2 c d pass 结果应该是这样的 f 1 pippo 4 paperino luca E
  • 阻止执行父事件处理程序

    我有一棵 div 树 div div div div div div 当单击 div 时 它会使其子级不可见 即单击 a 将使 b 和 c 不可见 function func if childId hasClass visible chil
  • 带有条件的 Ansible 即席命令

    我想运行此剧本的 Ansible ad hoc 命令 hosts localhost tasks name Print message if ansible version is greater than 2 7 0 debug msg A
  • 在 Ruby 中,术语“元类”、“特征类”和“单例类”完全是同义且可替换的吗?

    的文档Class http www ruby doc org core 2 1 2 Class html类有一个涉及 元类 的令人难以置信的混乱图 我试图揭开这里到底发生了什么的神秘面纱 这三个词都是 元类 特征类 单例类 同义 in Ru
  • 什么是snakemake元数据文件?我什么时候可以删除那些?

    我注意到我的备份 rsync 脚本花费了相当多的时间从以下位置复制具有随机名称的内容 snakemake metadata文件夹 这些文件有什么用 在 Snakemake 运行完成后我可以安全地删除它们吗 或者它们对于 Snakemake
  • 从 jar 文件加载图像

    我有一个可以在 Netbeans IDE 中完美运行的应用程序 但是当从 dist 目录中的 jar 文件运行时 不会加载必要的图像 我花了 1 1 2 天阅读这个论坛和其他论坛 试图找到答案 但我无法让 jar 图像工作 这是我的代码的摘
  • C# 和 SQL Server 中的 DateTimeOffset 解析

    文档指出 NET 和 SQL Server 中的分辨率均为 100 纳秒 DateTimeOffset 值的时间部分以 100 纳秒为单位 称为刻度 进行测量 C 精度 100 纳秒 SQL服务器 然而 SQL 似乎删除了最后一位数字 例如
  • 循环内导入模块

    我有一个文件 我们称之为 foo py 它执行一些操作 包括通过串行端口发送一些数据并通过电子邮件发送返回的响应 我有另一个文件 看起来像这样 iteration 0 while True iteration 1 do some stuff
  • 在不使用外部 gem 的情况下将文件上传到 db Rails 3

    我有一个任务 我需要在 Rails 3 2 中上传一个文件 txt 而不使用任何外部 gem 来完成腿部工作 恐怕是不可协商的 该文件还需要保存到数据库中 我有以下代码 但是当我尝试使用表单上传 创建新附件时 它会返回错误 No route
  • 使用 --depth 1 进行浅层克隆、创建提交并再次拉取更新是否安全?

    The depth 1选项中git clone http git scm com docs git clone 创建一个shallow克隆历史记录被截断为指定数量的修订版 浅存储库有许多限制 您不能从中克隆或获取 也不能从其中推入或推入其中
  • 无法使用 JSF 2.0 重复标记的 varStatus 的“end”属性

    我正在使用repeatJSF 2 0 的标签用于循环对象列表并显示它们的一些属性 我想使用varStatus的属性repeat这样我就可以访问循环索引 最后一个列表项的编号 并判断是否已到达列表末尾 因此不会显示间隔符 我认为这会起作用
  • 安全的客户端脚本

    我有一个特殊的要求 其中一些关键算法必须在客户端脚本中处理 并且必须得到保护 使用 javascript 只会公开算法 我目前正在评估保护客户端脚本上的算法的方法 感谢任何建议和替代方法 我正在考虑的一个选择是将一个小小程序下载到本地 PC
  • 使用温莎城堡配置文件是否可以委托给另一个项目声明?

    使用 Castle Windsor 是否可以声明一个类型一次并将此声明用于多个 Id 而不是每次都完整地写出来 例如 我们有实现 IFoo 的 Widget 类 并且我们需要键 IFoo A 和 IFoo B 从 Castle 获取 Wid
  • CSS 优先级和针对特定元素

    我的问题应该很简单 出于某种原因 我今天无法理解它 我正在制作一个结构如下的菜单 div class wrapper ul li class menu item a href Menu Item a div class inner a hr
  • 如何实现index-core风格的索引状态monad?

    我试图理解中的索引单子index core http hackage haskell org package index core风格 我陷入了一个悖论 即在构建一些示例之前我无法理解原理 而在理解原理之前我无法构建示例 我正在尝试构建一个