text:
Composing fill in the blanks
Let us say that we have a particular set of functions on strings.  These functions are kind of like fill in the blanks or madlibs, except that they only take one input and use that to fill in all of their blanks.  For example we might have a function that looks like
I went to the ____ store and bought ____ today.

If we applied this function to the string cheese the result would be:
I went to the cheese store and bought cheese today.

We can represent these functions as a non-empty list of strings, where the blanks are simply the gaps in between strings.  For example our function above would be:
["I went to the ", " store and bought ", " today."]

With this representation there is only one representation for every function of this sort and only one function for each representation.
A really neat thing is that the set of such functions is closed under composition.  That is to say composition of two of our functions is always another one of these functions.  For example if I compose our function above with
["blue ", ""]

(the function that prepends blue to the input)
We get the function:
["I went to the blue ", " store and bought blue ", " today."]

These can get a little more complex though.  For example if we compose the first function with
["big ", " and ", ""]

The result is
["I went to the big ", " and ", " store and bought big ", "and", " today."]

Task
Your task is to take two functions as described as non-empty lists of strings and output their composition as a non-empty list of strings.
For the purpose of this challenge a list can be any ordered container that permits
duplicates and a string may be a native string type, a list of characters or a list of integers.
This is code-golf answers will be scored in bytes with fewer bytes being better.
Test cases
["","xy"] ["ab",""] -> ["ab","xy"]
["x","y","z"] ["a","b"] -> ["xa","bya","bz"]
["xy"] ["ab"] -> ["xy"]
["","",""] ["a",""] -> ["a","a",""]
["x",""] ["","",""] -> ["x","",""]
["x","y","z"] ["a","b","c"] -> ["xa","b","cya","b","cz"]
["x","x","x"] ["a"] -> ["xaxax"]
["w","x","y","z"] ["ab","cd","e"] -> ["wab","cd","exab","cd","eyab","cd","ez"]

All 3 existing answers currently fail if some non-printable ASCII character is used in the input (SOH, TAB or LF, depending on the answer). So I think you should really decide if the input is restricted to printable ASCII or not.

@Arnauld Ok well as of now it is unrestricted and I have not seen a reason to change that so it will remain.

@SriotchilismO'Zaic In that case all six current answers are invalid.

@KevinCruijssen mine's valid since zero is not a character. Lucky language feature helping out.

@JonathanAllan Ah, I thought Jelly had mixed types so "0" and 0 would be the same, my bad. The other five are invalid, though.

@KevinCruijssen I do not know C#, 05AB1E, perl 5, or Javascript well enough to verify the answers are incorrect or what they are doing but I have informed flawr that the Haskell answer has this issue.

@SriotchilismO'Zaic My 05AB1E was joining/splitting by newlines. The JavaScript and Haskell answers are joining/splitting by tabs, the C# answer by the unprintable character `` (SOH), so those are all invalid as well. I don't know Perl 5 well enough either, though. So that one might be valid.

Does "unrestricted" refer to the ASCII range 1..127 or to the byte range 1..255? In other words, can we use non-ASCII characters in the range 128..255 as separators that will be guaranteed never to occur in the input strings?

@Roman You cannot assume that any character will not appear in the input so that you may use it as a separator.  You must actually solve the challenge.

Jelly, 6 bytes
j0j@ṣ0

A dyadic Link accepting the first function representation on the right and the second function representation on the left which yields the resulting function representation. Each function representation is a list of lists of characters (Jelly has no other strings).
Try it online! (the full-program arguments are given in Python notation; strings become lists. The footer shows a Python representation of the Link's output.)
Here is a test-suite which reformats the Link's output like the inputs.
How?
Takes advantage of Jelly's mixed type lists to allow the entire domain of representations (any list of lists of characters) by using the integer zero as a place-holder:
j0j@ṣ0 - Link: b, a        e.g.    b = [['a','b'],['c','d'],['e']]
       -                   ...and  a = [['w'],['x'],['y'],['z']]
                             (i.e. test-case ["w","x","y","z"] ["ab","cd","e"])
j0     - join b with zeros         ['a','b',0,'c','d',0,'e']
  j@   - join a with that          ['w','a','b',0,'c','d',0,'e','x','a','b',0,'c','d',0,'e','y','a','b',0,'c','d',0,'e','z']
    ṣ0 - split at zeros            [['w','a','b'],['c','d'],['e','x','a','b'],['c','d'],['e','y','a','b'],['c','d'],['e','z']
                             (i.e.: ["wab","cd","exab","cd","eyab","cd","ez"])

If we needed to deal with any of Jelly's mixed lists (including those of any depth or shape) we could use this eight byter: j,©⁹jœṣ® which uses the paired arguments as the place-holder.

Python 3.8 (pre-release),  60  58 bytes
lambda a,b:(v:='&'.join(a+b)+'$').join(b).join(a).split(v)

An unnamed function accepting two lists of strings, a and b, which returns a list of strings.
Try it online! Or see the test-suite.
How?
First forms a separator string, v, which cannot be found inside a or b. Then forms a string by joining up the strings in b with copies of v. Then forms a string by joining up the strings in a with copies of that. Finally splits that string at instances of v to give a list of strings.
While ensuring v is not in a or b we must also ensure that v wont make us split early in the case where all the strings in a and b are equal. To do so we form v by joining all the strings in both lists with instances of a string (here '&') and add an extra, different character (here '$'). Note that doing either in isolation is not enough as all strings in the inputs could equal the chosen character.

Could you give an example input where & is required? and using ''.join(a+b)+'$' is not enough?

It took me a while but ['$','$'] ['$','$'] would be one.

Yeah if all strings equal the chosen '$' character and the result will be more than one string we need a different character in there to avoid splitting early.

Haskell, 78 bytes
(a:b:r)#t@(x:s)|s>[]=(a++x):init s++((last s++b):r)#t|z<-a++x++b=(z:r)#t
x#_=x

Try it online!

05AB1E, 4 15 19 9 11 bytes
«TýR©ý¹sý®¡

Unlike the Jelly answer, 05AB1E's string "0", integer 0, and float 0.0 are all (somewhat) equal, so I can't split/join by an integer. This is why we had the +15 bytes as workarounds, although I've golfed it back to 9 bytes now. Thanks to @JonathanAllan for finding 2 bugs.
Try it online or verify all test cases.
Explanation:
«            # Merge the two (implicit) input-lists together
 Tý          # Then using a "10" delimiter join all strings together
   R         # Reverse this string
    ©        # Store this string in variable `®` (without popping)
     ý       # Use this string as delimiter to join the second (implicit) input-list
      ¹sý    # Then join the first input-list by this entire string
         ®¡  # And split it back on variable `®` so it's the expected list of strings
             # (after which this result is output implicitly)

This fails if the input has newlines (OP has said that the input is currently unrestricted).

@EriktheOutgolfer Every other answer has the same issue btw.

@EriktheOutgolfer Can definitely be golfed some more, but made a quick and dirty fix for now.

Cool. Could you use the idea of my Jelly alternative j,©⁹jœṣ® perhaps (uses the pair of arguments itself as a separator), or something similar?

@JonathanAllan I was actually just about to post something like that when I realized that. :)

...Nicely done :)

