What you basically need is just a way to convert a number to string representation and vice-versa. This task is by the way, always the same, for every base. Here a step-by-step solution.
To convert a number to binary, you can use the following algorithm.
let rec toBinary x =
if x = 0 then "0"
else
let y = x % 2
(toBinary ((x-y)/2)) + (string y)
As an example, this is how you convert to Octal representation.
let rec toOctal x =
if x = 0 then "0"
else
let y = x % 8
(toOctal ((x-y)/8)) + (string y)
As you see, its always the same. Make a module on the base, to get the right most number. Repeat on the subtraction and division of the base.
20
20 % 2 = 0 // 20 / 2
10 % 2 = 0 // 10 / 2
5 % 2 = 1 // (5-1) / 2
2 % 2 = 0 // 2 / 1
1 % 2 = 1 // (1-1) / 2
0
This way, you uild the number from right-to-left and it works for any base.
Now, instead of writing every version, you could make it more general, by providing the base as a number.
let rec toBase nbase x =
if x = 0 then "0"
else
let y = x % nbase
(toBase nbase ((x-y)/nbase)) + (string y)
And to make it even more general, you could provide a string list, with your mappings. Like this.
let rec toBase' nbase x =
let bse = List.length nbase
if x = 0 then
nbase.[0]
else
let y = x % bse
(toBase' nbase ((x-y)/bse)) + (nbase.[y])
Now, you can create arbitary mappings.
let toBin = toBase' ["0";"1"]
let toABCD = toBase' ["A";"B";"C";"D"]
let toHex = toBase' ["0";"1";"2";"3";"4";"5";"6";"7";"8";"9";"A";"B";"C";"D";"E";"F"]
let toOct = toBase' ["0";"1";"2";"3";"4";"5";"6";"7"]
Next, you should do the reverse. Map a string, back to a number. The usually way, is to understand, that a number is a multiplication at a position. For example the binary number "1010" really means:
(1 * 8) + (0 * 4) + (1 * 2) + (0 * 1)
And as code:
let rec toInt nbase x =
let bse = List.length nbase
let mut = pown bse (String.length x - 1)
if x = "" then
0
else
let fc = string (x.[0])
let index = List.findIndex (fun e -> e = fc) nbase
(toInt nbase (x.[1..])) + (index * mut)
Now you can define the reverse.
let toBin = toBase' ["0";"1"]
let fromBin = toInt ["0";"1"]
let toABCD = toBase' ["A";"B";"C";"D"]
let fromABCD = toInt ["A";"B";"C";"D"]
let toHex = toBase' ["0";"1";"2";"3";"4";"5";"6";"7";"8";"9";"A";"B";"C";"D";"E";"F"]
let fromHex = toInt ["0";"1";"2";"3";"4";"5";"6";"7";"8";"9";"A";"B";"C";"D";"E";"F"]
let toOct = toBase' ["0";"1";"2";"3";"4";"5";"6";"7"]
let fromOct = toInt ["0";"1";"2";"3";"4";"5";"6";"7"]
If you now want a stream of numbers, you just can List.map your numbers, or create a sequence from it. For example, a stream of binary numbers. This sequence is what you wanted as your "++" operation. A lazy sequence that counts up, all your variants.
let binaryStream = Seq.initInfinite toBin
for x in Seq.take 10 binaryStream do
printfn "%s" x
// Will print
// 0
// 01
// 010
// 011
// 0100
// 0101
// 0110
// 0111
// 01000
// 01001
Will print the first, 10 binary numbers. If you want to add + 100 to a string, you first convert it to a number, to number multipliciation, and convert it back to a string. Or providers those functions you want. For example to add two binary strings.
let addBin x y =
toBin ((fromBin x) + (fromBin y))
addBin "1000" "1010" // 8 + 10
Now you can do your base62. For example, to print the first 200 strings.
let toB62 =
toBase' (
List.map string [0..9]
@ List.map string ['a' .. 'z']
@ List.map string ['A' .. 'Z'])
let fromB62 =
toInt (
List.map string [0..9]
@ List.map string ['a' .. 'z']
@ List.map string ['A' .. 'Z'])
let b62stream = Seq.initInfinite toB62
for x in Seq.take 200 b62stream do
printfn "%s" x