String, Text, ByteString

Posted on August 4, 2020

Untangling Haskell’s Strings - Monday Morning Haskell
Fusion on Haskell Unicode Strings

하스켈엔 문자열을 나타내는 타입이 5가지가 있습니다.

String, Text strict, Text lazy, ByteString strict, ByteString lazy

여기서는 strict, lazy를 구분하지 않고, 크게 String, Text, ByteString의 차이점을 보겠습니다.

String

유니코드 Char의 문자열

-- "ab" 는
U+0061 : U+0062 : [] -- 유니코드 리스트입니다.

String은 리스트이므로, 리스트 관련 함수로 주무를수 있고, 크기를 미리 정하지 않아도 된다는 장점이 있지만, 단점으로 퍼포먼스 문제가 있을 수 있습니다.

Text

data Text = Text !(UArray Int Word16) !Int !Int

배열의 셀 크기가 Word16이므로 16비트 유니코드 한 글자는 한 셀에 넣을 수 있습니다. String의 퍼포먼스 문제를 해결합니다. UArray로 구현되어 있는데, 리스트를 다루는 함수와 대응되는 cons, map, append, toLower 등의 함수가 정의되어 있기 때문에, 리스트를 다루듯 쓸 수 있고, 퍼포먼스도 올릴 수 있기 때문에, 산업용 코드에서는 Text를 주로 씁니다. text 라이브러리는 내부적으로 UTF-16을 쓰고, UTF-8을 쓰려면 text-utf8 또는 text-short 라이브러리를 쓰면 됩니다.
https://hackage.haskell.org/package/text

바이트열로 다룬다면 ByteString이 좋지만, 한 글자 글자가 의미있는 문자열로 취급하려면 Text 타입이 좋습니다. 문자열을 처리할 때는 Text를 쓰고, 네트워크를 통해 전송하거나 파일에 저장하려고 할 때는 ByteString으로 인코딩해야 합니다.

ByteString

문자열을 가장 저수준으로 취급하는 타입입니다. 기계가 다루는 문자열에 가장 근접합니다. Word8 오브젝트의 배열로 되어 있습니다. (Word8은 8비트로 이루어진 부호 없는 정수 타입입니다.) 배열 한 셀로 표현 가능한 범위가 8비트, 즉 255까지기 때문에 한 셀로 유니코드 한 글자를 표현하지 못합니다. 유니코드셋에서 한 글자를 나타내는 코드가 여러 셀(16비트면 두 셀, 32비트면 네개의 셀)에 나누어 들어가기 때문에, 유니코드를 텍스트로 다루려면 Text 타입보다 불리합니다.

대부분의 네트워크 라이브러리가 이 타입을 씁니다. 이 타입도 배열을 쓰기 때문에 String보다 퍼포먼스가 좋습니다.

바이너리 데이터를 위한 라이브러리지만 ASCII 문자셋만 쓴다면 (0~255) 이 라이브러리로 해결할 수도 있습니다. 하지만, 유니코드를 다룬다면 Text가 더 적당합니다.

GHC 오리지날은 Bryan O’Sullivan이 구현했고, 이를 Simon Marlow가 UArray로 다시 구현했습니다.
Haskell Hierarchical Libraries (base package) - Data.ByteString


[1] code : 글자마다 번호를 붙여 놓은걸 코드셋이라 합니다.
ASCII 코드는 ‘a’ 는 97, ‘b’ 는 98 …
유니코드 UTF-32 인코딩은 4자리 16진수로 표현됩니다. ’a’는 U+0061

[2] Unicode : 유니코드 표준에는 UTF-8, UTF-16, UTF-32 인코딩이 있습니다.
UTF-8은 작은 값은 8비트를 쓰고, 필요할 때는 32비트까지 씁니다. 그럼 한 바이트가 한 글자를 표시하는지, 여러 바이트가 한 글자를 표현하는지 어떻게 알까요? 첫 비트를 이 용도로 희생합니다. 1바이트로 표시된 코드의 최상위 비트는 항상 0이고, 2바이트는 상위 3자리가 110, 3바이트는 상위 4자리가 1110으로 표시합니다.
UTF-32는 모든 유니코드를 32비트로 표현하기 때문에, 글자를 구분하기 위한 절차가 필요 없기 때문에 가장 빠르지만 공간 활용이 나쁩니다.

Github 계정이 없는 분은 메일로 보내주세요. lionhairdino at gmail.com