- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在不断努力有效地摆弄位(例如,参见此 SO question)中,最新的挑战是位的有效流传输和消耗。
作为第一个简单的任务,我选择在 /dev/urandom
生成的比特流中找到最长的相同比特序列。 .典型的咒语是 head -c 1000000 </dev/urandom | my-exe
.实际目标是流式传输比特并解码 Elias gamma code ,例如,即不是字节块或其倍数的代码。
对于这种可变长度的代码,最好使用 take
, takeWhile
, group
等用于列表操作的语言。自 BitStream.take
实际上会消耗一些 monad 可能会发挥作用的双流的一部分。
明显的起点是来自 Data.ByteString.Lazy
的惰性字节串。 .
A. 计数字节
正如预期的那样,这个非常简单的 Haskell 程序的性能与 C 程序相当。
import qualified Data.ByteString.Lazy as BSL
main :: IO ()
main = do
bs <- BSL.getContents
print $ BSL.length bs
unpack
事情应该变得更糟。
main = do
bs <- BSL.getContents
print $ sum $ BSL.unpack bs
module Main where
import Data.Bits (shiftR, (.&.))
import qualified Data.ByteString.Lazy as BSL
import Data.List (group)
import Data.Word8 (Word8)
splitByte :: Word8 -> [Bool]
splitByte w = Prelude.map (\i-> (w `shiftR` i) .&. 1 == 1) [0..7]
bitStream :: BSL.ByteString -> [Bool]
bitStream bs = concat $ map splitByte (BSL.unpack bs)
main :: IO ()
main = do
bs <- BSL.getContents
print $ maximum $ length <$> (group $ bitStream bs)
[Word8]
然后,使用类次,每个
Word
被拆分成位,产生一个列表
[Bool]
.这个列表列表然后用
concat
扁平化。 .已获得
Bool
的(懒惰)列表, 使用
group
将列表拆分为相同位的序列,然后映射
length
超过它。最后
maximum
给出了想要的结果。很简单,但不是很快:
# C
real 0m0.606s
# Haskell
real 0m6.062s
bitstream
package promise “具有半自动流融合的快速、打包、严格的位流(即 bool 列表)。”。不幸的是,它不是最新的 vector
包,见 here详情。 streaming
.我不太明白为什么我需要“有效”的流媒体来让一些 monad 发挥作用——至少在我开始与所提出的任务相反的时候,即将比特流编码和写入文件。 fold
怎么样? -ing 在 ByteString
?我必须引入状态来跟踪消耗的位。那不是很好take
, takeWhile
, group
等语言是可取的。 streaming
做到这一点和
streaming-bytestring
.我可能做得不对,因为结果是灾难性的。
import Data.Bits (shiftR, (.&.))
import qualified Data.ByteString.Streaming as BSS
import Data.Word8 (Word8)
import qualified Streaming as S
import Streaming.Prelude (Of, Stream)
import qualified Streaming.Prelude as S
splitByte :: Word8 -> [Bool]
splitByte w = (\i-> (w `shiftR` i) .&. 1 == 1) <$> [0..7]
bitStream :: Monad m => Stream (Of Word8) m () -> Stream (Of Bool) m ()
bitStream s = S.concat $ S.map splitByte s
main :: IO ()
main = do
let bs = BSS.unpack BSS.getContents :: Stream (Of Word8) IO ()
gs = S.group $ bitStream bs :: Stream (Stream (Of Bool) IO) IO ()
maxLen <- S.maximum $ S.mapped S.length gs
print $ S.fst' maxLen
Streaming.Internal.>>=.loop
中花费了疯狂的时间(输入大小的二次方)和
Data.Functor.Of.fmap
.我不太确定第一个是什么,但
fmap
表示 (?) 这些
Of a b
的杂耍对我们没有任何好处,因为我们处于 IO monad 中,因此无法对其进行优化。
SumBytesStream.hs
,这比简单的懒惰
ByteString
稍慢实现,但仍然体面。自
streaming-bytestring
是
proclaimed要成为“正确完成字节串 io”,我期望更好。那我可能做得不对。
BSS.getContents
强制我进入 IO monad 因为
getContents :: MonadIO m => ByteString m ()
而且没有出路。
streaming
包在 master@HEAD。结果如下。
longest-seq-c 0m0.747s (C)
longest-seq 0m8.190s (Haskell ByteString)
longest-seq-stream 0m13.946s (Haskell streaming-bytestring)
Streaming.concat
的 O(n^2) 问题已经解决了,但我们仍然没有接近 C 基准。
Makefile
具有运行实验和分析的所有各种目标。默认
make
将构建所有内容(首先创建一个
bin/
目录!)然后是
make time
将在
longest-seq
上做计时可执行文件。 C 可执行文件得到一个
-c
附加以区分它们。
最佳答案
当对流的操作融合在一起时,可以删除中间分配及其相应的开销。 GHC prelude 以 rewrite rules 的形式为惰性流提供了折叠/构建融合。 .一般的想法是,如果一个函数产生一个看起来像文件夹的结果(它的类型 (a -> b -> b) -> b -> b
应用于 (:)
和 []
),而另一个函数使用一个看起来像文件夹的列表,构建中间列表可以被移除。
对于您的问题,我将构建类似的东西,但使用严格的左折叠( foldl'
)而不是 foldr。而不是使用重写规则来尝试检测何时看起来像 foldl
,我将使用强制列表看起来像左折叠的数据类型。
-- A list encoded as a strict left fold.
newtype ListS a = ListS {build :: forall b. (b -> a -> b) -> b -> b}
foldl'
创建严格的左折叠列表和字节串的函数。
{-# INLINE fromList #-}
fromList :: [a] -> ListS a
fromList l = ListS (\c z -> foldl' c z l)
{-# INLINE fromBS #-}
fromBS :: BSL.ByteString -> ListS Word8
fromBS l = ListS (\c z -> BSL.foldl' c z l)
{-# INLINE length' #-}
length' :: ListS a -> Int
length' l = build l (\z a -> z+1) 0
{-# INLINE map' #-}
-- fmap renamed so it can be inlined
map' f l = ListS (\c z -> build l (\z a -> c z (f a)) z)
{-# INLINE concat' #-}
concat' :: ListS (ListS a) -> ListS a
concat' ll = ListS (\c z -> build ll (\z l -> build l c z) z)
{-# INLINE splitByte #-}
splitByte :: Word8 -> [Bool]
splitByte w = Prelude.map (\i-> (w `shiftR` i) .&. 1 == 1) [0..7]
{-# INLINE splitByte' #-}
splitByte' :: Word8 -> ListS Bool
splitByte' = fromList . splitByte
ByteString
成比特
{-# INLINE bitStream' #-}
bitStream' :: BSL.ByteString -> ListS Bool
bitStream' = concat' . map' splitByte' . fromBS
data LongestRun = LongestRun !Bool !Int !Int
{-# INLINE extendRun #-}
extendRun (LongestRun previous run longest) x = LongestRun x current (max current longest)
where
current = if x == previous then run + 1 else 1
{-# INLINE longestRun #-}
longestRun :: ListS Bool -> Int
longestRun l = longest
where
(LongestRun _ _ longest) = build l extendRun (LongestRun False 0 0)
main :: IO ()
main = do
bs <- BSL.getContents
print $ longestRun $ bitStream' bs
longest-seq-c 0m00.12s (C)
longest-seq 0m08.65s (Haskell ByteString)
longest-seq-fuse 0m00.81s (Haskell ByteString fused)
total alloc = 1,173,104 bytes (excludes profiling overheads)
关于haskell - Haskell 中的高效比特流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50101329/
在 Haskell 中,类型声明使用双冒号,即 (::),如 not::Bool -> Bool。 但是在许多语法与 Haskell 类似的语言中,例如榆树、 Agda 、他们使用单个冒号(:)来声明
insertST :: StateDecoder -> SomeState -> Update SomeState SomeThing insertST stDecoder st = ... Stat
如果这个问题有点含糊,请提前道歉。这是一些周末白日梦的结果。 借助 Haskell 出色的类型系统,将数学(尤其是代数)结构表达为类型类是非常令人愉快的。我的意思是,看看 numeric-prelud
我有需要每 5 分钟执行一次的小程序。 目前,我有执行该任务的 shell 脚本,但我想通过 CLI 中的键为用户提供无需其他脚本即可运行它的能力。 实现这一目标的最佳方法是什么? 最佳答案 我想你会
RWH 面世已经有一段时间了(将近 3 年)。在在线跟踪这本书的渐进式写作之后,我渴望获得我的副本(我认为这是写书的最佳方式之一。)在所有相当学术性的论文中,作为一个 haskell 学生,读起来多么
一个经典的编程练习是用 Lisp/Scheme 编写一个 Lisp/Scheme 解释器。可以利用完整语言的力量来为该语言的子集生成解释器。 Haskell 有类似的练习吗?我想使用 Haskell
以下摘自' Learn You a Haskell ' 表示 f 在函数中用作“值的类型”。 这是什么意思?即“值的类型”是什么意思? Int 是“值的类型”,对吗?但是 Maybe 不是“值的类型”
现在我正在尝试创建一个基本函数,用于删除句子中的所有空格或逗号。 stringToIntList :: [Char] -> [Char] stringToIntList inpt = [ a | a
我是 Haskell 的新手,对模式匹配有疑问。这是代码的高度简化版本: data Value = MyBool Bool | MyInt Integer codeDuplicate1 :: Valu
如何解释这个表达式? :t (+) (+3) (*100) 自 和 具有相同的优先级并且是左结合的。我认为这与 ((+) (+3)) (*100) 相同.但是,我不知道它的作用。在 Learn
这怎么行 > (* 30) 4 120 但这不是 > * 30 40 error: parse error on input ‘*’ 最佳答案 (* 30) 是一个 section,它仍然将 * 视为
我想创建一个函数,删除满足第二个参数中给定谓词的第一个元素。像这样: removeFirst "abab" ( 'b') = "abab" removeFirst [1,2,3,4] even =
Context : def fib(n): if n aand returns a memoized version of the same function. The trick is t
我明白惰性求值是什么,它是如何工作的以及它有什么优势,但是你能解释一下 Haskell 中什么是严格求值吗?我似乎找不到太多关于它的信息,因为惰性评估是最著名的。 他们各自的优势是什么。什么时候真正使
digits :: Int -> [Int] digits n = reverse (x) where x | n digits 1234 = [3,1,2,4]
我在 F# 中有以下代码(来自一本书) open System.Collections.Generic type Table = abstract Item : 'T -> 'U with ge
我对 Haskell 比较陌生,过去几周一直在尝试学习它,但一直停留在过滤器和谓词上,我希望能得到帮助以帮助理解。 我遇到了一个问题,我有一个元组列表。每个元组包含一个 (songName, song
我是 haskell 的初学者,我试图为埃拉托色尼筛法定义一个简单的函数,但它说错误: • Couldn't match expected type ‘Bool -> Bool’
我是 Haskell 语言的新手,我在使用 read 函数时遇到了一些问题。准确地说,我的理解是: read "8.2" + 3.8 应该返回 12.0,因为我们希望返回与第二个成员相同的类型。我真正
当我尝试使用真实项目来驱动它来学习 Haskell 时,我遇到了以下定义。我不明白每个参数前面的感叹号是什么意思,我的书上好像也没有提到。 data MidiMessage = MidiMessage
我是一名优秀的程序员,十分优秀!