MonadRef纯实现

时间:2014-06-23 12:59:55

标签: haskell monads

我正在研究与MonadRef相关的this problem。看一下定义

class MonadRef r m | m -> r where
    newRef :: a -> m (r a)
    readRef :: r a -> m a
    writeRef :: r a -> a -> m ()

我在考虑如何使用纯数据结构实现此功能但未能找到答案。实际上,所有已知的独立实现(不依赖于另一个MonadRef

instance TVar STM
instance IORef IO
instance (STRef s) (ST s)

要求RealWorld进行实践。这是否意味着我们只能拥有不纯粹的MonadRef

当我尝试解决此问题时,我首先发现Maybe无法实现MonadRef只是因为它太简单而且没有空间来记录所需信息。作为一般概括,我得出结论,对于任何实现,Monad必须能够包含任意数量的信息,因为您可以尽可能多地调用newRef

所以我考虑了[],但它仍然是失败的,因为存储在Monad中的数据可以是任何类型。我不知道如何在Haskell中构建一个可以存储任何类型数据的容器,同时仍然能够以适当的类型提取数据(也许existential quantification可以帮助吗?但我仍然没有&#39 ;我知道怎么做)。

1 个答案:

答案 0 :(得分:3)

你可以几乎到达那里(纯粹实现ST的等价物),使用State monad,其状态是来自引用的Map字典ID为该引用内的值。

但是Haskell的类型系统缺少依赖类型,其中值的类型取决于另一个固定类型术语的。因此,它无法表达引用中的类型取决于引用的ID,以允许所有类型。

您可以通过让存储的值为GHC.Exts.Any类型并使用来解决此问题 Unsafe.Coerce.unsafeCoerce在内部转换为正确的类型。

但正如所宣传的那样unsafeCoerce是不安全的。这再次意味着Haskell的类型系统无法保证您以类型安全的方式使用引用,如果您出错,您可以通过这种方式使GHC崩溃。 (如果MonadRef对其参考内容有Data.Typeable.Typeable约束,可能已经习惯了这样做,但事实并非如此。(然后你就可以放Data.Dynamic.Dynamic代替地图内Any。))

但是,如果 以这种方式使用unsafeCoerce,请注意隐藏所使用的ID类型,并实现与ST相同的API,包括s参数可以防止不同的ST“线程”混淆彼此的引用,那么这实际上应该可以安全地作为库工作。我找到了at least one attempt on GitHub。 (它也试图作为变压器工作,虽然我怀疑这是否安全。)