ByteString は怠惰ではないため、 からの無限の回答に対応できませんcycleBytes
。("
あなたが得ているのは、結果を印刷するときに、残りを気にせずに出力の最初の文字を遅延して取得できるためですが、他のcycleBytes
ものを印刷する前に取得した無限の ByteString を計算しようとするためです。無限と厳密な評価は行いません。混ぜないでください。)
Data.ByteString.Lazy
代わりにインポートします (そして、 を必要としないため、 で使用fromIntegral
します。膨大な量のデータに Lazy ByteStrings を使用する場合があるため、ライブラリにはこれを可能にする長さパラメーターが必要です。)n
Int64
Int
n
または(より良い) modを減らして、無限に多くの代わりにB.length xs
使用します 。B.append xs xs
ソリューション1は次のようになります
import qualified Data.ByteString.Lazy as B
-- Cycle function for binary data
cycleBytes :: B.ByteString -> B.ByteString
cycleBytes xs
| B.null xs = error "cycleBytes: empty list"
| otherwise = xs' where xs' = xs `B.append` xs'
-- Rotate function for binary data
rotateBytes :: B.ByteString -> Int -> B.ByteString
rotateBytes xs n = B.take (B.length xs)
$ B.drop (B.length xs + fromIntegral n)
$ cycleBytes xs
test.dat
含まれている場合、Hello Mum!
これは計算されます。これはChunk "lo Mum!" (Chunk "Hel" Empty)
、遅延構築され、強制された場合にのみ結合されるためです。
ソリューション2は次のようになります
rotateBytes :: B.ByteString -> Int -> B.ByteString
rotateBytes xs n =
let len = B.length xs
n' = n `mod` len in
B.take len $! B.drop n' $! B.append xs xs
解決策 2 は、すべてを厳密に保つことができるため (これはあなたがやろうとしていたと思います)、部分的に優れていますが、cycleBytes
.
Ben Millwood は、これを次のようなものに置き換えることを提案しています。
rotateBytes :: B.ByteString -> Int -> B.ByteString
rotateBytes xs n =
let n' = n `mod` B.length xs
(beginning,end) = B.splitAt n' xs in
B.append end beginning
より明確に読み取れます。take
、drop
およびsplitAt
はすべてO(1)でByteString
あるため、効率には大きな違いはありませんが、splitAt
はよりクリーンに感じられます。