Haskell 冷冻哈斯凯尔·斯特里夫斯
我想实现一个用于Haskell的双连接边缘列表数据结构。此数据结构用于管理平面中直线排列的拓扑,并包含面、边和顶点的结构 在我看来,这个数据结构的良好接口应该是一种类型Haskell 冷冻哈斯凯尔·斯特里夫斯,haskell,data-structures,reference,mutable,freeze-thaw,Haskell,Data Structures,Reference,Mutable,Freeze Thaw,我想实现一个用于Haskell的双连接边缘列表数据结构。此数据结构用于管理平面中直线排列的拓扑,并包含面、边和顶点的结构 在我看来,这个数据结构的良好接口应该是一种类型排列,具有如下功能 overlay :: Arrangement -> Arrangement -> Arrangement 但通常的实现严重依赖于引用(例如,每个面都有对相邻边的引用) 在我看来,实现这一点的理想方式类似于可变数组和不可变数组的方式:将排列数据结构的内部实现为功能数据结构,但对排列进行变异的操作会“
排列
,具有如下功能
overlay :: Arrangement -> Arrangement -> Arrangement
但通常的实现严重依赖于引用(例如,每个面都有对相邻边的引用)
在我看来,实现这一点的理想方式类似于可变数组和不可变数组的方式:将排列
数据结构的内部实现为功能数据结构,但对排列进行变异的操作会“解冻”它们,以在monad中创建新的可变实例(理想情况下,使用奶牛魔法来提高效率)
因此,我的问题是:
(1) 有没有一种方法可以像数组一样冻结和解冻一个小堆?
(2)如果没有,有更好的方法吗?不是说
冻结
和解冻
的安全版本可以制作数组的完整副本,所以不一定那么有效。当然,制作一个引用数组的完整副本可以说是一种优化,而不是通过遍历和递归p来制作一个结构的完整副本使用MVar
s等的ou
另一种方法类似于
Repa
——以代数方式表示结构上的操作,并编写一个run
函数,该函数在一个过程中优化、融合并执行所有操作。可以说,这是一种更具功能性的设计。(你甚至可以在幕后使用不安全的操作,使具体化按需进行,而不是显式地进行)。这可能就是你想要的。循环应该可以正常工作。首先出现一个涉及循环的简单示例
data List a t = Nil | Cons a t deriving (Show, Functor, Foldable, Traversable)
runTerm $ do
x <- newVar Nil
writeVar x (Cons 'a' (Var x)))
return $ Var x
data List a t=Nil | Cons a t派生(显示、函子、可折叠、可遍历)
短期$do
x mfix$\f'->do
提升$writeSTRef ref$!两个f'
ask>>=提升。翻转修改Stref'(参考:|)
固定导线回路f
解冻::可遍历f=>FixF->STS(术语SF)
解冻=返回.loop
哪里
loop=Val.fmap loop.getFix
新类型Var s f=STRef(STRef s(多个s f))
newVar::f(术语sf)->ST-s(Var-sf)
newVar=fmap STRef.newSTRef.Only
readVar::Var s f->ST s(f(术语s f))
readVar(STRef ref)=fst'readSTRef ref
writeVar::Var s f->f(术语s f)->ST s()
writeVar(STRef ref)a=writeSTRef ref$!仅限a
modifyVar::Var s f->(f(sf项)->f(sf项))->ST s()
modifyVar(STRef ref)f=modifySTRef'ref(仅.f.fst')
modifyVar'::Var s f->(f(项s f)->f(项s f))->ST s()
modifyVar'(STRef ref)f=modifySTRef'ref(\a->仅$!f(fst'a))
数据多s f
=仅(f(术语SF))
|两者(f(术语SF))(固定f)
fst':多个sf->f(术语sf)
fst'(仅a)=a
fst'(两个a uu)=a
modifyToOnly::STRef s(多个sf)->ST s()
modifyToOnly ref=do
报税表()
两个f->writeSTRef ref$!仅限f
数据列表SA=Nil{-{解包{-}!(STRef s a):|!(列表SA)
地图:单子m=>(STRef s a->m b)->列表s a->m()
mapM_'\unil=返回()
mapM|k(x:| xs)=kx>>mapM|kxs
我猜您对通常的打结技巧不感兴趣,而是对更低级的东西感兴趣。我对在Haskell中创建类似的数据结构感兴趣。我了解的唯一两种方法是使用非常优雅但修改效率低的打结方法,或者使用基于ID的方法和地图类型的数据结构cture(间接)从优雅的角度来看似乎不令人满意,但可能效果很好。如果您有不同的想法,我想听到更多。您看过Martin Erwig的函数图库吗?()我刚刚读了一篇描述FGL的文章,这似乎是一种有趣的方法。我不认为我可以直接使用FGL,但也许我可以用同样的方法实现我的图。谢谢你!你能用数组作为广义引用来实现你的结构吗?
{-# LANGUAGE
Rank2Types
, StandaloneDeriving
, UndecidableInstances #-}
module Freeze
( Term (..)
, Fix (..)
, runTerm
, freeze
, thaw
, Var
, newVar
, writeVar
, readVar
, modifyVar
, modifyVar'
) where
import Control.Applicative
import Control.Monad.Fix
import Control.Monad.Trans.Class
import Control.Monad.Trans.Reader
import Control.Monad.ST
import Data.STRef
import Data.Traversable (Traversable, traverse)
data Term s f
= Var {-# UNPACK #-} !(Var s f)
| Val !(f (Term s f))
newtype Fix f = Fix { getFix :: f (Fix f) }
deriving instance Show (f (Fix f)) => Show (Fix f)
runTerm :: Traversable f => (forall s . ST s (Term s f)) -> Fix f
runTerm m = runST $ m >>= freeze
freeze :: Traversable f => Term s f -> ST s (Fix f)
freeze t = do
xs <- newSTRef Nil
f <- runReaderT (loop t) xs
readSTRef xs >>= mapM_' modifyToOnly
return f
where
loop (Val f) = Fix <$> traverse loop f
loop (Var (STRef ref)) = do
a <- lift $ readSTRef ref
case a of
Both _ f' ->
return f'
Only f -> mfix $ \ f' -> do
lift $ writeSTRef ref $! Both f f'
ask >>= lift . flip modifySTRef' (ref :|)
Fix <$> traverse loop f
thaw :: Traversable f => Fix f -> ST s (Term s f)
thaw = return . loop
where
loop = Val . fmap loop . getFix
newtype Var s f = STRef (STRef s (Many s f))
newVar :: f (Term s f) -> ST s (Var s f)
newVar = fmap STRef . newSTRef . Only
readVar :: Var s f -> ST s (f (Term s f))
readVar (STRef ref) = fst' <$> readSTRef ref
writeVar :: Var s f -> f (Term s f) -> ST s ()
writeVar (STRef ref) a = writeSTRef ref $! Only a
modifyVar :: Var s f -> (f (Term s f) -> f (Term s f)) -> ST s ()
modifyVar (STRef ref) f = modifySTRef' ref (Only . f . fst')
modifyVar' :: Var s f -> (f (Term s f) -> f (Term s f)) -> ST s ()
modifyVar' (STRef ref) f = modifySTRef' ref (\ a -> Only $! f (fst' a))
data Many s f
= Only (f (Term s f))
| Both (f (Term s f)) (Fix f)
fst' :: Many s f -> f (Term s f)
fst' (Only a) = a
fst' (Both a _) = a
modifyToOnly :: STRef s (Many s f) -> ST s ()
modifyToOnly ref = do
a <- readSTRef ref
case a of
Only _ -> return ()
Both f _ -> writeSTRef ref $! Only f
data List s a = Nil | {-# UNPACK #-} !(STRef s a) :| !(List s a)
mapM_' :: Monad m => (STRef s a -> m b) -> List s a -> m ()
mapM_' _ Nil = return ()
mapM_' k (x :| xs) = k x >> mapM_' k xs