ST 的状态是否应该不改变以便由 runST 执行?

问题描述 投票:0回答:1
type ST s a = ST (s -> (s, a))

runST :: (forall s. ST s a) -> a
runST (ST f) = case (f realWorld) of (_, a) -> a

仔细看,错误很多,但

runST
的整体结构如上

因此,如果要将

runST
应用于与
ST s a
相同的
s -> (s, a)
类型的值,则其类型
s
必须完全参数化。

某些依赖于具体类型的函数不能被

runST
应用。 下面是不适当功能的示例。

\s -> (s + s, "hello world")   // this won't run cause it depends on (Num) type class.

fun [] = ([], 0)
fun (x : xs) = (xs, length (x : xs))  // this won't run. It depends on ([]) type.

所以,runST要执行的函数应该如下所示。

\s -> (s, fun s)

fun = maybe some native code, not haskell.

关键是

s
来自
(s, a)
s -> (s, a)
项应该始终与
s
本身相同,就像一个身份。

我们称之为参数化。

目前我知道,如果

s
里面有
RealWorld
,即使看起来是
id
的东西也可以进行有意义的计算。 (虽然它不是纯 Haskell)。

为了证明我的猜测,我准备了以下实验

//given
newMutVar# :: v -> State# s -> (# State# s, MutVar# s v #)

//then (this is pseudo code)
let (# s#, var# #) = newMutVar# "hello world" (State# 0) in
    s# == State# 0

并查看结果是否为

True
,这意味着
newMutVar#
对于
id
的行为类似于
State#

但是我不能这样做,因为我不知道如何产生

State# s
值。我知道如何只为
RealWorld
做它,它没有意义的原因
RealWorld
内部只有一个值,所以无论映射是什么,它总是相同的。

此外,即使我成功生成了

State# 0
,也无法将
State# 0
s#
进行比较,因为
State# s
没有实现
Eq

haskell monads state-monad
1个回答
1
投票

我认为您在某种程度上将

State
类型与
ST
混为一谈。我看到您已经在幕后查看 GHC 如何定义
ST
IO
,但我认为您误解了您在那里看到的内容的含义。您正在尝试对实现进行推理,就好像它与
State
一样。考虑到像
State#
这样的名称的使用和这样的定义的一般结构,这是可以理解的:

type STRep s a = State# s -> (# State# s, a #)

这确实看起来像

State
类型背后的想法,但这非常具有误导性。要了解原因,您需要查看
State#
的文档,该文档以关键句子结尾:“它完全没有代表。”

不存在

State# Realworld
State# s
类型的值。一个类型为
STRep s a
的函数实际上是一个 0 参数函数(
State# s
参数根本没有表示)它返回一个类型为
a
的值(一对没有装箱的任何东西和
a
值)。

这在GHC的实现中是非常神奇的。你不能创建这样的类型。编译器必须定义它并具有正确处理它的所有特殊情况。那么为什么要打扰呢?因为它用于弥合 Haskell 函数和机器代码过程之间的表示差异。在 Haskell(好吧,GHC 核心)级别发生的所有优化都看到一个常规的 Haskell 函数,该函数正在执行令牌传递。令牌传递用于序列化执行,以便 GHC 在进行优化时无法重新排序操作。但是当 GHC 核心被转换为 C-- 用于本机代码生成后端或 LLVM IR 用于 LLVM 后端时,所有

State#
值都会被剥离,这样在低级别上你就不会拥有所有无用的东西GHC 核心表示建议的令牌传递正在发生。

所以你不知道如何创建

State#
值的原因是它们不存在。它们永远不会更新,因为
ST
不像
State
那样工作,尽管它们的内部结构表面上有相似之处。

© www.soinside.com 2019 - 2024. All rights reserved.