When you start thinking about real programming languages, most of them don't assign any meaning to A + B or A * B, so it's up to you to construct types that act like those types.
Product types are easiest. Tuples or case classes / record types act like product types. In the case of the Foo type I defined above, it's easy to see that for each pair (c, b) in C x Boolean, there is one value of Foo, Foo(c, b), and vice-versa.
Sum types are weird, because in practice you often don't have a guarantee that two types are disjoint. Because of this, you typically don't see sum types in use without wrapper types that distinguishes the two cases. For example, the instances of Either<A, B> are typically Left(a) for some a in A or Right(b) for some b in B.
To see why this is important, consider a sum type combining Option<A> + Option<B>. The value None belongs to both types, and you can't tell if None arose as a value of Option<A> or Option<B>. In practice, this distinction matters more often than not.
For a more extreme value of non-disjoint union, consider a library function
fetch<A>(extract: Response -> A): Either<A, Int>
that calls an HTTP API, extracts a value of type A from the response, and returns either the extracted value or, if extract fails, the HTTP status code of the response. If you extract a value of type Int from the response, the return value is Either<Int, Int>. A simple sum type Int+Int is useless here, because you won't be able to tell if 404 was the value extracted from the response or the HTTP response code.For these reasons, Either<A, B> isn't a sum of A and B, but rather a sum of Left<Int> + Right<Int>.
One place sum types are useful is combining enumerations, because different enumerations have distinct values. For example:
enum ClientErrors { BadRequest, NotFound }
enum ServerErrors { InternalServerError, BadGateway }
APIErrors = ClientErrors + ServerErrors