(Σ*)² ⟲ Σ* (Round-Trip a String Pair)
Jelly, 2 bytes
combine
Ṿ

Try it online!
separate
V

Try it online!
A boring, but short, solution. Uses Jelly's repr and eval atoms.
Ṿ is the right-inverse of V, meaning that ṾV (the Jelly way of composing 2 functions) returns the argument unchanged. Therefore, if passed [A, B], ṾV will return [A, B]
The first program takes input as a pair [A, B] and unevals it. The second takes a string as input and evals it as a Jelly program

Just a quick precursor on strings and Jelly. Jelly does not like strings. At all. Internally, strings are just lists of characters to Jelly, and when outputting, Jelly will do all it can to &quot;mash&quot; everything together so that it doesn't look like it should. An example that you'd expect to output ['a', 'b', 'c', 2], or even ['abc', 2]. As such, the Footers of the two programs above contain code to print the strings as-is, as lists of characters. Unfortunately, this can make them difficult to read.
But how do the programs work? Well, most of the work is done by the combine function. The separate function is simply &quot;eval the argument as Jelly code&quot;.
Ṿ
Ṿ is a weird atom, as Jelly atoms go. It's entire purpose is to act as the inverse to V (as a side note, if an character has an &quot;underdot&quot; below it in Jelly, it's likely to be the &quot;inverse&quot; to the atom without that underdot. For example, O/Ọ (ord/chr) or Y/Ỵ (join/split at newlines)) and the function it uses in the interpreter, jelly_uneval, is only used by one other atom, Ṙ, which just prints the same value as Ṿ.
However, Ṿ does a pretty good job at yielding some Jelly code that, when evaluated, yields it's argument. I won't break down into the exact details, but it's able to handle when string delimiters such as “ are contained in the input, so is a pretty solid &quot;uneval&quot; atom, as these things go.