Haskell如何强制在haskell中评估Data.Map?

Posted

技术标签:

【中文标题】Haskell如何强制在haskell中评估Data.Map?【英文标题】:Haskell how to force evaluation of Data.Map in haskell? 【发布时间】:2013-08-30 00:20:53 【问题描述】:

所以我有一张严格的地图

import qualified Data.Map.Strict      as Map
import qualified Data.ByteString       as BS
import qualified Data.ByteString.Char8 as C

type Key = Int
type Value = BS.ByteString

data KeyValue = KeyValue !(Map.Map Key Value)

source :: [(Key, Value)]
source = zip [0..] $ map (\x -> BS.concat $ replicate 10000 $ "alsfdd" `C.append` (C.pack $ show x)) [0..10000]

每次我放置一个元素时,我都会尝试让 Map 进行评估...

 putStrLn "Putting 10000 Strict ByteStrings into a Map"
 let newMap = foldr (\(k,v) i -> Map.insert k v $! i) Map.empty source
 putStrLn "Done..."
 putStrLn "Launching interactive mode"
 forever $ do
      putStrLn "Enter an integer:"
      k <- getLine
      print $ Map.lookup (read k) newMap

但是,在我进入“交互模式”并提交查询之前,地图不会评估。

我可以让它评估的唯一方法是打印它的大小:

newMap <- foldM (\i (k, v) -> (print $ Map.size i) >> (return Map.insert k v i)) Map.empty source

如何正确使用seq$!

有关我的实际问题的更多详细信息:

我应该注意到,在我的原始程序中,地图包含在 TVar 中,并且元素被插入到 IO 事件中。所以对我来说,为什么如果我修改 TVar haskell 不强制评估地图是没有意义的。我的程序是一个多线程套接字服务器,其中一个地址是执行查找的“读取器”。另一个套接字地址只是将字节串推送到地图上。我可以将 2 个插座连接到插入器,将 1 个插座连接到阅读器。如果我插入了很多次,地图将不会被评估,直到我的阅读器套接字查找该值。我希望在修改 TVar 时评估地图。我发现这样做的唯一方法是在我修改插入上的 TVar 之前打印地图的大小。

编辑:

所以我尝试了一个 bang 模式,它适用于上面的示例,但不适用于我的服务器:

buildIndex :: Int -> ByteString -> M.Map Int ByteString -> M.Map Int ByteString

liftIO $ do indexed <- readTVarIO tvi
            let !newIndex = buildIndex nextKey serialized indexed
            atomically $ writeTVar tvi $! newIndex

【问题讨论】:

试试newMap `seq` return ()evaluate newMap(需要Control.Exception)。 谢谢。虽然都没有工作。 :| 我的答案与@Vitus 相同,并且确实有效。只需将newMap `seq` return()evaluate newMap 放在let newMap = ... 之后即可。 【参考方案1】:

我建议使用 bang 模式,因为它通常是强制进行评估的最简单方法。问题是,当您使用 MapByteString 的严格版本时,并非您执行的每个操作都是严格的,因此不会立即计算源。与其尝试追踪每个懒惰评估的语句,只需将-# LANGUAGE BangPatterns #- 添加到文件顶部并将let newMap = ... 更改为let !newMap = ...。就是这样。

有一些技术可以手动跟踪和消除懒惰,但 bang 模式是迄今为止我见过的最简单和最快的技术。

【讨论】:

感谢您的意见。我试过这个。请参阅上面的编辑。【参考方案2】:

怎么样:

liftIO $ atomically $ modifyTVar' (buildIndex nextKey serialized) tvi

而不是

liftIO $ do indexed <- readTVarIO tvi
         let !newIndex = buildIndex nextKey serialized indexed
         atomically $ writeTVar tvi $! newIndex

查看modifyTVar' 和what is weak head normal form? 的文档

【讨论】:

以上是关于Haskell如何强制在haskell中评估Data.Map?的主要内容,如果未能解决你的问题,请参考以下文章

在 Haskell 中评估函数 a -> () 有啥规则?

是否有使用严格评估的 Haskell 编译器或预处理器?

使用 GHC API 评估 Haskell 语句/表达式

在 Haskell 中自动插入惰性

Haskell 不会懒惰地评估交错

Haskell - 延迟评估是不是会导致此文件夹停止评估所有功能