@JonathanAllan Thanks. I should have thought a bit more before posting that 19-byter though.. Had a frustrating day at work and it's currently almost 9 o'clock in the evening, so I lack a bit of concentration. Anyway, I'm content with the current 9-byter version. :)

Uh, sorry about this ...it wont work if the input lists contain strings only containing newlines :( (it'll split early)

@JonathanAllan Lol.. Ah well, I guess I can only thank you for finding these bugs.. I hope it's fixed now and you won't find anything else.. Although I have the feeling you might..

Japt, 8 bytes
Adapts Jonathan's approach.
qVqN²)qN

Try it
qVqN²)qN     :Implicit input of arrays U & V (N=[U,V])
q            :Join U with
 Vq          :  V joined with
   N²        :    Push 2 to N (modifying the original), which gets coerced to a string
             >     e.g., N=[["a","b"],["c","d"]] -> N=[["a","b"],["c","d"],2] -> "a,b,c,d,2"
     )       :End join
      qN     :Split on the modified N, which, again, gets coerced to a string
             > e.g., N=[["a","b"],["c","d"],2] -> "a,b,c,d,2"

What is N in this case? If I understand it correctly (using the search functionality of the TryIt-link), it repeats N two times (N²). It then uses that to join the second input V (VqN²), and then uses that entire string to join the first (implicit) input U (q...)). And finally splits the resulting string on N (qN). But what is N in this case?

Ah wait, I think I've looked at the wrong p(...) method in the search. It appends the 2 to both inputs paired together doesn't it. Only N² results in [["w","x","y","z"],["ab","cd","e"],2], and it uses that entire list to join. Why does the final qN not leave the 2 to the result-list in that case? Or does N² modify the original N?

@KevinCruijssen, added an explanation but you pretty much have it figured out. And, yes, pushing elements to an array in JS modifies the original array.

Wolfram Language (Mathematica), 62 61 bytes
""<>#&/@Flatten[#~(R=Riffle)~I/.I->#2~R~I]~SequenceSplit~{I}&

Try it online!
-1 thanks to Roman

Though it's not a valid output, this returns a function that actually does the job.. (34 bytes)
(g=a""<>a~Riffle~#&)[#]@*g[#2]&

Try it online!

61 bytes by recycling Riffle.

Haskell, 62 bytes
[a]#(c:d)=(a++c):d
(a:b)#c=a:b#c
[a]%b=[a]
(a:b)%c=[a]#c#(b%c)

Try it online!
Here is my Haskell answer.  It works on any type of list.

J, 44 43 42 29 bytes
_<;._1@,(;@}:@,@,.(,_&,)&.>/)

Try it online!
-13 bytes thanks to miles!
This approach uses integers and is due to miles.
original approach with strings
g=.[:}.@,,.
f=.(<@0<@;;._1@,];@g<"0@[)<@0<@g]

Try it online!
Note: I've adjusted -3 off the TIO to account for f=.
Uses Jonathan Allen's method, adapted for J.
This was surprisingly difficult to golf, since J doesn't have a built in "join" method, and I'd be curious to see if it can be improved significantly.
g is helper verb that gives us "join"

Working with list of integers as input, I found a 29 char solution, _<;._1@,(;@}:@,@,.(,_&,)&.>/) uses infinity _ as the sentinel value to know where to split <;._1. Joining is first done using reduce / to form one large box, then its just array shaping.

That's impressive.  Thanks @miles.  This one definitely felt like there was room to improve but I didn't see how.

@miles Shouldn't the g&.:(a.&i.&.>) count toward the bytes or am I missing something?

The OP mentioned that input could be as a list of characters or as a list of integers, so that helper function is just to convert from boxes of char arrays to boxes of int arrays for easier viewing

Ah I forgot that, thanks

Perl 5 (-lp), 20 bytes
As @JonathanAllan commented, this is a full-program using, for IO, a tab as a list separator and a newline to separate the two lists.
chop($n=<>);s/  /$n/g

TIO
the tab and newline were chosen because more convenient to check test cases, otherwise could be changed to non-printable characters \1 and \2.
(-02l012p)
chop($n=<>);s//$n/g

TIO
How it works,

-02 : to set input record separator to \2

-l : to remove input separator from default argument $_ and to add output record separator to default output

-012 : to set output record separator to \012 (\n) so that output is easier to check

-p : to print default argument

$n=<>; : to read next record and to assign to $n

chop$n; : to remove separator from $n

s/\x1/$n/g : to replace all occurences of \1 with $n

My Perl is almost non-existent but I believe that this is a full-program using, for IO, a tab as a list separator and a newline to separate the two lists. How can it accept input with these characters?

@JonathanAllan, you are correct, i did not have the time to add explanation when submitting i will try to do

JavaScript (Node.js), 85 79 bytes
([a,...b],[c,...d])=>b.map(e=>r.push(r.pop(r.push(r.pop()+c,...d))+e),r=[a])&&r

Try it online!

JavaScript, 37 bytes
Also adapts Jonathan's approach.
a=>b=>a.join(b.join(a+=b+0)).split(a)

Try it online

Hacked if you try to allow every possible string

JavaScript (ES6),  62  59 bytes
Saved 3 bytes thanks to @Shaggy
This is a fixed version of Luis' answer (now deleted) to support all characters.
a=>b=>a.map(e=escape).join(b.map(e)).split`,`.map(unescape)

Try it online!

all_licenses: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/


text:
Virus vs Antidotes code golf
There is a rectangular 2D array containing viruses denoted by 'v', antidote1 denoted by 'a', and antidote2 denoted by 'b' (there are no values other than 'v', 'a' and 'b').
Antidote1 can kill neighboring viruses in horizontal and vertical directions only, but antidote2 can kill neighboring(if any) viruses in horizontal, vertical and diagonal directions.
Once the antidotes are activated, how many viruses will remain at the end?
Examples:
Input:
vv
vv

