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

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

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

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

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

※ `Builder` から直接作れる `ByteString` は Lazy `ByteString` のみです。

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

```haskell
import qualified Data.ByteString as BS
import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Char8 as BSC

main :: IO ()
main = do

    let byteStringA = BS.pack [99, 97, 116, 32, 227, 129, 173, 227, 129, 147]
    BSC.putStrLn byteStringA
    print byteStringA

    let byteStringB = BS.singleton 99
    BSC.putStrLn byteStringB
    print byteStringB

    let byteStringC = BSC.toStrict . BSB.toLazyByteString . BSB.word8 $ 99
    BSC.putStrLn byteStringC
    print byteStringC
```

```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.Char8 as BSC

main :: IO ()
main = do

    let byteStringA = BSC.pack "cat"
    BSC.putStrLn byteStringA
    print byteStringA

    let byteStringB = fromString "cat"
    BSC.putStrLn byteStringB
    print byteStringB

    let byteStringC = BSC.singleton 'c'
    BSC.putStrLn byteStringC
    print byteStringC

    let byteStringD = BSC.toStrict . BSB.toLazyByteString . BSB.string7 $ "cat"
    BSC.putStrLn byteStringD
    print byteStringD

    let byteStringE = BSC.toStrict . BSB.toLazyByteString . BSB.char7 $ 'c'
    BSC.putStrLn byteStringE
    print byteStringE
```

```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.Char8 as BSC

main :: IO ()
main = do

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

    let byteStringB = fromString "cat ねこ"
    BSC.putStrLn byteStringB
    print byteStringB

    let byteStringC = BSC.singleton 'ね'
    BSC.putStrLn byteStringC
    print byteStringC

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

    let byteStringE = BSC.toStrict . BSB.toLazyByteString . fromString $ "cat ねこ"
    BSC.putStrLn byteStringE
    print byteStringE

    let byteStringF = BSC.toStrict . BSB.toLazyByteString . BSB.charUtf8 $ 'ね'
    BSC.putStrLn byteStringF
    print byteStringF
```

```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.Char8 as BSC

main :: IO ()
main = do

    let byteString = "cat"
    BSC.putStrLn byteString
    print byteString
```

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

### 2.2.2. UTF-8 の場合

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

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

import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Char8 as BSC

main :: IO ()
main = do

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

    -- UTF-8 を正しく扱える
    let byteStringB = BSC.toStrict . BSB.toLazyByteString $ "cat ねこ"
    BSC.putStrLn byteStringB
    print byteStringB
```

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

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

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

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

main :: IO ()
main = do

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

    let byteStringA = BSC.toStrict lazyByteString
    BSC.putStrLn byteStringA
    print byteStringA

    let byteStringB = BSC.toStrict . BSB.toLazyByteString . BSB.lazyByteString $ lazyByteString
    BSC.putStrLn byteStringB
    print byteStringB

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

    let byteStringC = BSS.fromShort shortByteString
    BSC.putStrLn byteStringC
    print byteStringC

    let byteStringD = BSC.toStrict . BSB.toLazyByteString . BSB.shortByteString $ shortByteString
    BSC.putStrLn byteStringD
    print byteStringD
```

```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"
```

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

# 4. 空文字列の場合

```haskell
import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Char8 as BSC

main :: IO ()
main = do

    let byteStringA = BSC.empty
    BSC.putStrLn byteStringA
    print byteStringA

    let byteStringB = mempty
    BSC.putStrLn byteStringB
    print byteStringB

    let byteStringC = BSC.toStrict . BSB.toLazyByteString $ mempty
    BSC.putStrLn byteStringC
    print byteStringC
```

```text:実行結果

""

""

""
```

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

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

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

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

```haskell
import qualified Data.ByteString.Builder as BSB
import qualified Data.ByteString.Char8 as BSC

main :: IO ()
main = do

    let byteStringA = BSC.toStrict . BSB.toLazyByteString . BSB.word32BE $ 0x63617420
    BSC.putStrLn byteStringA
    print byteStringA

    let byteStringB = BSC.toStrict . BSB.toLazyByteString . BSB.byteStringHex $ byteStringA
    BSC.putStrLn byteStringB
    print byteStringB

    let byteStringC = BSC.toStrict . BSB.toLazyByteString . BSB.word32HexFixed $ 0x63617420
    BSC.putStrLn byteStringC
    print byteStringC
```

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