如何在Haskell中从线性基(Data.HashMap.Mutable.Lineral)正确创建HashMap



我能够使用GHC9:中的LinearTypes扩展,成功地从线性基本包中的Data.HashMap.Mutable.Linear生成HashMap

{-# LANGUAGE LinearTypes #-}
module Main where
import Data.HashMap.Mutable.Linear
import Data.Unrestricted.Linear
main :: IO ()
main = do
let m :: (HashMap Int String %1 -> Ur b) %1 -> Ur b
m = empty 10
let m' = m (h -> toList (insert 1 "s" (insert 2 "w" h)))
let um = unur m'
print um

这看起来很不符合逻辑,因为整个HashMap必须一次性创建,创建后,我会得到一个[(Int, String)]。我想继续使用HashMap来添加、更新、删除项目等。在非线性Haskell中,使用unordered-containers,它看起来像:

module Main where
import Data.HashMap.Strict
main :: IO ()
main = do
let m :: HashMap Int String
m = empty
let m1 = insert 1 "s" m
-- anywhere else in the code...
let m2 = insert 2 "w" m1
print $ m2

我完全根据文档中的类型编写了前者。empty似乎与非线性HashMapsempty函数相匹配,但它具有类型

empty :: forall k v b. Keyed k => Int -> (HashMap k v %1 -> Ur b) %1 -> Ur b

上面写着

使用给定容量的空HashMap运行计算。

我的理解是,我给它一个Int作为容量,然后是一个";计算";其将CCD_ 13转换为CCD_。我能找到的唯一满足该类型的函数是toList :: HashMap k v %1 -> Ur [(k, v)]。其他函数,如insert(insert :: Keyed k => k -> v -> HashMap k v %1 -> HashMap k v(,都返回一个新的HashMap(这实际上是我所期望的,但empty要求我返回Ur b(。

理想情况下,empty将返回HashMap而不是Ur b,但返回Ur (HashMap ...)对我来说也很好。有一个签名为a -> Ur a的函数,它是Ur构造函数,但如果我用它替换toList,我得到:

• Couldn't match type ‘'Many’ with ‘'One’
arising from multiplicity of ‘h’
• In the first argument of ‘m’, namely
‘( h -> Ur (insert 1 "s" (insert 2 "w" h)))’
In the expression: m ( h -> Ur (insert 1 "s" (insert 2 "w" h)))
In an equation for ‘m'’:
m' = m ( h -> Ur (insert 1 "s" (insert 2 "w" h)))
|
24 |   let m' = m (h -> Ur (insert 1 "s" (insert 2 "w" h)))
|                ^

我认为这个想法是将您感兴趣的哈希图计算转移到empty的延续中,例如,您的第二个示例如下所示:

{-# LANGUAGE LinearTypes #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Main where
import Data.HashMap.Mutable.Linear
import Prelude.Linear hiding (insert)
main :: IO ()
main = print (unur $ empty 10 $ m ->
insert (1 :: Int) "s" m & case
-- anywhere else in the code...
m -> insert 2 "w" m & case
m -> toList m)

这并不好看,但这是我做IO的意思:

{-# LANGUAGE LinearTypes #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE UnboxedTuples #-}
module Main where
import Prelude ((*>))
import Data.HashMap.Mutable.Linear
import Prelude.Linear hiding (insert)
print' :: (Show k, Show v) => HashMap k v %1 -> Ur (IO ())
print' x = toList x & (Ur x1) -> Ur (print x1)
main :: IO ()
main = unur $ empty 10 $ m ->
insert (1 :: Int) "s" m & case
m -> dup m & case
(m1, m) -> print' m1 & case
(Ur io1) -> insert 2 "w" m & case
m -> print' m & case
(Ur io2) -> Ur (io1 *> io2)

可以说,这相当于在这个功能之外进行IO,所以我不知道这有多有用

我想一个更好的解决方案是有一个empty函数,它明确地允许一种形式的IO

最新更新