Output: 4
Input:
av
vv

Output: 1
Input:
vvv
vbv
vvv

Output: 0
Input:
bvb
bav
vab
vvv
vvb
vvv
vvv
bva
vav

Output: 3

@EmbodimentofIgnorance that doesn't matter.

I appreciate your edits @Grimy - Also nice challenge :)

@manatwork, there are no values other that "v", "a" and "b".

@KevinCruijssen, it is not irregular shaped.

May we take 3 (distinct) arbitrary values instead of "v", "a", and "b"?

do the anti-viruses wrap around (ie, "a" in bottom row would remove a "v" in top row)?

Just a kindly reminder: the challenge is likely to remain closed until unclear points have been clarified. The corresponding answers must be integrated in the body of the challenge (users are not supposed to read the comments, which may later be removed anyway). Also, we have a sandbox to help fixing a question before it is posted to the main site. Enjoy your stay!

@Brian Test case #4 implies no (horizontal) wrap.

@Kiara Dan I would advise not allowing any 3 distinct values, as it keeps some character in the challenge, as well as possible forced cleverness with code points of the letters.

Python 3, 126 bytes
j=''.join
g=lambda*s:eval('j(s)'+4*'.replace("%s%s","%s%s")'%(*'vbbbbvbbavacvaca',))
f=lambda x:j(map(g,*map(g,x))).count('v')

Try it online!
-2 bytes thanks to Kevin Cruijssen
Explanation
Replaces all 'v' to 'b' if found next to 'b'. Next, replaces all 'v' to 'c' if found next to 'a'. A second iteration with the transposed version of the array clears all vertical and diagonal viruses. Finally, it will return the remaining number of 'v's.

Without eval:
Python 3, 133 bytes
j=''.join
g=lambda*s,r=str.replace:r(r(r(r(j(s),'vb','bb'),'bv','bb'),'av','ac'),'va','ca')
f=lambda x:j(map(g,*map(g,x))).count('v')

Try it online!

You can remove the space after y>1else. Nice approach though. At first I wasn't sure how this deals with the diagonal b, but that seems to work just fine due to your replacements. :) +1 from me.

@KevinCruijssen Thanks! The diagonals are taken care of by replacing 'v' with 'a' if they are next to 'b'. In the second iteration, the adjacent 'v's are then removed.

For the following input, output should be 3, but its returning 4 :bvb
bav
vab
vvv
vvb
vvv
vvv
bva
vav

@KiaraDan Ah, in that case my 05AB1E answer has the same issue, being a port of this. I'll delete my answer for now. The incorrect part is the bottom section btw: vvv bva vav. It will become avc bca cac, so fails to replace the v from the diagonal connection with b.

@KiaraDan Thanks! I fixed it with an additional replacement sequence.

164 bytes by using j=''.join in your fixed version

@KevinCruijssen Found an even shorter one, but your suggestion saves another byte!

JavaScript (ES7), 108 bytes
Takes input as a matrix of characters.
f=m=>(g=(y,X,V)=>m.map(r=>r.map((v,x)=>V?v>f&V>'a'>(x-X)**2+y*y-2?r[x]=n--:0:v<f?g(-y,x,v):n++)|y++))(n=0)|n

Try it online!
Similar to my original answer, but doing V>'a'>(x-X)**2+y*y-2 is actually 1 byte shorter than using the hexa trick described below. ¯\_(ツ)_/¯

JavaScript (ES7), 109 bytes
Takes input as a matrix of characters.
f=m=>(g=(y,X,V)=>m.map(r=>r.map((v,x)=>V?v>f&(x-X)**2+y*y<V-8?r[x]=n--:0:v<f?g(-y,x,'0x'+v):n++)|y++))(n=0)|n

Try it online!
How?
The quadrance of two points \$A_1=(x_1,y_1)\$ and \$A_2=(x_2,y_2)\$ is defined as:
$$Q(A_1,A_2)=(x_2−x_1)^2+(y_2−y_1)^2$$
Considering integer coordinates, it looks as follows:
$$\begin{matrix}
&8&5&4&5&8\\
&5&2&1&2&5\\
&4&1&\bullet&1&4\\
&5&2&1&2&5\\
&8&5&4&5&8
\end{matrix}$$
Therefore:

a type A antidote located at \$A_1\$ is able to kill a virus located at \$A_2\$ if \$Q(A_1,A_2)<2\$
a type B antidote located at \$A_1\$ is able to kill a virus located at \$A_2\$ if \$Q(A_1,A_2)<3\$

Conveniently, this exclusive upper bound (\$2\$ or \$3\$) can be obtained by converting the antidote character from hexadecimal to decimal and subtracting \$8\$:

\$\text{A}_{16} - 8_{10} = 2_{10}\$
\$\text{B}_{16} - 8_{10} = 3_{10}\$

Commented
f =                      // named function, because we use it to test if a character
                         // is below or above 'm'
m => (                   // m[] = input matrix
  g = (                  // g is a recursive function taking:
    y,                   //   y = offset between the reference row and the current row
    X,                   //   X = reference column
    V                    //   V = reference value, prefixed with '0x'
  ) =>                   //
    m.map(r =>           // for each row r[] in m[]:
      r.map((v, x) =>    //   for each value v at position x in r[]:
        V ?              //     if V is defined:
          v > f &        //       if v is equal to 'v'
          (x - X) ** 2 + //       and the quadrance between the reference point and
          y * y          //       the current point
          < V - 8 ?      //       is less than the reference value read as hexa minus 8:
            r[x] = n--   //         decrement n and invalidate the current cell
          :              //       else:
            0            //         do nothing
        :                //     else:
          v < f ?        //       if v is either 'a' or 'b':
            g(           //         do a recursive call:
              -y,        //           pass the opposite of y
              x,         //           pass x unchanged
              '0x' + v   //           pass v prefixed with '0x'
            )            //         end of recursive call
          :              //       else:
            n++          //         increment n
      ) | y++            //   end of inner map(); increment y
    )                    // end of outer map()
  )(n = 0)               // initial call to g with y = n = 0
  | n                    // return n

thanks @Arnauld, can you also explain the code?

@KiaraDan Done.

