Last week, we looked at the definition of Base64. Today we’ll try to
implement two functions - encode64
and decode64
- in Haskell. Since we are
working with binary data, we are using the bytestring library to represent
the decoded data. In the end, we want our functions to be encapsulated in a
module to make the functions easy to re-use later on.
1
2
3
4
5
6
7
8
9
10
module Base64 (encode64, decode64) where
import Data.ByteString
encode64 :: ByteString -> String
encode64 data = undefined
-- Decoding can fail for invalid inputs.
decode64 :: String -> Maybe ByteString
decode64 data = undefined
Focusing on encode64
first, our alphabet is a good point to get started. We
can define this in terms of another function (private to our module).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
alphabet :: [Char]
alphabet = [ 'A', 'B', 'C', 'D' -- 000000 to 000011
, 'E', 'F', 'G', 'H' -- 000100 to 000111
, 'I', 'J', 'K', 'L' -- 001000 to 001011
, 'M', 'N', 'O', 'P' -- 001100 to 001111
, 'Q', 'R', 'S', 'T' -- 010000 to 010011
, 'U', 'V', 'W', 'X' -- 010100 to 010111
, 'Y', 'Z', 'a', 'b' -- 011000 to 011011
, 'c', 'd', 'e', 'f' -- 011100 to 011111
, 'g', 'h', 'i', 'j' -- 100000 to 100011
, 'k', 'l', 'm', 'n' -- 100100 to 100111
, 'o', 'p', 'q', 'r' -- 101000 to 101011
, 's', 't', 'u', 'v' -- 101100 to 101111
, 'w', 'x', 'y', 'z' -- 110000 to 110011
, '0', '1', '2', '3' -- 110100 to 110111
, '4', '5', '6', '7' -- 111000 to 111011
, '8', '9', '+', '/' -- 111100 to 111111
]
Note, that you have to enable the language extension BinaryLiterals
to
support binary literals such as 0b110100
. We also need the padding character,
which can define as another private function. You can think of the alphabet
and the paddingCharacter
functions as constants.
1
paddingCharacter = '=' :: Char