Skip to content

Instantly share code, notes, and snippets.

@nattybear
Last active July 8, 2022 01:04
Show Gist options
  • Save nattybear/99e035b8968540b0bc044378aac5177e to your computer and use it in GitHub Desktop.
Save nattybear/99e035b8968540b0bc044378aac5177e to your computer and use it in GitHub Desktop.
하스켈 ByteString

ByteString

  • 리스트랑 비슷한데 원소 하나의 크기가 1바이트이다.1
  • 지연 평가 lazy 를 다루는 방식이 리스트와 다르다.
  • 패키지 이름은 bytestring

Strict

  • 모듈 이름은 Data.ByteString
  • 지연 평가를 전혀 쓰지 않는다.
  • thunk가 없어서 오버헤드가 적다.
  • 메모리 소모 시점이 이르고 기간이 짧다.

Lazy

  • 모듈 이름은 Data.ByteString.Lazy
  • lazy 하긴 하지만 리스트만큼 lazy 하지는 않다.
  • 데이터를 chunk에 저장한다. chunk 하나의 크기는 64K이다.
  • 데이터를 평가할 때 한 chunk만큼만 하고 나머지는 필요할 때 한다.
  • 리스트가 제공하는 함수와 이름이 겹쳐서 import qualified를 한다.
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString      as S
  • [a] ~ ByteString
  • a ~ Word8

pack

  • 함수 packWord8 리스트를 넣으면 리스트보다는 덜 lazy한 ByteString을 리턴한다.2
pack :: [Word8] -> ByteString

Word8

  • Int랑 비슷하다.
  • 값 범위는 0 - 255
  • 타입 클래스 Num 인스턴스 있다. 그래서 5와 같은 숫자 리터럴은 타입 Word8이 될 수 있다.
ghci> B.pack [99, 97, 110]
Chunk "can" Empty
  • Word8 범위보다 큰 수가 오면 0부터 다시 센다. 예를 들어 33680이 된다.
  • Empty는 리스트에서 []와 같다.3
  • 함수 unpackpack과 반대이다. ByteString을 넣으면 [Word8]이 나온다.
unpack :: ByteString -> [Word8]

fromChunks

  • 함수 fromChunks는 strict bytestring 리스트를 넣으면 lazy bytestring을 리턴한다.4
fromChunks :: [S.ByteString] -> B.ByteString
ghci> :{
ghci| B.fromChunks [ S.pack [40,41,42]
ghci|              , S.pack [43,44,45]
ghci|              , S.pack [46,47,48] ]
ghci|:}
()*+,-./0
  • toChunks는 반대로 lazy bytestring을 넣으면 strict bytestring 리스트를 리턴한다.
toChunks :: B.ByteString -> [S.ByteString]

cons

  • 리스트에서 :은 bytestring에서 cons와 같다.
  • 바이트와 bytestring을 받아서 바이트를 bytestring 앞에 붙인다.
cons :: Word8 -> ByteString -> ByteString
  • cons는 lazy 해서 앞에 붙이려는 게 1바이트인데도 64K짜리 chunk를 하나 새로 만든다. 그래서 앞에 여러개를 붙일 때는 strict 버전인 cons'를 쓰는 게 좋다.
ghci> B.cons 85 $ B.pack [80,81,82,83]
UPQRT

API

  • Data.List에서 제공하는 것과 이름이 같은 함수를 지원한다 : head, tail, init, null, length, map, reverse, foldl, foldr, concat, takeWhile, filter
  • System.IO도 마찬가지인데 StringByteString으로 바꾸면 된다.
System.IO.readFile  :: FilePath -> IO String
ByteString.readFile :: FilePath -> IO ByteString
  • strict bytestring으로 파일을 읽으면 내용 전체를 한 번에 읽는다.
  • lazy bytestring으로 파일을 읽으면 한 번에 chunk만큼만 읽는다.

파일 복사 프로그램 만들기

import System.Environment
import qualified Data.ByteString.Lazy as B

main = do
  (fileName1:fileName2:_) <- getArgs
  copyFile fileName1 fileName2
  
copyFile :: FilePath -> FilePath -> IO ()
copyFile source dest = do
  contents <- B.readFile source
  B.writeFile dest contents

출처

대문

Footnotes

  1. Char는 크기가 정해져 있지 않다. 유니코드는 여러 바이트가 필요하다.

  2. 한 번에 64K만큼만 lazy 하다.

  3. 특정 버전부터 출력 방식이 바뀌어서 ConsEmpty가 보이진 않는다. 스택오버플로우 링크 참고.

  4. 이름이 반대여야 할 것 같다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment