【问题标题】:Size indexed mutable arrays in HaskellHaskell中的大小索引可变数组
【发布时间】:2016-01-11 06:00:42
【问题描述】:

在 Haskell 中,可以在大小索引列表上编写函数,以确保我们永远不会越界。一个可能的实现是:

data Nat = Zero | Succ Nat deriving (Eq, Ord, Show)

infixr 5 :-

data Vec (n :: Nat) a where
    Nil  :: Vec 'Zero a
    (:-) :: a -> Vec n a -> Vec ('Succ n) a       

data Fin (n :: Nat) where
    FZ :: Fin ('Succ n)
    FS :: Fin n -> Fin ('Succ n)                       

vLookup :: Vec n a -> Fin n -> a
vLookup Nil _ = undefined           
vLookup (x :- _) FZ = x
vLookup (_ :- xs) (FS i) = vLookup xs i                      

当然,这对于不可变大小的索引列表(又名Vec)来说很好。

但是可变的呢?是否可以在 Haskell 中定义(或者是否有用于)可变大小索引数组的库?如果没有这样的库,如何实现?

编辑 1:我搜索了 Hackage 并没有找到任何符合我描述的库(大小索引可变数组)。

编辑 2: 我想提一下,我曾想过使用 IORef 来获得所需的可变性:

 type Array n a = IORef (Vec n a)

但我想知道是否有更好(更高效、更优雅)的选择...

【问题讨论】:

    标签: arrays haskell dependent-type


    【解决方案1】:

    这样的类型does exist on Hackage

    我会避免使用type Array n a = IORef (Vec n a) 之类的东西。可变数组都是关于效率的。如果您不需要它快速运行/内存占用少,那么使用它们就没有多大意义——即使是“可变算法”通常也更容易在 Haskell 中使用函数式风格来表达,也许使用状态单子但没有真正的破坏性可变状态。
    但如果效率很重要,那么您还需要紧凑的缓存高效存储。 Unboxed vectors 是理想的。 OTOH,Vec 在运行时数据级别上与普通列表没有什么不同,在缓存一致性方面当然不是那么好。即使您将它们定义为实际上将可变性交织到列表脊中,它也不会比在纯函数样式中使用不可变 Vecs 更好。

    所以,如果我不得不写这样简单的东西,我宁愿将一个(不安全的,长度方面的)未装箱的可变 arrox 包装在一个长度索引的新类型中。

    import qualified Data.Vector.Unboxed.Mutable as VUM
    
    newtype MVec (s :: *) (n :: Nat) (a :: *)
            = MVec { getMVector :: VUM.MVector s a }
    

    然后您可以定义一个接口,使所有公共操作的类型检查长度安全,同时仍保留MVector 的性能配置文件。

    【讨论】:

    • 抱歉打扰了...我错过了这个库。感谢您的关注。
    猜你喜欢
    • 2018-09-12
    • 2017-03-22
    • 2017-06-16
    • 1970-01-01
    • 2012-04-30
    • 2010-09-15
    • 2019-12-02
    • 1970-01-01
    相关资源
    最近更新 更多