05AB1E, 33 30 29 bytes
2F.•s¯}˜?•2ô€Â2ä`.:S¶¡øJ»}'v¢

Try it online or verify a few more test cases.
Port of @Jitse's Python 3 answer, so make sure to upvote him!
-1 byte thanks to @Jitse.
Explanation:
The legacy version has the advantage of being able to zip/transpose a string-list, where the new version would need an explicit S and J, since it only works with character-lists. But, the new version is still 3 bytes shorter by using €Â in combination with a shorter compressed string. In the legacy version, € would only keep the last value on the stack inside the map, but in the new version, it will keep all values on the stack inside the map.
2F                  # Loop 2 times:
  .•s¯}˜?•          #  Push compressed string "vbvabbca"
   2ô               #  Split it into parts of size 2: ["vb","va","bb","ca"]
     €Â             #  Bifurcate (short for duplicate & reverse copy) each:
                    #   ["vb","bv","va","av","bb","bb","ca","ac"]
       2ä           #  Split it into two parts:
                    #   [["vb","bv","va","av"],["bb","bb","ca","ac"]]
         `          #  Push both those lists separated to the stack
          .:        #  Replace all strings once one by one in the (implicit) input-string
            S       #  Then split the entire modified input to a list of characters
             ¶¡     #  Split that list by newlines into sublists of characters
               ø    #  Zip/transpose; swapping rows/columns
                J   #  Join each inner character-list back together to a string again
                 »  #  And join it back together by newlines
}'v¢               '# After the loop: count how many "v" remain

See this 05AB1E tip of mine (section How to compress strings not part of the dictionary?) to understand why .•s¯}˜?• is "vbvabbca".

You don't need bc => ba if you apply bv => ba before av => ac. Thus .•6øнãI• (compressed form of `"bvavbaac") is enough, saving 2 bytes.

@Grimy It results in 1 instead of 3 for the last test case however.

@KevinCruijssen two replacement steps instead of three seems to do the trick after all

@Jitse Thanks. The compression string is 2 bytes shorter, but I do now need .: (replace all once) instead of : (keep replacing all until it is no longer present). Still -1, though. :) Thanks for letting me know.

Java 10, 211 209 204 202 bytes
m->{int i=m.length,j,c=0,f,t,I,J;for(;i-->0;)for(j=m[i].length;j-->0;c+=m[i][j]>98?f/9:0)for(f=t=9;t-->0;)try{f-=m[I=i+t/3-1][J=j+t%3-1]==98||m[I][J]<98&(I-=i-J+j)*I==1?1:0;}finally{continue;}return c;}

Modification of my answer for the All the single eights challenge.
-9 bytes thanks to @ceilingcat.
Try it online.
Explanation:
m->{                           // Method with char-matrix parameter & int return-type
  int i=m.length,              //  Amount of rows
      j,                       //  Amount of columns
      c=0,                     //  Virus-counter, starting at 0
      f,                       //  Flag-integer
      t,I,J;                   //  Temp-integers
  for(;i-->0;)                 //  Loop over the rows of the matrix
    for(j=m[i].length;j-->0    //   Inner loop over the columns
        ;c+=                   //     After every iteration: increase the counter by:
            m[i][j]>98         //      If the current cell contains a 'v'
             f/9               //      And the flag is 9:
                               //       Increase the counter by 1
            :0)                //      Else: leave the counter unchanged by adding 0
      for(f=t=9;               //    Reset the flag to 9
          t-->0;)              //    Loop `t` in the range (9, 0]:
         try{f-=               //     Decrease the flag by:
           m[I=i+t/3-1]        //      If `t` is 0, 1, or 2: Look at the previous row
                               //      Else-if `t` is 6, 7, or 8: Look at the next row
                               //      Else (`t` is 3, 4, or 5): Look at the current row
            [J=j+t%3-1]        //      If `t` is 0, 3, or 6: Look at the previous column
                               //      Else-if `t` is 2, 5, or 8: Look at the next column
                               //      Else (`t` is 1, 4, or 7): Look at the current column
            ==98               //      And if this cell contains a 'b'
            ||m[I][J]<98       //      Or if there is an 'a'
              &(I-=i-J+j)*I==1?//      in a vertical/horizontal adjacent cell:
               1               //       Decrease the flag by 1
            :0;                //      Else: leave the flag unchanged by decreasing with 0
         }finally{continue;}   //     Catch and ignore any ArrayIndexOutOfBoundsExceptions,
                               //     which is shorter than manual checks
  return c;}                   //  And finally return the virus-counter as result

@ceilingcat The *I>0?1:0; will break the second test case, but thanks for the catch to finally for -2.

Perl (-00lp), 82 bytes
Using regex to replace v by space, then count the vs
/.
/;$,="(|..{@-})";$;="(|.{@-,@+})";$_=s/(a$,|b$;)\Kv|v(?=$,a|$;b)/ /s?redo:y/v//

TIO

Charcoal, 39 bytes
ＷＳ⊞υι≔⪫υ⸿θＰθ≔⁰ηＦθ«≧⁺›⁼ιv⁺№ＫＭb№ＫＶaηι»⎚Ｉη

Try it online! Link is to verbose version of code. Explanation:
ＷＳ⊞υι≔⪫υ⸿θＰθ

Join the input strings with \r characters and draw the result to the canvas.
≔⁰η

Clear the number of live virii.
Ｆθ«

Loop over the characters in the input.
≧⁺›⁼ιv⁺№ＫＭb№ＫＶaη

If the current character is a virus and there are no adjacent bs in any direction or as orthogonally then increment the number of live virii.
ι»

Repeat with the next character.
⎚Ｉη

Clear the canvas and print the total number of live virii.

source: Stack Exchange

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

sort: votes


text:
Does this addition pyramid puzzle have a unique solution?
Given an addition pyramid \$P\$, determine whether it can be solved. An addition pyramid consists of layers, each having one number less than the one below it. Layer \$i\$ is symbolized as \$P_i\$. \$P_1\$ is the base layer, and \$P_{i+1}\$ is the layer atop \$P_i\$. The \$j\$th number of \$P_i\$ is denoted as \$P_{i,j}\$. \$P_{i,1}\$ is the leftmost number of \$P_i\$, and \$P_{i,j+1}\$ is the number to the right of \$P_{i,j}\$. You may visualize \$P_{i+1,j}\$ residing on top of \$P_{i,j}\$ and \$P_{i,j+1}\$ at the middle, hence the name "addition pyramid".

\$\forall P_{i,j},P_{i,j}\in\mathbb N^*\$, that is, every number in the pyramid is a non-zero positive integer.
\$\forall i>1,P_{i,j}=P_{i-1,j}+P_{i-1,j+1}\$, that is, every number not on the base layer of the pyramid is the sum of the two numbers below it.
If \$P_1\$ has \$n\$ numbers, \$P_i\$ has \$n-i+1\$ numbers, therefore \$P_{i,n-i+1}\$ is the rightmost number of \$P_i\$. In simpler terms, each layer has one number less than the layer below it.

