[Haskell] Lazy ByteString の作り方 まとめ

Strict `ByteString` および `ShortByteString` については別記事にしました。

参考「[[Haskell] Strict ByteString の作り方 まとめ - Qiita](https://qiita.com/kerupani129/items/25144e9fac571123d529)」
参考「[[Haskell] ShortByteString の作り方 まとめ - Qiita](https://qiita.com/kerupani129/items/ab1c3571ad930b3b88e6)」

各関数の説明等は公式ドキュメント等を参照。

参考「[Data.ByteString.Builder](https://hackage.haskell.org/package/bytestring-0.12.0.2/docs/Data-ByteString-Builder.html)」
参考「[Data.ByteString.Lazy](https://hackage.haskell.org/package/bytestring-0.12.0.2/docs/Data-ByteString-Lazy.html)」
参考「[Data.ByteString.Lazy.Char8](https://hackage.haskell.org/package/bytestring-0.12.0.2/docs/Data-ByteString-Lazy-Char8.html)」

# 1. `[Word8]` または `Word8` から作る場合

```haskell
import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString.Lazy.Char8 as BSLC

main :: IO ()
main = do

    let lazyByteStringA = BSL.pack [99, 97, 116, 32, 227, 129, 173, 227, 129, 147]
    BSLC.putStrLn lazyByteStringA
    print lazyByteStringA

    let lazyByteStringB = BSL.singleton 99
    BSLC.putStrLn lazyByteStringB
    print lazyByteStringB

    let lazyByteStringC = BSB.toLazyByteString . BSB.word8 $ 99
    BSLC.putStrLn lazyByteStringC
    print lazyByteStringC
```

```text:実行結果
cat ねこ
"cat \227\129\173\227\129\147"
c
"c"
c
"c"
```

# 2. `String = [Char]` または `Char` から作る場合

## 2.1. 言語拡張を使わない場合

### 2.1.1. ASCII の場合

```haskell
import Data.String (fromString)

import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Lazy.Char8 as BSLC

main :: IO ()
main = do

    let lazyByteStringA = BSLC.pack "cat"
    BSLC.putStrLn lazyByteStringA
    print lazyByteStringA

    let lazyByteStringB = fromString "cat"
    BSLC.putStrLn lazyByteStringB
    print lazyByteStringB

    let lazyByteStringC = BSLC.singleton 'c'
    BSLC.putStrLn lazyByteStringC
    print lazyByteStringC

    let lazyByteStringD = BSB.toLazyByteString . BSB.string7 $ "cat"
    BSLC.putStrLn lazyByteStringD
    print lazyByteStringD

    let lazyByteStringE = BSB.toLazyByteString . BSB.char7 $ 'c'
    BSLC.putStrLn lazyByteStringE
    print lazyByteStringE
```

```text:実行結果
cat
"cat"
cat
"cat"
c
"c"
cat
"cat"
c
"c"
```

### 2.1.2. UTF-8 の場合

やり方によっては UTF-8 を正しく扱えないため注意が必要です。

```haskell
import Data.String (fromString)

import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Lazy.Char8 as BSLC

main :: IO ()
main = do

    -- UTF-8 を正しく扱えない
    let lazyByteStringA = BSLC.pack "cat ねこ"
    BSLC.putStrLn lazyByteStringA
    print lazyByteStringA

    let lazyByteStringB = fromString "cat ねこ"
    BSLC.putStrLn lazyByteStringB
    print lazyByteStringB

    let lazyByteStringC = BSLC.singleton 'ね'
    BSLC.putStrLn lazyByteStringC
    print lazyByteStringC

    -- UTF-8 を正しく扱える
    let lazyByteStringD = BSB.toLazyByteString . BSB.stringUtf8 $ "cat ねこ"
    BSLC.putStrLn lazyByteStringD
    print lazyByteStringD

    let lazyByteStringE = BSB.toLazyByteString . fromString $ "cat ねこ"
    BSLC.putStrLn lazyByteStringE
    print lazyByteStringE

    let lazyByteStringF = BSB.toLazyByteString . BSB.charUtf8 $ 'ね'
    BSLC.putStrLn lazyByteStringF
    print lazyByteStringF
```

```text:実行結果
cat mS
"cat mS"
cat mS
"cat mS"
m
"m"
cat ねこ
"cat \227\129\173\227\129\147"
cat ねこ
"cat \227\129\173\227\129\147"
ね
"\227\129\173"
```

※ `ByteString` の `fromString` は `String` 型の文字列を UTF-8 として扱いませんが、`Builder` の `fromString` は `String` 型の文字列を UTF-8 として扱います。

## 2.2. `OverloadedStrings` 言語拡張を使う場合

### 2.2.1. ASCII の場合

```haskell
{-# LANGUAGE OverloadedStrings #-}

import qualified Data.ByteString.Lazy.Char8 as BSLC

main :: IO ()
main = do

    let lazyByteString = "cat"
    BSLC.putStrLn lazyByteString
    print lazyByteString
```

```text:実行結果
cat
"cat"
```

### 2.2.2. UTF-8 の場合

やり方によっては UTF-8 を正しく扱えないため注意が必要です。

```haskell
{-# LANGUAGE OverloadedStrings #-}

import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Lazy.Char8 as BSLC

main :: IO ()
main = do

    -- UTF-8 を正しく扱えない
    let lazyByteStringA = "cat ねこ"
    BSLC.putStrLn lazyByteStringA
    print lazyByteStringA

    -- UTF-8 を正しく扱える
    let lazyByteStringB = BSB.toLazyByteString "cat ねこ"
    BSLC.putStrLn lazyByteStringB
    print lazyByteStringB
```

```text:実行結果
cat mS
"cat mS"
cat ねこ
"cat \227\129\173\227\129\147"
```

※ `ByteString` の場合は `String` 型の文字列を UTF-8 として扱いませんが、`Builder` の場合は `String` 型の文字列を UTF-8 として扱います。

# 3. Strict `ByteString` または `ShortByteString` から作る場合

```haskell
import qualified Data.ByteString as BS
import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString.Lazy.Char8 as BSLC
import qualified Data.ByteString.Short as BSS

main :: IO ()
main = do

    -- 
    let byteString = BS.pack [99, 97, 116, 32, 227, 129, 173, 227, 129, 147]

    let lazyByteStringA = BSLC.fromStrict byteString
    BSLC.putStrLn lazyByteStringA
    print lazyByteStringA

    let lazyByteStringB = BSB.toLazyByteString . BSB.byteString $ byteString
    BSLC.putStrLn lazyByteStringB
    print lazyByteStringB

    -- 
    let shortByteString = BSS.pack [99, 97, 116, 32, 227, 129, 173, 227, 129, 147]

    let lazyByteStringC = BSL.pack . BSS.unpack $ shortByteString
    BSLC.putStrLn lazyByteStringC
    print lazyByteStringC

    let lazyByteStringD = BSB.toLazyByteString . BSB.shortByteString $ shortByteString
    BSLC.putStrLn lazyByteStringD
    print lazyByteStringD
```

```text:実行結果
cat ねこ
"cat \227\129\173\227\129\147"
cat ねこ
"cat \227\129\173\227\129\147"
cat ねこ
"cat \227\129\173\227\129\147"
cat ねこ
"cat \227\129\173\227\129\147"
```

※ `ShortByteString` から直接 Lazy `ByteString` を作ることはできません。

参考「[unpack - Data.ByteString.Short](https://hackage.haskell.org/package/bytestring-0.12.0.2/docs/Data-ByteString-Short.html#v:unpack)」

# 4. 空文字列の場合

```haskell
import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Lazy.Char8 as BSLC

main :: IO ()
main = do

    let lazyByteStringA = BSLC.empty
    BSLC.putStrLn lazyByteStringA
    print lazyByteStringA

    let lazyByteStringB = mempty
    BSLC.putStrLn lazyByteStringB
    print lazyByteStringB

    let lazyByteStringC = BSB.toLazyByteString mempty
    BSLC.putStrLn lazyByteStringC
    print lazyByteStringC
```

```text:実行結果

""

""

""
```

# 5. その他の型から作る場合

他にも様々な型の値から Lazy `ByteString` を作ることができます。

ここでは例として一部のみ載せます。他の作り方に関しては公式ドキュメント等を参照して下さい。

参考「[Data.ByteString.Builder](https://hackage.haskell.org/package/bytestring-0.12.0.2/docs/Data-ByteString-Builder.html)」
参考「[Data.ByteString.Lazy](https://hackage.haskell.org/package/bytestring-0.12.0.2/docs/Data-ByteString-Lazy.html)」
参考「[Data.ByteString.Lazy.Char8](https://hackage.haskell.org/package/bytestring-0.12.0.2/docs/Data-ByteString-Lazy-Char8.html)」

```haskell
import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Lazy.Char8 as BSLC

main :: IO ()
main = do

    let lazyByteStringA = BSB.toLazyByteString . BSB.word32BE $ 0x63617420
    BSLC.putStrLn lazyByteStringA
    print lazyByteStringA

    let lazyByteStringB = BSB.toLazyByteString . BSB.lazyByteStringHex $ lazyByteStringA
    BSLC.putStrLn lazyByteStringB
    print lazyByteStringB

    let lazyByteStringC = BSB.toLazyByteString . BSB.word32HexFixed $ 0x63617420
    BSLC.putStrLn lazyByteStringC
    print lazyByteStringC
```

```text:実行結果
cat
"cat "
63617420
"63617420"
63617420
"63617420"
```