[Question]
  [
There are lots of different ways to explain matrix multiplication. I'll stick with a single figure since I believe most people here are familiar with it (and the figure is very descriptive). If you want more detailed information, I suggest you visit the [Wikipedia-article](https://www.google.no/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjU467auLzRAhXiK5oKHT6TCBcQFggcMAA&url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FMatrix_multiplication&usg=AFQjCNGePV5rqwqZO0YVgw14coxNEmN6dw&sig2=4Hnrg9yz0KkcF7SGcrKSoA), or the explanation on [WolframMathWorld](http://mathworld.wolfram.com/MatrixMultiplication.html).
**Simple explanation:**
Suppose you have two matrices, **A** and **B**, where **A** is 3-by-2, and **B** is 2-by-3. If you perform matrix multiplication on these to matrices, either **AB**, or **BA** you'll get the results below:
[![enter image description here](https://i.stack.imgur.com/Ohocx.gif)](https://i.stack.imgur.com/Ohocx.gif)
## Challenge:
Implement *symbolic* matrix multiplication in you language. You shall take two matrices as input, where each element in the matrices are represented by an non-whitespace ASCII-character (code points 33-126). You must output the product of these matrices.
**Rules regarding output:**
A product of two entries shall not have any symbols in between. It's `ab`, not `a*b`, `a·b`, `times(a,b)` or something similar. It's `aa`, not `a^2`.
The sum of terms should have a space (ASCII code point 32) in between. It's `a b`, not `a+b`, `plus(a,b)` or something similar.
The rationale for those two rules is: All non white space characters are allowed as symbols in the matrices, thus using them as mathematical symbols would be messy. So, what you could normally write as `a*b+c*d` will be `ab cd`.
You may choose the order of the terms. `ab cd`, `dc ab` and `cd ba` are mathematically speaking the same, so you can choose the order here too. The order need not be consistent as long as it's mathematically correct.
**Rules regarding matrix formatting:**
A matrix can be entered in whatever format you like, except a single string with no delimiters between rows (this is because the output would be completely messed up). Both matrices must be inputted on the same format. All the examples below are valid ways of entering and outputting a matrix.
```
"ab;cd"     <- This will look awful, but it's still accepted.
"a,b\nc,d"
[[a,b],[c,d]] 
[a, b]
[c, d]
```
I'm aware that this allows a lot of formats that will look messy, but the challenge is about multiplying matrices, not formatting the output.
**General rules:**
* You may assume valid input. Matrix multiplication will always be possible with the given dimensions.
* There will only be two matrices.
* You may assume that the matrices are non-empty
* Built-in functions are accepted (but probably a bit cumbersome due to the formatting requirements).
* You may of course use escape characters in the input if necessary (`\'` instead of `'`).
* Any [standard input and output method is OK](https://codegolf.meta.stackexchange.com/questions/2447/default-for-code-golf-input-output-methods?answertab=votes#tab-top).
## Test cases:
The two input matrices are shown with an empty line in between. The output is shown after `Output:`. When there are two output matrices then it's just to show other outputs that would be accepted.
**Test case #1**
```
Inputs:
[a]
[b]
Output:
[ab]
[ba]      <- Also OK
```
**Test case #2**
```
Inputs:
[a, b]
[1, 4] 
[y, {]
[%, 4, 1] 
[a, b, c]
Output:    
[a% ba, a4 bb, a1 bc] 
[1% 4a, 14 4b, 11 4c] 
[y% {a, y4 {b, y1 {c]
```
**Test case #3:**
```
Inputs:
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 1, 2, 3]
[4, 5, 6, 7]
[a]
[b]
[c]
[d]
Output:
[1a 2b 3c 4d]
[5a 6b 7c 8d]
[9a 1b 2c 3d]
[4a 5b 6c 7d]
[d4 c3 b2 a1]      <-- Also OK
[d8 c7 b6 a5]
[1b 9a c2 3d]
[a4 b5 d7 6c]
```
If your response to the rules about requiring `ab cd` instead of `a*b+c*d` is: [you should avoid cumbersome input/output formats](https://codegolf.meta.stackexchange.com/a/8077/31516), then I'd like note that the input and output formats are very flexible. The fact that you can't use `*` and `+` for products and sums might make it harder to use a simple built-in, but [I don't consider that negative thing.](https://codegolf.meta.stackexchange.com/a/10132/31516)
  
[Answer]
# [Haskell](https://www.haskell.org/), ~~62~~ ~~61~~ 59 bytes
```
e=[]:e
z=zipWith
a!b=[unwords.z(++)r<$>foldr(z(:))e b|r<-a]
```
[Try it online!](https://tio.run/##HcgxDoMgFIDh3VM8XxwgWg9gpJfo0IEwQMVCSsUAxoT07pR2@//PyPjSzpWiGReTbjLLdr/bZBrZKsaP7fRhiWMmfU/D3F1X75ZAMpko1aA@Yb5IUd7SbsBgP9ItBRghGn9CB5yjxAEVioHjo5ZGIaD9@Vrv@XdTy1YvXw "Haskell – Try It Online")
Example usage:
```
Prelude> [["a","b"],["c","e"]] ! [["f","g"],["h","i"]]
[["af bh","ag bi"],["cf eh","cg ei"]]
```
I found a way to get a `transpose` function in one byte shorter than using the import.
```
import Data.List;transpose
e=[]:e;foldr(zipWith(:))e
```
As the code then uses `zipWith` twice, two more bytes can be saved with the abbreviation `z=zipWith`.
---
**Old version with import:** (62 bytes)
```
import Data.List
a!b=[unwords.zipWith(++)r<$>transpose b|r<-a]
```
[Try it online!](https://tio.run/nexus/haskell#JYwxT8MwEEZ3fsVXqwOojcXI0FaqYGBgQGJgiDI4ybU@4drW@UKkqv89GNjee8PjS06ieE5RJQV7zDnw4JS/CU2DSDTSiFMS7NYHzJ4HDy7IQoWigiNeXfmiEPBkH/EuFKaRFv6fvjh19o2L3rlVv2@nOCcZi71y/mT195vNg9Srioslp0Lob7JrXLdcXP3ukSf9UIFF8WnGGm1rnNma3nTb1gyVyHQdVr/9VO38130lrn35AQ "Haskell – TIO Nexus")
This is quite similar to my answer to [non-symbolic matrix multiplication](https://codegolf.stackexchange.com/a/106479/56433): `a!b=[sum.zipWith(*)r<$>transpose b|r<-a]`, substituting the multiplication `(*)` with string concatenation `(++)` and `sum` with `unwords` which concatenates a list of strings with a space in between. The import is needed for the `transpose` function, so all in all the transposition of the second matrix uses up half of the bytes ...
---
**Old version without import:** (64 bytes)
```
a![]=[];a!b=(unwords.zipWith(++)[h|h:_<-b]<$>a):a![s:t|_:s:t<-b]
```
[Try it online!](https://tio.run/nexus/haskell#HYzBasMwEER/ZSxySEhseixuXCi99FjooQchgmxvIjWyJCS5hpJ/dzc5zPJmZxg7xZAK3oMvKbjmLUZnB13sL6Gu4YlGGnEOCcfNKxZjBwObERNl8gXW40PnKzmH5@YJn4ncPNKqK6k6qV501Xfb2S8hjbn5s/HbFrPd73fS3Ex7Ota94lW9a7mf23I7tXzv33XSvNwhzuWrJDTIJizYQEqhxUH0Qh2kGJjoQWemi1AK1b1h2FnWzyO7MjnWxPn6Dw "Haskell – TIO Nexus")
With the import and `transpose` function taking up so much bytes, I tried solving the task without import. So far this approach turned out being two bytes longer, but it might be more golfable. *Edit: The other approach at the top now beats the import!*
The list comprehension `[s:t|_:s:t<-b]` gets the non-empty tails of the lists in `b`, using just `[t|_:t<-b]` to get the tails would be 4 bytes shorter (even beating the import version) but append an empty row like `["","",""]` to the matrix which I suppose is not allowed.
[Answer]
## Mathematica, 36 bytes
```
Inner[#<>#2&,##,StringRiffle@*List]&
```
`Inner` is a generalisation of Mathematica's `Dot` (i.e. the usual matrix/vector product). It generalises the dot product by letting you provide two function `f` and `g`, which will be used in place of the usual multiplication and addition, respectively. We're replacing the multiplication with `#<>#2&` (which joins the the two characters into a single string) and the addition with `StringRiffle@*List`, which first wraps all the summands in a list, and then `StringRiffle` joins them together with spaces.
One could potentially use the `Dot` operator `.` and then transform the result, but the trouble is that things like `"a"*"a"` would immediately get transformed into `"a"^2` (same for sums), which would be annoying to pick apart again.
[Answer]
## Ruby, 61 bytes
```
->a,b{a.map{|x|b.transpose.map{|y|x.zip(y).map(&:join)*' '}}}
```
Sample run:
```
main(0):007> ->a,b{a.map{|x|b.transpose.map{|y|x.zip(y).map(&:join)*' '}}}[[[?a, ?b], [?1, ?4], [?y, ?{]], [[?%, ?4, ?1], [?a, ?b, ?c]]]
=> [["a% ba", "a4 bb", "a1 bc"], ["1% 4a", "14 4b", "11 4c"], ["y% {a", "y4 {b", "y1 {c"]]
```
```
->a,b{
a.map{|x|            # for each row of a
b.transpose.map{|y|  # and for each column of b
x.zip(y)             # match up corresponding elements
.map(&:join)         # join each pair together
*' '                 # join the entire thing on space
}}}
```
[Answer]
## Clojure, 53 bytes
```
#(for[a %](for[b(apply map vector %2)](map str a b)))
```
Running with arguments `[["a" "b"]["c" "e"]]` and `[["f" "g"]["h" "i"]]` returns `((("af" "bh") ("ag" "bi")) (("cf" "eh") ("cg" "ei")))`. This is actually shorter than the [numeric version](https://codegolf.stackexchange.com/a/106491/59617).
[Answer]
# [Jelly](https://github.com/DennisMitchell/jelly), 7 bytes
```
Z;"þK€€
```
This is a dyadic link that takes **B** and **A** as arguments (in that order) and returns **AB**. Input and output are in the form of 2D arrays of strings, which are actually 3D arrays of characters. A further byte could be saved by taking 2D arrays of *characters* as input. I'm not sure if that's allowed.
[Try it online!](https://tio.run/nexus/jelly#@x9lrXR4n/ejpjVA9P/w8kNbFR7u2P6oYY5zYk6OQklGqkJOZl623qOGuQpZIEWN2ypMDi2BqvHKz8xTSM7PKc3NK1ZIqlRIyy8tUiguSExOLQbriERWV5RfDlYENC81LTU1Bazk///oaHVVdR0FdRMQYageq8OlEK2eCOIkgYhk9dhYkBqoCETaEKIBwqkEcaqBygA "Jelly – TIO Nexus")
It's a bit hard to determine what Jelly does under the hood when strings are involved, since it does a lot of splattening before printing. [This is how Jelly represents input and output internally.](https://tio.run/nexus/jelly#@x9lrXR4n/ejpjVA9F/H@vDy8ENLj056uHMGkJ/1qGHOoW2Htv3/Hx2trqquo6BuAiIM1WN1uBSi1RNBnCQQkaweGwtSAxWBSBtCNEA4lSBONVAZAA "Jelly – TIO Nexus")
### How it works
```
Z;"þK€€  Dyadic link. Left argument: B. Right argument: A
Z        Zip/transpose B.
 ;"þ     Table vectorized concatenation; for each row in B' and each row in A,
         concatenate the corresponding strings.
    K€€  Join the arrays that correspond to the rows of A by spaces.
```
[Answer]
# [Dyalog APL](http://dyalog.com/download-zone.htm), 10 [bytes](http://meta.codegolf.stackexchange.com/a/9429/43319)
Takes matrices of characters as left and right arguments. Returns matrix of lists of characters. (APL represents strings as lists of characters.)
```
{∊⍺' '⍵}.,
```
[TryAPL online!](http://tryapl.org/?a=%28%u2355%27A%20%20%3D%27%20%28A%u21903%202%u2374%27ab14y%7B%27%29%29%20%28%u2355%27B%20%20%3D%27%20%28B%u21902%203%u2374%27%2541abc%27%29%29%20%u22C4%20A%7B%u220A%u237A%27%20%27%u2375%7D.%2CB&run)
Normal inner product is in APL `+.×`, but the addition and multiplication can be any functions, in particular:
Addition has been replaced by  
`{` an anonymous function:  
 `∊` the flattened  
 `⍺ ' ' ⍵` list consisting of the left argument, a space, and the right argument `⍵`  
`}`
Multiplication has been replaced by concatenation, `,`
[Answer]
## Prolog, >256 Bytes
I am using { \_ | \_ } which is a findall/3, \_ [ \_ , \_ ] which is some arg/3, and sum(\_) which is some aggregate. They can all be used inside is/2:
```
*(X, Y, Z) :- functor(Y, matrice, _), L is len(X[1]), L =:= len(Y), !,
   M is len(X), N is len(Y[1]),
   Z is { { sum({ X[J,K] * Y[K,I] | between(1,L,K) })
                                  | between(1,N,I) }
                                  | between(1,M,J) }.
```
Together with the [extra definitions](https://gist.github.com/jburse/b79e21447eda6843daadf52942026eff) for the aforementioned predicates and the non-standard is/2 that can return more than numbers, its sure >256 bytes.
[Answer]
## JavaScript (ES6), 65 bytes
```
(a,b)=>a.map(c=>b[0].map((_,j)=>c.map((e,i)=>e+b[i][j]).join` `))
```
Takes input as two 2D arrays of characters and returns a 2D array of strings. Add 10 bytes to support input as two 1D arrays of strings.
[Answer]
# Pyth, 14 bytes
```
clQmj;sMCd*QCE
```
A program that takes input of two newline-separated two-dimensional lists of characters and prints a two dimensional list of strings.
[Test suite](http://pyth.herokuapp.com/?code=clQmj%3BsMCd%2aQCE&test_suite=1&test_suite_input=%5B%5B%27a%27%5D%5D%0A%5B%5B%27b%27%5D%5D%0A%5B%5B%27a%27%2C%27b%27%5D%2C%5B%271%27%2C%274%27%5D%2C%5B%27y%27%2C%27%7B%27%5D%5D%0A%5B%5B%27%25%27%2C%274%27%2C%271%27%5D%2C%5B%27a%27%2C%27b%27%2C%27c%27%5D%5D%0A%5B%5B%271%27%2C%272%27%2C%273%27%2C%274%27%5D%2C%5B%275%27%2C%276%27%2C%277%27%2C%278%27%5D%2C%5B%279%27%2C%271%27%2C%272%27%2C%273%27%5D%2C%5B%274%27%2C%275%27%2C%276%27%2C%277%27%5D%5D%0A%5B%5B%27a%27%5D%2C%5B%27b%27%5D%2C%5B%27c%27%5D%2C%5B%27d%27%5D%5D&debug=0&input_size=2)
**How it works**
*[Explanation coming later]*
[Answer]
# [Pip](https://github.com/dloscutoff/pip), 17 bytes
```
{Y Zb{a._JsMy}Ma}
```
This is a function that takes two nested lists of (single-character) strings and returns a nested list of strings. [Try it online!](https://tio.run/nexus/pip#c3S0io42VDCK5VIAgmhjBRMoy1TBLDaWy8kJKK2eqKCepKCeDJVRT1FQT1VQTwNKc6VZ/a@OVIhKqk7Ui/cq9q2s9U2s/R@gEBSgoJGm4Oio4OSkyQXhODkB@Zr/AQ "Pip – TIO Nexus") (with two test cases).
### Explanation
Arguments to a `{}`-delimited function are assigned to the local variables `a` to `e`. The first argument of a lambda function is represented by `_`.
```
{               }  Define a function:
   Zb              Zip rows of b, transposing it
 Y                 Yank into global variable y for access in nested function
     {       }Ma   To the rows of a, map this function:
           My       To the rows of y (i.e. columns of b), map this function:
      a._           Concatenate, itemwise, the current row of a and row of y
         Js         Join the resulting list on space
                   The result of the outer map operation is returned
```
]