An addition pyramid puzzle \$Q\$ is an addition pyramid with some numbers removed (replaced with \$?\$). Its solution is an addition pyramid \$P\$, where \$\forall Q_{i,j}\ne{?},P_{i,j}=Q_{i,j}\$, that is, the numbers that were originally present in the puzzle have been left unchanged. Such a puzzle may have more than one solution.
Your job is, given an addition pyramid puzzle, to determine if it has exactly one solution.
Input
You can get input in any of the following forms, but be consistent:

Array of layers.
Array of layers, shaped like a pyramid using a consistent non-positive-integer value as a separator between elements (used only once each time) as well as left and right padding. The separator and the padding must be the same.
Array of layers with a consistent valid right or left padding (you must be consistent and not mix right and left padding in this case).

Please note that a consistent value that's not a strictly positive integer must be used to represent a missing number; this value can't be used as padding. Also, you can take the layers concatenated (you can still separate them), and the ordering can either be from the base to the top or from the top to the base.
Output
One of two consistent distinct values, where one represents the presence of a unique solution and the other the absence of a solution or the presence of more than one solution.
Rules

\$Q_{i+1,j}=Q_{i,j}+Q_{i,j+1}\$ will always be true if \$Q_{i,j},Q_{i,j+1},Q_{i+1,j}\in\mathbb N^*\$, that is, the input is guaranteed to not contain a number on top of two other numbers that isn't their sum if all three numbers are known.
\$\exists Q_{i,j},Q_{i,j}\ne{?}\$, that is, the pyramid will contain at least one known number.
Don't do these things.
This is code-golf, so the shortest answer wins! However, don't let that discourage you from posting a solution just because your language is "too verbose".

Test cases
An array with the layers from the top to the base is used for these test cases, with 0 representing \$?\$.
[[10], [0, 0], [0, 2, 0], [0, 0, 0, 1]] -> True
[[32], [0, 0], [0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0]] -> True
[[0], [1, 1]] -> True
[[1], [0, 0]] -> False
[[10], [5, 5], [2, 3, 2], [0, 0, 0, 0]] -> False
[[5], [0, 0], [0, 0, 0]] -> False

Worked examples
The test cases are worked here.
Unique solution 1
$$\begin{array}c&&&10\\&&?&&?\\&?&&2&&?\\?&&?&&?&&1\end{array}$$
Step 1: \$x+y=2\leftrightarrow x=y=1\$.
$$\begin{array}c&&&10\\&&?&&?\\&?&&2&&?\\?&&\color{red}1&&\color{red}1&&1\end{array}$$
Step 2: \$x=y=1\leftrightarrow x+y=2\$.
$$\begin{array}c&&&10\\&&?&&?\\&?&&2&&\color{red}2\\?&&1&&1&&1\end{array}$$
Step 3: \$x=y=2\rightarrow x+y=4\$.
$$\begin{array}c&&&10\\&&?&&\color{red}4\\&?&&2&&2\\?&&1&&1&&1\end{array}$$
Step 4: \$x+4=10\leftrightarrow x=6\$.
$$\begin{array}c&&&10\\&&\color{red}6&&4\\&?&&2&&2\\?&&1&&1&&1\end{array}$$
Steps 5-6 are similar to 4.
$$\begin{array}c&&&10\\&&6&&4\\&\color{red}4&&2&&2\\\color{red}3&&1&&1&&1\end{array}$$
So here we have our unique solution.
Unique solution 2
$$\begin{array}c&&&&&32\\&&&&?&&?\\&&&?&&?&&?\\&&?&&?&&?&&?\\&?&&?&&?&&?&&?\\?&&?&&?&&?&&?&&?\end{array}$$
Step 1: There's no obvious approach here, so let's try using the minimum possible values.
$$\begin{array}c&&&&&32\\&&&&?&&?\\&&&?&&?&&?\\&&?&&?&&?&&?\\&?&&?&&?&&?&&?\\\color{red}1&&\color{red}1&&\color{red}1&&\color{red}1&&\color{red}1&&\color{red}1\end{array}$$
Steps 2-5: It looks like the minimum values result in a solution, therefore this is the only solution and is therefore unique.
$$\begin{array}c&&&&&32\\&&&&\color{red}{16}&&\color{red}{16}\\&&&\color{red}8&&\color{red}8&&\color{red}8\\&&\color{red}4&&\color{red}4&&\color{red}4&&\color{red}4\\&\color{red}2&&\color{red}2&&\color{red}2&&\color{red}2&&\color{red}2\\1&&1&&1&&1&&1&&1\end{array}$$
Hint: There's a theorem about addition pyramid puzzles related to this puzzle that you can prove if you think hard enough.
Unique solution 3
$$\begin{array}c&?\\1&&1\end{array}$$
Step 1: \$x=y=1\rightarrow x+y=2\$.
$$\begin{array}c&\color{red}2\\1&&1\end{array}$$
This is an obviously unique solution.
No solution 1
$$\begin{array}c&1\\?&&?\end{array}$$
\$\min\mathbb N^*=1\rightarrow x,y\ge1\rightarrow x+y\ge2>1\$, so there is no solution.
No solution 2
$$\begin{array}c&&&10\\&&5&&5\\&2&&3&&2\\?&&?&&?&&?\end{array}$$
Steps 1-2: \$x+y=2\leftrightarrow x=y=1\$.
$$\begin{array}c&&&10\\&&5&&5\\&2&&3&&2\\\color{red}1&&\color{red}1&&\color{red}1&&\color{red}1\end{array}$$
From there, it follows that \$1+1=3\$, which is a contradiction, therefore there's no solution.
Non-unique solution
$$\begin{array}c&&5\\&?&&?\\?&&?&&?\end{array}$$
Two solutions:
$$\begin{array}c&&5&&&&&&&5\\&2&&3&&&&&3&&2\\1&&1&&2&&&2&&1&&1\end{array}$$
Since there are at least two solutions, there's no unique solution.

Somewhat related.

Jelly, 18 16 bytes
FṀ‘ṗLSƝƬ€Ṗ€a@ċ⁼1

