(Σ*)² ⟲ Σ* (aka Round-Trip a String Pair) This is a challenge I thought of recently which I think is not hard but allows for a wide range of possible solutions. Seems like a perfect fit for the creativity of PPCG users :)
Your Task
Define two functions which together form a lossless round-trip String × String → String → String × String.
More specifically, define two functions combine and separate with repsective types String × String → String and String → String × String such that separate ∘ combine = id.
Even more specifically, define two functions (or methods/procedures/etc), which I will refer to as combine and separate, and which exhibit the following characteristics:

When invoked with a single string, separate produces two strings as results. (You may use any reasonable string type. Most languages don't canonically allow producing multiple values, so feel free to to do something equivalent, such as returning a 2-tuple or modifying two global variables.)

When invoked with two strings, combine produces a single string as result. (You may accept input to separate in the same form that combine produces, or any other reasonable form.)

For any two strings a and b, separate(combine(a, b)) must result in two strings which are (structurally) equivalent to a and b.

The above bullets are the only restrictions on combine and separate. So, for instance, combine ∘ separate need not be id, and separate can even be a partial function, if you like.


(Defer to the final and more-verbose description if there are any ambiguities between the three)
Intent
My goal with this challenge is to inspire creative and interesting solutions. As such, in order to avoid priming/suggesting your thinking about how to solve this problem, I will not be providing test cases, and I strongly suggest that you do not look at the existing answers until you submit your own.
Winning Criteria
This challenge is a popularity-contest; the answer with the highest score at noon on April 5th, UTC, is the winner.
Guidelines for voters, included to be a valid popularity-contest, are as follows:

Strongly prefer answers which you do not immediately comprehend, are not obviously correct, and/or surprise you
Prefer answers which go beyond strings, i.e., those which make use of more than the problem statement did (functions, strings, pairs)
Avoid answers which are similar to your own solution(s)
Avoid answers which boil down to language builtins


Have fun!
I know this is extra credit, but your problem got me thinking a lot about this and what interested me the most was not just separate being the left inverse of combine, but having them be true inverses of each other. This ends up with us defining a bijection from String -&gt; String x String. The path I took was as follows

Define a bijection from String -&gt; N
Define a bijection from N -&gt; N x N
Combine them to get the functions we need

String -&gt; N
Let r be the size of the character set you're working with and give each character a unique value from 1 to r, say f(c) = n. Going from right to left and indexing starting from zero, create the number f(s[0])r^0 + f(s[1])r^1 + f(s[2])r^2 ... f(s[length(s)])r^(length(s)). The lowest number you can get this way is 1, so we let the empty string equal 0.
N -&gt; N x N
Take n in any base you like. Separate even digits into one part of the tuple and the odd digits into the other to make a pair of numbers. E.g. 12345 -&gt; (24, 135). To work your way back, combine the numbers in the opposite way, inserting extra zeros as necessary.
Putting it all together
Haskell

module Main where

import Data.Function ((&amp;))
-- tio is saying this isn't correct for some reason so gotta define it manually
-- import Data.Functor ((&lt;&amp;&gt;))

main :: IO ()
main = do
  putStrLn $ show $ separate &quot;Hello, world!&quot;
  putStrLn $ combine (&quot;Hello, world!&quot;, &quot;&quot;)
  putStrLn $ show $ separate $ combine (&quot;Hello, world!&quot;, &quot;&quot;)
  putStrLn $ combine $ separate &quot;Hello, world!&quot; 

separate :: String -&gt; (String, String)
separate str =
  str
  &lt;&amp;&gt; toInt
  &amp; fromNZ
  &amp; split
  &amp; tmap toNZ
  &amp; tmap (map fromInt)

combine :: (String, String) -&gt; String
combine strs =
  strs
  &amp; tmap (map toInt)
  &amp; tmap fromNZ
  &amp; join
  &amp; toNZ
  &lt;&amp;&gt; fromInt

base :: Int
base = 95

toInt :: Char -&gt; Int
toInt c = fromEnum c - 31

fromInt :: Int -&gt; Char
fromInt i = toEnum $ i + 31

strip :: [Int] -&gt; [Int]
strip is = case is of
  0 : i : tail -&gt; strip $ i : tail
  _ -&gt; is

split :: [Int] -&gt; ([Int], [Int])
split =
  tmap strip . fst . foldr
    (\a ((acc1, acc0), i) -&gt;
      (if mod i 2 == 0 then
        (acc1, a : acc0)
      else
        (a : acc1, acc0)
      , i + 1
      )
    )
    (([], []), 0)

join :: ([Int], [Int]) -&gt; [Int]
join (l1, l2)= strip $ reverse $ go [] (reverse l1, reverse l2)
  where
    go :: [Int] -&gt; ([Int], [Int]) -&gt; [Int]
    go acc (l1', l2') = case (l1', l2') of
      (head1 : tail1, head2 : tail2) -&gt; head2 : head1 : go acc (tail1, tail2)
      ([], head : tail) -&gt; head : 0 : go acc ([], tail)
      (head : tail, []) -&gt; 0 : head : go acc (tail, [])
      ([], []) -&gt;  acc

tmap :: (a -&gt; b) -&gt; (a, a) -&gt; (b, b)
tmap f (a1, a2) = (f a1, f a2)

fromNZ :: [Int] -&gt; [Int]
fromNZ is =
  if is == [] then [0]
  else let
    (result, finalCarry) =
      foldr
        (\i' (acc, carry) -&gt;
          let
            i =
              if carry then i' + 1
              else i'
          in
            if i &gt;= base then (i - base : acc, True)
            else (i : acc, False)
        )
        ([], False)
        is
  in
    if finalCarry then 1 : result
    else result

toNZ :: [Int] -&gt; [Int]
toNZ is =
  if is == [0] then []
  else let
    (result, finalUncarry) =
      foldr
        (\i' (acc, uncarry) -&gt;
          let
            i =
              if uncarry then i' - 1
              else i'
          in
            if i &lt;= 0 then (i + base : acc, True)
            else (i : acc, False)
        )
        ([], False)
        is
  in
    if finalUncarry then
      case result of
        a : tail -&gt;
          if a == base then tail
          else result
        _ -&gt; result
    else result

m &lt;&amp;&gt; f = f &lt;$&gt; m
infixl 1 &lt;&amp;&gt;

Try it online!