Try it online!
A monadic link that takes the pyramid in reverse order and returns 1 for true and 0 for false. Generates all possible pyramids with a base up to the max number in the pyramid and checks whether there is one unique match for the input.
Thanks to @Arnauld for pointing out that this failed for [[1,0],[0]]; now corrected.
Thanks to @JonathanAlan for saving 2 bytes!
Explanation
F                | Flatten
 Ṁ               | Maximum
  ‘              | Increase by 1
   ṗ             | Cartesian power of this with:
    L            | - Length of input
        €        | For each:
       Ƭ         | - Repeat the following until no change
     SƝ          |   - Sum of neighbours
         Ṗ€      | Remove last element from each list
           a@    | Logical and input with each list
             ċ   | Count times input appears
              ⁼1 | Check if equal to 1

Very nice.  How does the  "generate all possibilties" logic work?

@Jonah the Catrtesian power ṗ of the max number in the grid with the length of the base. e.g. if The maximum number were 10 and the length of the base 4 then it would test everything from [1,1,1,1] to [10,10,10,10], i.e. 10000 possibilities.

Outputs truthy for [[0,0],[0]].

@KevinCruijssen I’ve asked for clarification whether input with no known values is valid. If so, I can change ‘ to »2 which also has the advantage of regaining the efficiency lost with my last change, albeit at the cost of a byte.

@KevinCruijssen now has been clarified that [[0,0],[0]] isn’t valid input.

...Ƭ€Ṗ€a@ċ⁼1 saves two bytes (unless there are edge cases with the AND not catered for by the tests?)

C# (Visual C# Interactive Compiler), 303 227 bytes
n=>{int i=n.Max(x=>x.Max()),j=n.Count,t=0,k,m=0,z;for(;t<Math.Pow(i,j);){k=t++;var s=n.Select(_=>(a:k%i+1,k/=i).a).ToList();if(n.All(x=>(z=0,b:x.All(o=>o==s[z++]|o<1),s=s.Skip(1).Select((a,b)=>a+s[b]).ToList()).b))m++;}m/=m-1;}

Throws exception if true, runs normally if false.
Try it online!

Wolfram Language (Mathematica), 85 88 bytes
Count[l=Length@#;NestList[2#~MovingMedian~2&,#,l-1]&/@Range@Max@#~Tuples~l,#/. 0->_]==1&

Try it online!
+3 fixed.
Brute force: for all bases with values 1..(sum of all numbers), see if the resulting pyramid matches the given form, and check if the total number of matches is 1. Takes input as a list of levels, base first, with 0 representing missing numbers.

05AB1E, 25 bytes
ZÌLsgãε©.Γü+}¨®š.S*˜O_}OΘ

Takes the pyramid layers in upside down order, base to tip (i.e. [[0,0,0,1],[0,2,0],[0,0],[10]]).
Also, there seems to be a bug somewhere in 05AB1E with .Γ inside a map.. The ©...®š should just be ...yš for -1 byte..
Try it online or verify a few more test cases.
A minor equal-bytes alternative for ©.ΓüO}®š could be [Ðg#üO}\): Try it online.
Explanation:
Z        # Get the flattened maximum of the (implicit) input (without popping)
 Ì       # Increase it by 2
  L      # Create a list in the range [1, max+2]
   sg    # Swap to get the input again, and get the length (amount of layers)
     ã   # Create a cartesian product of this list repeated that many times
ε        # Map each inner list to:
 ©       #  Store it in variable `®` (without popping)
  .Γ     #  Collect all results until the following doesn't change anymore:
    ü    #   Get the pairwise:
     +   #    Sums
   }®š   #  After we've collected all, prepend the original list `®`
 .S      #  Now compare this potential pyramid with the (implicit) input-pyramid
         #  (-1 if a<b; 0 if a==b; 1 if a>b)
   *     #  Multiply that with the (implicit) input-pyramid
    ˜O   #  Then take the flattened sum
      _  #  And check that this sum equals 0 (1 if truhy; 0 if falsey)
}O       # After the map, take the sum to get the amount of truthy values
  Θ      # And trutify it (== 1), since we must output distinct values instead of truthy/falsey
         # (after which the result is output implicitly)

Fails on many easy cases. Seems like you're trying to use a%b == 0 as a shortcut for a == b || a == 0, but that doesn't work because a could be a multiple of b.

Separate issue: the code returns true for cases like [[0,0],[0]], which have infinitely many solutions. I think just changing > to the correctly-accented I fixes that.

@Grimy Fixed by using .S* instead of the %, so just +2 bytes.

Haskell, 106 bytes
z=zipWith
a#b=a*b==a*a
f x=[1|t<-mapM(\_->[1..sum(sum<$>x)])x,all and$z(z(#))x$iterate(z(+)=<<tail)t]==[1]

Takes an upside down pyramid, e.g. [[0,0,0,1],[0,2,0],[0,0],[10]].
Try it online!
The brute force approach in Haskell:

create all possible base layers t (mapM(\_->[1..sum(sum<$>x)])x), where the numbers go from 1 to the sum of all numbers in the input pyramid
create a pyramid from t (iterate(z(+)=<<tail)t)
compare each layer element-wise with the input (z(z(#))x). The comparison function a # b returns True if both numbers are equal or a is zero (a*b==a*a).
take a 1 for every pyramid that matches and compare the resulting list to the singleton list [1].


text:
Shortest way to get a TypeError
It's simple, simply write the shortest code to raise a TypeError.
In Python you can do:
raise TypeError

However it should be shorter with a code that gives a TypeError without raising it.

this isn't really defined for other languages. You've also immediately answered the shortest possible way for Python...

@JoKing I answer one out of 3 or more, feel free to post the other 3 byte ones

This shouldn't be closed, but it's only well-defined for one language (Python)

I now made this a python golf

I'm retracting my close vote, since this is pretty clear. But I'm downvoting this because it is an extremely simple challenge with an obvious optimal answer with no possibility of improvement.

Oh right, you might want to post your challenges to the Sandbox before you post this here.

maybe add the tips tag since it's language-specific.

for chr1 in range(32, 128):
  for chr2 in range(32, 128):
    for chr3 in range(32, 128):
      code = chr(chr1) + chr(chr2) + chr(chr3)
      try:
        output = exec(code, {})
      except TypeError:
        print(code)
      except:
        pass

Try it online!
A naive search may result that you cannot trigger a TypeError within 2 characters. You may get a TypeError with 3 characters. All solutions including:
1. Math operator, non-numeric types

Math operator including +, -, ~
Non-numeric types including "", (), [], id, {}

+[]
-""
~id
2. Invoke number as function
0()

3. Matrix multiplication between numbers
@ is __matmul__ in python, read more here
0@0

4. Binary operator with float / complex number
~0.
~.0
~0j

5. Iterate over number
Thanks to @Dennis to point out this.
You may iterate some variable by star operator. And () for a tuple may be omitted.
*0,

JavaScript (V8), 4 bytes
1.()

Try it online!
[Output]
.code.tio:1: TypeError: 1 is not a function
1.()
  ^
TypeError: 1 is not a function
    at .code.tio:1:3

Python 3, 3 bytes
+''

Try it online!

Uh oh. I can not make my program less than 3 bytes. Anyway, nice trick!

@A__ Yeah, anyway you can post the other 3 byte ones

Python, 3 bytes
This is self-explanatory. The unary - operator does not take a string argument. This was covered in @tsh's solution above.
-""

Try it online!
Another one:
~id

Try it online!

Haha yeah nice idea i still have more than 2 different styles in mind tho

yeah, double quotes and that's about it

There is also -id and +id

Japt, 1 byte
Throws TypeError: U.í is not a function
í

Test it (Errors are displayed below the output field)

Or, a bit less trivial:
Japt, 2 bytes
Throws TypeError: (U++) is not a function
°(

Test it

Python 3, 3 bytes
+[]

It gives an TypeError: bad operand type for unary +: 'list

Python 3, 3 bytes
0()

raises a TypeError

I just made a program that finds all the possible combinations for one and two bytes, execs that, and no two bytes raised a TypeError. Therefore, raising an TypeError with less than three bytes is impossible.


text:
Move arrows along a contour
Sandboxed
Given a set of closed non-overlapping 2d contours (separated by at least one space even on diagonals) with arrows oriented consistently in the same clockwise or counter-clockwise direction (each contour has its own direction) and a positive number n, move the arrows n steps along the contours in the respective direction.
The arrows are represented by > v < ^ respectively for right, down, left and up directions. There the other characters are - (horizontal), | (vertical) and + (corner).
When an arrow is on a corner, it keeps its current direction and changes it only after the turn is taken.
There will always be a straight segment (or a space) between any two corners (like +-+ for the horizontal and similar for the vertical) - in other words the sharp U turns are forbidden. The segments between the corners are either vertical or horizontal and the bend at a corner is always 90 degree.
Input:

a positive integer - n - number of steps
an ASCII representation of the contours - it can be a multiline string, a list of strings, a list of characters and so on.

Output:
The same contours with all arrows shifted n steps in each contour's overall direction.
Test cases:
1.
Input:
n = 1
 +----->->
 |       |
 |       v---+
 |           |
 +---<-------+

Output:
 +------>+
 |       v
 |       +>--+
 |           |
 +--<--------+

2.
Input:
n = 2
 +-----+ +---+
 |     | |   |
 +-->--+ |   v
         |   |
 +--->---+   |
 |           |
 +------<<---+

Output:
 +-----+ +---+
 |     | |   |
 +---->+ |   |
         |   |
 +----->-+   v
 |           |
 +----<<-----+

3.
Input:
n = 3
 +---+   +---+   +-------+
 |   |   |   v   |       |
 ^   |   |   |   +-<-+   |
 |   |   ^   |       |   v
 |   +---+   +-->----+   |
 |                       |
 |   +-------+   +---+   |
 |   |       |   v   |   |
 +---+       +---+   +---+

Output:
 +>--+   ^---+   +-------+
 |   |   |   |   ^       |
 |   |   |   |   +---+   |
 |   |   |   |       |   |
 |   +---+   v----->-+   |
 |                       |
 |   +-------+   +---+   v
 |   |       |   |   |   |
 +---+       +-<-+   +---+

4.
Input:
n = 1
+--+
|  |
|  +---+
|      |
+----+ |
     | |
     +-+

Output:
+--+
|  |
|  +---+
|      |
+----+ |
     | |
     +-+

5.
Input
n = 4
^>>>>
^   v
^   v>>>>
^       v
<<<<<<<<v

Output:
^>>>>
^   v
^   v>>>>
^       v
<<<<<<<<v

6.
Input:
n = 1
^->
^ v
<<v

Output:
^>+
^ v
<<v

Write a function or a program solving the above task. The shortest code in bytes in every language wins. Don't be discouraged by the golfing languages. Explanation of the algorithm and the code is highly appreciated.

Can two contours touch their corners on a diagonal, or a contour touch itself like that?

"Given a set of closed non-overlapping 2d contours ... with arrows oriented consistently in the same clockwise or counter-clockwise direction" sounds to me like every contour is oriented in the same direction, whereas from the test cases, it seems the arrows only have be consistent within a contour.

@xnor Thanks for your comments!

No, contours are not allowed to touch each other/itself on a diagonal.
Each contour has its own directon.
I'll update the description.

@ngn No, it's a mistake - I'll correct it. Thanks for observing it!

Can I take input as a singleline StringBuilder and an integer representing the length of each line? (language is C#)

@EmbodimentofIgnorance Yes, you can.

Is input with no space between the walls possible? Eg: Try it online!.  I know you said "separated by at least one space" but I was unclear if that applied only to independent loops or if it applied to a single loop as well.

@Jonah No, it's not possible: There will always be a straight segment (or a space) between any two corners (like +-+ for the horizontal and similar for the vertical) - in other words the sharp U turns are forbidden.

@Arnauld Don't worry :)

JavaScript (ES6),  210 ... 182  180 bytes
Takes input as (m)(n), where \$m\$ is a list of lists of characters. Returns the result in the same format.
m=>g=n=>n?g(n-1,m=m.map((r,y)=>r.map((c,x)=>(i=0,h=$=>~$?(m[Y=y+($-2)%2]||0)[X=x+~-$%2]>h?"-|+"[n+=`;m[${Y}][${X}]=S[${$}]`,i?2:$&1]:h($^++i):c)((S="<^>v").indexOf(c)))),eval(n)):m

Try it online!
How?
You can follow this link to see a formatted version of the source.
Wrapper
The recursive function \$g\$ is just used as a wrapper that invokes the main code to move all arrows by 1 step and keeps calling itself with \$n-1\$ until \$n=0\$.
Update method
We can't safely move each arrow one at a time because we would run the risk of overwriting non-updated arrows with updated ones. Instead, we first remove all arrows and compute their new positions. We apply the new positions in a second time.
This is done by re-using \$n\$ as a string to store the position updates as JS code.
For instance, in the first test case, \$n\$ is set to:
"1;m[0][7]=S[2];m[1][8]=S[3];m[2][9]=S[2];m[4][3]=S[0]"

(Note that the leading number -- which is the original value of \$n\$ -- is harmless.)
The new positions are applied by just doing eval(n).
Directions
Each arrow is converted into a direction \$d\$ (named $ in the code), using the following compass:
$$\begin{matrix}
&1\\
0&+&2\\
&3
\end{matrix}$$
The corresponding values of \$dx\$ and \$dy\$ are computed this way:
 d | dx = (d - 1) % 2 | dy = (d - 2) % 2
---+------------------+------------------
 0 |        -1        |         0
 1 |         0        |        -1
 2 |        +1        |         0
 3 |         0        |        +1

Corners
If the next character in the identified direction is a space or is out of bounds, it means that we're located on a corner and we need to take a 90° or 270° turn. This is why the helper function \$h\$ is testing up to 3 distinct directions: \$d\$, \$d\operatorname{xor}1\$ and \$d\operatorname{xor}3\$.
If we're located on a corner, we overwrite the cell with +. Otherwise, we overwrite it with either - or |, depending on the parity of \$d\$.
Note: The parameter of \$h\$ is not named $ just because it looks uber l33t but also because it allows us to compare a given character with \$h\$ (implicitly coerced to a string) to know if it's a space (below "$"), a contour character (above "$") or another arrow (also above "$").
Animated version

f=
m=>g=n=>n?g(n-1,m=m.map((r,y)=>r.map((c,x)=>(i=0,h=$=>~$?(m[Y=y+($-2)%2]||0)[X=x+~-$%2]>h?"-|+"[n+=`;m[${Y}][${X}]=S[${$}]`,i?2:$&1]:h($^++i):c)((S="<^>v").indexOf(c)))),eval(n)):m

m = [
  [..."+---+   +---+   +-------+"],
  [..."|   |   |   v   |       |"],
  [..."^   |   |   |   +-<-+   |"],
  [..."|   |   ^   |       |   v"],
  [..."|   +---+   +-->----+   |"],
  [..."|                       |"],
  [..."|   +-------+   +---+   |"],
  [..."|   |       |   v   |   |"],
  [..."+---+       +---+   +---+"]
];

(F = _ => (o.innerHTML = m.map(r => r.join('')).join('\n'), m = f(m)(1), window.setTimeout(F, 100)))()

Thank you for the explanation!

K (ngn/k), 183 161 157 155 bytes
{A:"^>v<";D,:-D:(-1 0;!2);s:#'1*:\x;r:" -+|"r*+/'3':|0,|0,r:~^x;$[p:+s\&~^t:A?,/x;;:r];s#@[,/r;s/+q;:;A@D?-p-q:q@'*'&'~^x ./:/:q:+p+/:D@4!(t^0N)+/:0 1 3]}/

Try it online!
{ }/ when called with an int left arg n, this will apply the function in { } n times to the right arg
A:"^>v<" arrows
D,:-D:(-1 0;!2) ∆y,∆x for the 4 cardinal directions
s:#'1*:\x shape of the input: height,width
r:~^x countours - boolean matrix showing where the non-spaces are
r:" -+|"r*+/'3':|0,|0,r recreate the character matrix with a countour but without arrows, by counting self+upper+lower for each cell in r and replacing 1->-, 2->+, 3->|
t:A?,/x types of arrows: 0 1 2 3 for ^>v<, all other cells are represented as 0N (null)
p:+s\&~^t coordinates of the arrows
$[#p ;;:r] if there aren't any arrows, return r
q:+p+/:D@4!(t^0N)+/:0 1 3 all 3 possible new positions for each arrow - if it keeps going forward, if it turns left, and if it turns right
q:q@'*'&'~^x ./:/:q for each arrow choose the first option that lands on the countour
@[,/r;s/+q;:;A@D?q-p] flatten r and put on it the arrows at their new positions and with their new directions
s# reshape to the original shape

You are fast! I hope you'll explain the code after finish golfing it.

Thank you for the explanation!

Charcoal, 105 bytes
Ｗ¬ΦυΣκ⊞υＳ≔⊟υη≔⪫υ⸿θ≔⟦⟧υ≔>^<vζＰθＦθ¿№ζι«⊞υ⟦⌕ζιⅉⅈ⟧§+|-↨ＥＫＶ›κ ²»ιＦυ«Ｊ⊟ι⊟ι≔⊟ιιＦＩη«≔⊟Φ⁴∧﹪⁻⊖ι⊕λ⁴›§ＫＶ⁻⁵λ ιＭ✳⊗ι»§ζι

Try it online! Link is to verbose version of code. Includes 22 bytes used to avoid requiring a cumbersome input format. Explanation:
Ｗ¬ΦυΣκ⊞υＳ≔⊟υη≔⪫υ⸿θ≔⟦⟧υ

Conveniently input the contours and the number of steps.
≔>^<vζ

The direction characters are used several times so the string is cached here. The index of a direction character in this string is known as its direction.
Ｐθ

Print the original contours without moving the cursor.
Ｆθ

Loop over the characters in the contour.
¿№ζι«

If the current characters is a direction character...
⊞υ⟦⌕ζιⅉⅈ⟧

... then save the direction and position in a list...
§+|-↨ＥＫＶ›κ ²

... and replace the character with the appropriate line character.
»ι

Otherwise output the character and move on to the next character.
Ｆυ«

Loop over the saved positions.
Ｊ⊟ι⊟ι

Jump to the saved position.
≔⊟ιι

Extract the saved direction.
ＦＩη«

Loop over the appropriate number of steps.
≔⊟Φ⁴∧﹪⁻⊖ι⊕λ⁴›§ＫＶ⁻⁵λ ι

Find the direction of the next step, which is any direction that is neither reverse nor empty.
Ｍ✳⊗ι

Take a step in that direction. (Charcoal direction indices for the Move command are twice the value of my direction.)
»§ζι

Print the appropriate direction character.

Thank you for the explanation!

Hmm, why didn't I input n first? That would have saved 7 bytes...

APL (Dyalog Unicode), 111 bytesSBCS
{A[D⍳q-p]@q⊢' |+-'[c×3+/0,c,0]⊣q←⊃¨(⍸c←' '≠⍵)∘∩¨↓⍉D[4|0 1 3∘.+4~⍨,t]+⍤1⊢p←⍸4>t←⍵⍳⍨A←'v>^<'⊣D←9 11∘○¨0j1*⍳4}⍣⎕⊢⎕

Try it online!
similar to my k answer