text:
Write a Whitespace Interpreter
Challenge:
Your challenge is to write an interpreter for Whitespace. Given a string consisting of spaces, tabs, newlines, and potentially other characters, as well as possible inputs for the Whitespace program itself, output the result of the given Whitespace program.
Here is an overview of the Whitespace language and its builtins:
Whitespace is a stack-based language which uses only three characters: spaces (ASCII codepoint 32); tabs (ASCII codepoint 9); and newlines (ASCII codepoint 10); all other characters are ignored.
It only has a couple of basic builtins, which I will go over below. Whitespace has a stack, which can only consist of integers, as well as a heap, which is a map of integers (both the key and value).
From here on out I will be using S for spaces, T for tabs, and N for newlines to make the text more compact.
Stack Manipulation (always starts with leading S):

Push a number to the stack: SS, followed by either an S/T for positive/negative respectively, followed by some S and/or T which is the binary representation of the number (S=0; T=1), followed by a trailing newline N. Some examples:

SSSTN pushes the number 1; a positive integer with binary 1.
SSTTSN pushes the number -2; a negative integer with binary 10.
SSSTSTSN pushes the number 10; a positive integer with binary 1010.
SSTTTSSTSSN pushes the number -100; a negative integer with binary 1100100.
Pushing number 0 is an edge case, since it can be done in multiple ways. Some examples:

SSSN: push a positive integer without any binary digits.
SSTN: push a negative integer without any binary digits.
SSSSN: push a positive integer with binary 0.
SSTSSSN: push a negative integer with binary 000.

Duplicate the top of the stack: SNS.
Copy the 0-based \$n\$th item from the top of the stack to the top of the stack: STS followed by a number similar as mentioned earlier (excluding the leading SS). I.e. let's say the stack currently contains the integers [47,12,0,55], then we could use STSSTSN to copy the 0-based 2nd item (which is the 12 in this case) to the top. So the stack becomes: [47,12,0,55,12].

NOTE: This index may not be negative. On TIO this would result in a negative index error, but that same program would push a 0 in the vii5ard interpreter, and it could even be different in yet another interpreter. For the sake of this challenge, you can therefore assume a given copy will never be negative. So the copy will always start with STSS, followed by the binary of the top-to-bottom index, followed by a trailing N.

Swap the top two items on the stack: SNT.
Discard the top item of the stack: SNN.
Discard/slice \$n\$ items from the top of the stack, but keep the top item: STN, followed by a number similar as mentioned earlier (excluding the leading SS). I.e. let's say the stack currently contains the integers [1,2,3,4,5,6,7], then we could use STNSTTN to discard 3 items from the stack (except the top one). So the stack becomes: [1,2,3,7].

You can again assume no negative slice values will be used, so this will always start with STNS, followed by the amount to slice, followed by a trailing N.

Arithmetic (always starts with leading TS):

Addition; add the top two items on the stack together: TSSS.
Subtraction; subtract the top item of the stack from the (top-1)th item of the stack: TSST.
Multiplication; multiply the top two items on the stack: TSSN.
Integer division; integer divide the (top-1)th item of the stack by the top item of the stack: TSTS. (NOTE: Since Whitespace only has integers, this will always be integer division and never result in decimal values.)
Modulo; take the modulo of the (top-1)th item of the stack with the top item of the stack: TSTT.

You can assume no negative values will be used for the modulo.

For each of these two argument builtins the same applies: if none or only a single integer is on the stack, this will result in an error. How you implement this error in your interpreter is up to you, as long as the program stops when this occurs. I thought about not allowing it for the sake of this challenge, but decided not to because it's a commonly used strategy to stop a program with an error when printing hardcoded texts, using the approach explained in this Whitespace codegolfing tip.
Heap Access (always starts with leading TT):

Pop the top two items of the stack, and store the top item in the (top-1)th address of the heap: TTS. I.e. let's say the stack contains the integers [1,2,3,4,5] and the heap already contains [{2:10}]. When you use this store builtin twice in a row, the stack would contain [1] and the heap will contain [{2:3},{4:5}] (note how the {2:10} has been replaced with the {2:3}).

NOTE: Just like with the Arithmetic builtins, if no or a single argument is given, it will cause an error. But for the sake of this challenge you can assume this will never be given for this builtin.

Pop the top item of the stack, and push the item corresponding with that heap address to the top of the stack: TTT. I.e. let's say the stack contains the integers [1,4] and the heap contains [{2:3},{4:5}]. If you now use the retrieve builtin once, the stack would become [1,5] (and the heap will remain the same).

NOTE: If you use an address that isn't in the heap yet (or the heap is empty), it will push a 0 to the stack instead. But for the sake of this challenge you can also ignore this.

Flow Control (always starts with leading N):

Mark a location in the program with a label: NSS, followed by some (optional) S/T which aren't used by other labels/subroutines, followed by an N. I.e. if you're only using a single label in your full program, NSSN would be what to use when code-golfing. If you need two or three labels, you can add NSSSN and/or NSSTN.

Although it is possible to have multiple of the same labels in the TIO and vii5args interpreters, it will cause issues, so we assume the input will always only create a label/subroutine once.
Also, although NSSN would be a logical first label to use, it's completely valid to use a label NSSTSTSTTTSN instead as only label in the program.

Call a subroutine with the given label: NST, followed by some (optional) S/T which aren't used by other labels/subroutines, followed by an N. I.e. NSTTSTSTTTSN would jump to the label TSTSTTTS as subroutine.
Jump unconditionally to a label: NSN, followed by some (optional) S/T, followed by an N. I.e. NSNN would jump to the (empty) label N and continue the program flow from there.
Pop the top integer, and jump to a label if it is exactly 0: NTS, followed by some (optional) S/T, followed by an N. I.e. if the stack is currently [4,1,0] and we'd use NTSSN, it would jump to the label SN and continue the program flow from there (with stack [4,1]). If instead the stack is currently [4,1] and we'd use the NTSSN, it would jump past it to the next builtin below it (with stack [4]).
Pop the top integer, and jump to a label if it is negative: NTT, followed by some (optional) S/T, followed by an N. I.e. if the stack is currently [4,1,-10] and we'd use NTTTN, it would jump to the label TN and continue the program flow from there (with stack [4,1]). If instead the stack is currently [4,1] and we'd use the NTTTN, it would jump past it to the next builtin below it (with stack [4]).

Minor note: There is no Jump to label if positive builtin available in Whitespace.

End a subroutine, and go back to the caller (a.k.a. return): NTN.
End the entire program: NNN (everything after that becomes no-ops).

I/O (always starts with leading TN):

Pop the top integer, and print as character with that codepoint to STDOUT: TNSS. I.e. if the stack is currently [10,101] and we'd call the TNSS twice, it will output a lowercase e followed by a newline to STDOUT.
Pop the top integer, and print as integer to STDOUT: TNST.
Pop the top integer, and read a character from STDIN, for which its codepoint-integer will be stored in the heap with the popped integer as address: TNTS. I.e. if the stack is [0,0], the heap is empty, and STDIN contains the capital letter I, and we'd use TNTS. The stack will become [0] and the heap [{0:73}]. (After which we could use the retrieve builtin TTT to put this input on the stack.)
Pop the top integer, and read an integer from STDIN, which will be stored in the heap with the popped integer as address: TNTT.

Challenge rules:

You can assume the Whitespace input is always valid with the builtins above. So the compilation phase would always succeed.
You can assume executing the Whitespace input will never result in any errors, except when the Arithmetic builtins will only get 0 or 1 stack-arguments instead of the required 2. Although there are loads of other possible errors when executing a Whitespace program, like negative indices, jumps to labels that doesn't exist, read from STDIN when it's empty, etc. For the sake of this challenge you can assume none of those kind of errors will occur, and the input-program is error-free (except for the Arithmetic builtins).
You can assume the additional inputs given will be valid as well. So an integer when we want to read an integer or a character / string of multiple characters if we want to read those.
The Whitespace program-input can be taken in any reasonable format. Could be a string, list of characters, list of codepoint-integers, etc. Same applies to the other inputs.
Any non-whitespace character in the Whitespace-program input is ignored. You can assume the no-op characters will only be printable ASCII. So the Whitespace input will only contain the UTF-8/ASCII characters with the codepoints [9, 10, 32..126].
Whitespace numbers can in theory be as large as you want, but for the sake of this challenge you can assume the integers used will be in the range [-9223372036854775808, 9223372036854775807] (signed 64 bit integer).

General rules:

This is code-golf, so shortest answer in bytes wins.
Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
Standard rules apply for your answer with default I/O rules, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call.
Default Loopholes are forbidden.
If possible, please add a link with a test for your code (i.e. TIO).
Also, adding an explanation for your answer is highly recommended.

Test cases:
You should copy the actual test cases from the Try it online links to verify your interpreter.
Input(s):
 SSTTSTTTTNSSSTSNSSSTNSTSSTNSSTTSTNSSTTSNSNSSSSTNSTSSTNSSTTSSTTTSNSSTTTSSTTNSSSNSSTTSTNSSTTTNSSSTSNSSTTNSSSTTTNSSSTSNSSTTSSTTTSNSSSTSNSSTTNSSSTTTNSSTTSNSSSTSNSSTTSSTTTSNSSTTTSSTTNSSTTTNSSTTSNSSTTSTNSSTTNSSTTSSTTTSNSSTTNSSSTTTNSSTTSTNSSSNSSTTSTNSSTTSNSNSSSSTNSSTTTTTSNNSSNSSSTTSTTTSNTSSSTNSSNSNN
Builtins used:
 Push num; duplicate; copy; add; create label; jump to label; print as char
Output:
 Pollinium milk; plump pumpkin; lollipop?

Try it online as actual program using raw spaces, tabs, newlines.
See this Whitespace answer of mine for an explanation.
Input(s):
 SSTTSNSNSTSSNTNST
Builtins used:
 Push num; duplicate; multiply; print as int
Output:
 4

Try it online as actual program using spaces, tabs, newlines, and comments.
Input(s):
 SSTTNTNSTNNNTSNTNTSSS
Builtins used:
 Push num; print as int; stop program; (no-ops)
Output:
 -1

Try it online as actual program using raw spaces, tabs, newlines.
See this Whitespace answer of mine for an explanation.
Input(s):
 SSSNSNSSNSTNTTTTTNSSNSNSTNSTSSSTSTSNTNSSSNTSSSTNTSSSSTSSTNSTSSTNSNSSSSTSSNTSTTSNSNTSSNSSSTNTSSTSNSNTSTNSSSTNTSSTNTSSSNSNTSTSSTNTSSTNSNNNSSSNSNNTSTSSTSSTSNSTSSTSNTSTTNTSNNNNNSSTNSNNTSSNNSNNNSSSSNTSSSNSNN
 21
Builtins used:
 Push num; duplicate; swap; copy; discard; add; subtract; multiply; divide; modulo; retrieve; create label; jump to label; jump to label if 0; stop program; read as int; print as char; print as int
Output:
 21
 21
 23
 20
 5
 25
 31
 24
 3
 27
 37
 26

Try it online as actual program using spaces, tabs, newlines, and comments.
See this Whitespace answer of mine for an explanation.
Input(s):
 NSSNSSSNSNSTNTSTTTSNSSSSTSTSNTSSTNTSSNSSSNSNSTNTSTTTTSSTNTSNSSSNTNSTNSSSN
 TThhiiss  iiss  ddoouubblee  ssppeeaakk!!\n
Builtins used:
 Push num; duplicate; subtract; retrieve; create label; jump to label if 0; read as char; read as int
Output:
 0

Try it online as actual program using spaces, tabs, newlines, and comments.
See this Whitespace answer of mine for an explanation.
Inputs(s):
 SSSNSNSTNTTTTTSSSNSNSTNTTTTTTSSSTNST
 -3
 5
Builtins used:
 Push num; duplicate; add; retrieve; read as int; print as int
Output:
 2

Try it online as actual program using spaces, tabs, newlines, and comments.
See this Whitespace answer of mine for an explanation.
Input(s):
 SSSTSSSTTTTTSSSSSSSTTSSSTSTTTTTSSTTSNTNST
Builtins used:
 Push num; print as int
Output:
 4815162342

Try it online as actual program using spaces, tabs, newlines, and comments.
See this Whitespace answer of mine for an explanation.
Input(s):
 SSSTTTNTNTSSSSTSSSSTNSSSTSTSNNSSTTNSSSTNTSSTSNSNTTSNSTSSTNSNTNSNTTNNSSSNSSSTTTNTTTSTNSSSTSTNTNSTSSSTSNNSSTNSNTSNNSNTTNSSSSSTSNTSTSSNSNTSSSNNSNTNNSSSSNNNN
 〹
Builtins used:
 Push num; duplicate; swap; discard; copy; slice; retrieve; create label; jump to label; jump to label if 0; jump to label if negative; exit program; read as char; print as char; print as int
Output:
 12345!!

Try it online as actual program using spaces, tabs, newlines, and comments.
Inputs(s):
 SSSTTNSNSSNSSNSTTSSSSTTTNTTSNSTNTNSSNNNSSTNNSSNTTTNTNSSTN
Builtins used:
 Push num; duplicate; store; retrieve; call subroutine; return; exit program; print as char; (no-ops)
Output:
   (character with unicode value 7)

Try it online as actual program using spaces, tabs, newlines, and comments.

Can the heap have a fixed size? If so, what's an acceptable size for it?

@DLosc Sure. And let's say at least 1000 (or perhaps 1024)? If you have another reasonable alternative feel free to suggest it. I've been codegolfing in Whitespace a few years now and overall I never saved too many stuff in the heap. Although tbf, with codegolfing you usually just overwrite the initial heap value since pushing address 0 is just the shortest, and in most cases you don't need to re-use the heap too much.

Form feeds are white space.

@user230118 So are carriage returns, zero-width spaces, etc.  I'm not the one who named the language. Either way, those can all be ignored like any other character, except for the three whitespace characters (newline, tab, space) that are mentioned.

Vim, 2366 bytes
:let@z=''
:%s/\S//eg
:%s/ /S/&
:%s/    /T/&
:%s/\n/N/&
$xo"Zyl:if"<C-v><C-r>z"=="SS"||"<C-v><C-r>z"=="STS"||"<C-v><C-r>z"=="STN"||"<C-v><C-r>z"=="NST"||"<C-v><C-r>z"=="NSN"||"<C-v><C-r>z"=="NTS"||"<C-v><C-r>z"=="NTT"<C-v>
norm fN<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="SNS"||"<C-v><C-r>z"=="SNT"||"<C-v><C-r>z"=="SNN"||"<C-v><C-r>z"=="TSSS"||"<C-v><C-r>z"=="TSST"||"<C-v><C-r>z"=="TSSN"||"<C-v><C-r>z"=="TSTS"||"<C-v><C-r>z"=="TSTT"||"<C-v><C-r>z"=="TTS"||"<C-v><C-r>z"=="TTT"||"<C-v><C-r>z"=="NTN"||"<C-v><C-r>z"=="TNSS"||"<C-v><C-r>z"=="TNST"||"<C-v><C-r>z"=="TNTS"||"<C-v><C-r>z"=="TNTT"||"<C-v><C-r>z"=="NNN"<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="NSS"<C-v>
norm hhxxrmfN<C-v>
let@z=''<C-v>
en<C-v>
l@t<Esc>^"tC"Zyl:if"<C-v><C-r>z"=="SS"<C-v>
norm @a<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="STS"<C-v>
norm @b<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="STN"<C-v>
norm @c<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="SNS"<C-v>
norm @d<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="SNT"<C-v>
norm @e<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="SNN"<C-v>
norm @f<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TSSS"<C-v>
norm @g<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TSST"<C-v>
norm @h<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TSSN"<C-v>
norm @i<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TSTS"<C-v>
norm @j<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TSTT"<C-v>
norm @k<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TTS"<C-v>
norm @l<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TTT"<C-v>
norm @m<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="NST"<C-v>
norm @o<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="NSN"<C-v>
norm @p<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="NTS"<C-v>
norm @q<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="NTT"<C-v>
norm @r<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="NTN"<C-v>
norm @s<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TNSS"<C-v>
norm @u<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TNST"<C-v>
norm @v<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TNTS"<C-v>
norm @w<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="TNTT"<C-v>
norm @x<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="m"<C-v>
norm fNl<C-v>
let@z=''<C-v>
elsei"<C-v><C-r>z"=="NNN"<C-v>
k<C-v>
el<C-v>
norm l<C-v>
en<C-v>
@n<Esc>^"nClylmc'sO<C-v><Esc>p:s/T/-/e<C-v>
:s/S/+/e<C-v>
"9xms`cytN'sp^x@y^"9PC<C-v><C-r>=<C-v><C-r>"<C-v>
<C-v><Esc>ms`cfNl<Esc>^"aCllytNmc'sO<C-v><Esc>p@y<C-v><C-a>^Dms@"jy$'spms`cfNl<Esc>^"bCllytNmc'so<C-v><Esc>p@y^DJ@"dd`cfNl<Esc>^"cCmc'sy$O<C-v><C-r>"<C-v><Esc>ms`cl<Esc>^"dCmc'sddpkms`cl<Esc>^"eCmc'sddms`cl<Esc>^"fCmc'sy$ddmsC<C-v><C-r>=<C-v><C-r>0+<C-v><C-r>"<C-v>
<C-v><Esc>`cl<Esc>^"gCmc'sy$ddmsC<C-v><C-r>=-<C-v><C-r>0+<C-v><C-r>"<C-v>
<C-v><Esc>`cl<Esc>^"hCmc'sy$ddmsC<C-v><C-r>=<C-v><C-r>"*<C-v><C-r>0<C-v>
<C-v><Esc>`cl<Esc>^"iCmc'sy$ddmsC<C-v><C-r>=<C-v><C-r>"/<C-v><C-r>0<C-v>
<C-v><Esc>`cl<Esc>^"jCmc'sy$ddmsC<C-v><C-r>=<C-v><C-r>"%<C-v><C-r>0<C-v>
<C-v><Esc>`cl<Esc>^"kCmc'sy$ddDJms'h:s/ <C-v><C-r>"(\d*)//eg<C-v>
A <C-v><C-r>"(<C-v><C-r>0)<C-v><Esc>`cl<Esc>^"lCmc'sy$'h/ <C-v><C-r>"(<C-v>
%yT('sC<C-v><C-r>0<C-v><Esc>`cl<Esc>^"mCfN:let@9=col('.')+1<C-v>
vTNy/m<C-v><C-r>"<C-v>
fNlmc'xO<C-v><Esc>"9pmx`c<Esc>^"oCfNvTNy/m<C-v><C-r>"<C-v>
fNl<Esc>^"pCmc'sDJ`c:if<C-v><C-r>"==0<C-v>
norm fNvTNlly/m<C-v><C-v><C-v><C-r>"<C-v><C-v><C-v>
fNl<C-v>
el<C-v>
norm fNl<C-v>
en<C-v>
<Esc>^"qC
mc'sDJ`c:if<C-v><C-r>"<0<C-v>
norm fNvTNlly/m<C-v><C-v><C-v><C-r>"<C-v><C-v><C-v>
fNl<C-v>
el<C-v>
norm fNl<C-v>
en<C-v>
<Esc>^"rCmc'xDJmx`c@"|<Esc>^"sCmc'sDJms`oA<C-v><C-r>=nr2char(<C-v><C-r>-)<C-v>
<C-v><Esc>mo`cl<Esc>^"uCmc'sDJms`o$"-pmo`cl<Esc>^"vCmc'iDJ'sO<C-v><C-r>=char2nr('<C-v><C-r>"')<C-v>
<C-v><Esc>ms`c@l<Esc>^"wCmc'iDJ'sO<C-v><C-r>"<C-v><Esc>ms`c@l<Esc>^"xC0i0<C-v><Esc>y$@=len("<C-v><C-r>"")<C-v>
I(<C-v><Esc>^x:s/S/*2)/eg<C-v>
:s/T/*2+1)/&<C-v>
^C<C-v><C-r>=<C-v><C-r>"<C-v>
<C-v><Esc><Esc>^"yDo<Esc>mxo
Stack:
<Esc>mso
Heap:
<Esc>mho
Input:
<Esc>mio
Output:
<Esc>mo:let@z=''

Try it online!
I sure do love me a thicc Vim program.
This program replaces all of the spaces, tabs, and newlines with the letters STN. This is only necessary for the newlines, because Vim is primarily a text editor and treats them differently, but it does it to each character for consistency. It then takes each Whitespace command and puts it into its own macro. Here's a list of all of the macros, and what command they map to. After creating all of the macros, it goes through a compilation phase, followed by an execution phase.
The compilation phase goes through the program, and for every NSS command, it replaces the NSS with an m, to be able to easily jump to it later.
The execution phase collects characters into the "z register, and once the register matches a command, the macro for that command is executed, and the "z register is cleared.
The stack is simply a bunch of lines containing a number, with the top of the stack having the label s. When we want to access the top of the stack, we just jump to the label, then we can use the c label to jump back to the code.
The heap is a line that stores many values in the form key(value). To set a value, the program deletes the matching key/value pair if it exists, then adds the key/value to the end of the heap. To get the value, it just does / key(, which finds the key, then it uses %yT( to copy only the value.
Input can be passed to the program by adding `ii<input> to the beginning of the footer. Each value must be on a separate line to work: Try it online! The gg@tgg@n at the end of the footer compiles and runs the program. To view only the output of the Whitespace program, add `idH to the end of the footer.

JavaScript (Node.js),  608 597 586  551 bytes
Takes input as (source)(input), where input is an array containing single characters and/or integers.
s=>I=>eval([..."@CDEJKLMNQTUWYZ^_bkmqw"].reduce((s,c)=>(a=s.split(c)).join(a.pop()),"(R=X=>(H={},o=P=[],S=[],z=x=p=i=0,gUs[p]?~(j=` 	\n`.indexOf(s[p++]N?j:gK:3,hUgK<2?Mn*2+j):V=n,GUx=z--&&S.pop(y=x),FUg(x=`mbQQ$mS[z+~(b])TSCce((z-=V=b-1,V)$mkJLmyJkTTLH[x]=y$mHD)qR[M1)]=_?R[P@p),V]:_Y_&!kY_&k<0Yp$E?P.popK:pT$^QQQQQqW+yw-yw*yw/y|0w%yN:^QTTo+=Buffer(D)$o+=k$Z.codePointAtKZ`Ct`$`[n-9],x&&eval(x,n=1N<3&&F(n*3+jN(1N(0)||R(1)||owN:^$WqTT$mz=S@kGKbgK?-M0):M0N_p$M1),E^E?g:pZ$HD=I[i++]Y?R[V]:Wz>1?(LmxU=n=>T$$QqqN))Mh(Lk,k,K()J),mx)$Ep=XD[k]C.spli@.pusM"))

Try it online! (all test cases without comments)
Try it online! (an example with a commented source code as input)
How?
Because the code is packed with RegPack, it is more efficient to repeat the same pieces of code over and over rather than defining too many helper functions.
The sequences of spaces, tabs and linefeeds are converted to an integer in base 3 with a leading \$1\$ until they match a known value:
 seq. | mnemonic | base 3 | decimal
------+----------+--------+---------
 SS   |    PSH   |    100 |     9
 STS  |    CPY   |   1010 |    30
 STN  |    SLI   |   1012 |    32
 SNS  |    DUP   |   1020 |    33
 SNT  |    SWP   |   1021 |    34
 SNN  |    DIS   |   1022 |    35
------+----------+--------+---------
 TTS  |    PUT   |   1110 |    39
 TTT  |    GET   |   1111 |    40
------+----------+--------+---------
 NSS  |    LBL   |   1200 |    45
 NST  |    JSR   |   1201 |    46
 NSN  |    JMP   |   1202 |    47
 NTS  |    JZE   |   1210 |    48
 NTT  |    JMI   |   1211 |    49
 NTN  |    RTN   |   1212 |    50
 NNN  |    END   |   1222 |    53
------+----------+--------+---------
 TSSS |    ADD   |  11000 |   108
 TSST |    SUB   |  11001 |   109
 TSSN |    MUL   |  11002 |   110
 TSTS |    DIV   |  11010 |   111
 TSTT |    MOD   |  11011 |   112
------+----------+--------+---------
 TNSS |    CHR   |  11200 |   126
 TNST |    INT   |  11201 |   127
 TNTS |    RCH   |  11210 |   129
 TNTT |    RNU   |  11211 |   130

The commands are simply stored in a lookup table and executed with eval().
Everything is wrapped within the function \$R\$ which is called twice:

First pass (\$X=0\$): the jumps and the stack errors are ignored so that the whole code is parsed linearly and all labels are stored
Second pass (\$X=1\$): the code is executed normally

Unpacked and formatted
s => I => (
  R = X => (
    H = {},
    o = P = [],
    S = [],
    z = x = p = i = 0,
    g = n => s[p] ? ~(j = ` \t\n`.indexOf(s[p++])) ? j : g() : 3,
    h = n => g() < 2 ? h(n * 2 + j) : V = n,
    G = n => x = z-- && S.pop(y = x),
    F = n => g(
      x = [
        /* PSH */ "z=S.push(g()?-h(0):h(0))",,,,,,,,,,,,,,,,,,,,,
        /* CPY */ "z=S.push(S[z+~(g()?-h(0):h(0))])",,
        /* SLI */ "S.splice((z-=V=g()?-h(0):h(0))-1,V)",
        /* DUP */ "z=S.push(G()),z=S.push(x)",
        /* SWP */ "G(),G(),z=S.push(y),z=S.push(x)",
        /* DIS */ "G()",,,,

        /* PUT */ "G(),G(),H[x]=y",
        /* GET */ "z=S.push(H[G()])",,,,,

        /* LBL */ "R[h(1)]=p",
        /* JSR */ "h(1),p=X?R[P.push(p),V]:p",
        /* JMP */ "h(1),p=X?R[V]:p",
        /* JZE */ "h(1),p=X&!G()?R[V]:p",
        /* JMI */ "h(1),p=X&G()<0?R[V]:p",
        /* RTN */ "p=X?P.pop():p",,,
        /* END */ "p=X?g:p",,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,

        /* ADD */ "z>1?(G(),G(),z=S.push(x+y)):p=X?g:p",
        /* SUB */ "z>1?(G(),G(),z=S.push(x-y)):p=X?g:p",
        /* MUL */ "z>1?(G(),G(),z=S.push(x*y)):p=X?g:p",
        /* DIV */ "z>1?(G(),G(),z=S.push(x/y|0)):p=X?g:p",
        /* MOD */ "z>1?(G(),G(),z=S.push(x%y)):p=X?g:p",,,,,,,,,,,,,,

        /* CHR */ "o+=Buffer([G()])",
        /* INT */ "o+=G()",,
        /* RCH */ "H[G()]=I[i++].codePointAt()",
        /* RNU */ "H[G()]=I[i++]"
      ][n - 9],
      x && eval(x, n = 1)
    ) < 3 && F(n * 3 + j)
  )(1)
)(0) || R(1) || o

This is awesome :D

Pip Classic, 441 399 377 bytes
,:mn:@>gs:lt:v**@_*FBTM_a:(Ja@wTR"
"012`(00|01.|20.|21[01]).*?2|1[02]..|...`)M{!a@<2?"lPU(t".a@>2.')a@<3=10?"lPUl@(t".a@>3.')a@<3=12?"l:@lALl@>++(t".a@>3.')2=@a?("7080I!370I3<z70i:POs00sPUi7"^0a@<3%13).a@>3a=20?"lPU@l"a=21?"S@ll@o"a=22?3a=110?"Y36"a=111?"lPUm@3"a@1?("O C30O30Y APO@60YPO6"^0a)98J['*x"//"'%'+'-]@a}Wi<#a{Va@iR9"Y3l?lPU3"R8"y;Vk"R7"i:a@?"R6"nm@3:y"R3C`POl`++i}

Try it online!
Takes the Whitespace code as its first command-line argument, and the arguments to the Whitespace program as the following command-line arguments. (A string of characters should be given as a single argument.) The heap has a fixed size of 1000 entries.
How?
The broad-strokes version:

Strip non-whitespace characters from code
Transliterate space, tab, and newline to 0, 1, and 2
Use regex to break the program into a list of valid statements
Translate each statement into Pip code
While the program counter (initially set to 0) is less than the length of the program, execute the statement at that index and increment the program counter

When the program needs to halt, either because the Halt instruction was executed or because there were not enough operands for an arithmetic operation, it does so by throwing an error using the idiom Vk (explained in this tip).
Ungolfed & commented
Here's the ungolfed version that I started from. Note: this is written in modern Pip, so it won't work on TIO. I've restructured the golfed version a bit, particularly to compress some of the cases in the translation section, but the basic approach is the same.
;;;;;;;;;;;
;; Setup ;;
;;;;;;;;;;;

; Use S/T/N temporarily for ease of development
$codepage : "STN"

; Stack starts out empty
$stack : []
; Heap size is 1000 (initial values don't matter)
$heap : u RL 1000

; Whitespace code is first command-line argument
$code : a
; Program inputs are remaining command-line args
$inputs : g @> 1
; Program counter starts at 0
$pc : 0

; To handle subroutines, we need to store a stack of return-to line numbers
$return_addrs : []

; Function to decode number literals
$to_int : {
  $magnitude : FB TM a
  $sign : (-1) E @a
  $sign * $magnitude
}

;;;;;;;;;;;;;
;; Parsing ;;
;;;;;;;;;;;;;

; Remove characters from code that aren't in codepage
$code FI: _ N $codepage
; Transliterate code from codepage to 0 (space), 1 (tab), and 2 (newline)
$code TR: $codepage 012

; Split code into separate instructions
$command_rgx : `(00|01.|20.|21[01]).*?2|1[02]..|...`
P $code : (J $code) @ $command_rgx

; Translate each instruction into Pip commands
$program : $code M {
  $instr : a
  ; Push a number
  $instr @< 2 Q 00 ? "$stack PU " . ($to_int $instr @> 2)
  ; Copy nth number on stack
  $instr @< 3 Q 010 ? "$stack PU $stack @ " . ($to_int $instr @> 3)
  ; Slide n numbers off from under top of stack
  $instr @< 3 Q 012 ? "$stack : $stack @ 0 AL $stack @> " . 1 + ($to_int $instr @> 3)
  ; Label (no-op)
  $instr @< 3 Q 200 ? $instr @> 3
  ; Gosub label
  $instr @< 3 Q 201 ? "$return_addrs PU $pc; $pc : $program @? " . $instr @> 3
  ; Goto label
  $instr @< 3 Q 202 ? "$pc : $program @? " . $instr @> 3
  ; If top of stack is zero, goto label
  $instr @< 3 Q 210 ? "I PO $stack = 0 $pc : $program @? " . $instr @> 3
  ; If top of stack is negative, goto label
  $instr @< 3 Q 211 ? "I PO $stack < 0 $pc : $program @? " . $instr @> 3
  ; Dup
  $instr Q 020 ? "$stack PU $stack @ 0"
  ; Swap
  $instr Q 021 ? "$stack @ 0 :: $stack @ 1"
  ; Drop
  $instr Q 022 ? "PO $stack"
  ; Add
  $instr Q 1000 ? "Y PO $stack; $stack ? $stack PU (PO $stack) + y; V k"
  ; Subtract
  $instr Q 1001 ? "Y PO $stack; $stack ? $stack PU (PO $stack) - y; V k"
  ; Multiply
  $instr Q 1002 ? "Y PO $stack; $stack ? $stack PU (PO $stack) * y; V k"
  ; Divide
  $instr Q 1010 ? "Y PO $stack; $stack ? $stack PU (PO $stack) // y; V k"
  ; Modulo
  $instr Q 1011 ? "Y PO $stack; $stack ? $stack PU (PO $stack) % y; V k"
  ; Store top of stack on heap at second-on-stack address
  $instr Q 110 ? "Y PO $stack; $addr : PO $stack; $heap @ $addr : y"
  ; Recall number from heap at top-of-stack address
  $instr Q 111 ? "$stack PU $heap @ PO $stack"
  ; Print as char
  $instr Q 1200 ? "O C PO $stack"
  ; Print as number
  $instr Q 1201 ? "O PO $stack"
  ; Read char and store it on heap at top-of-stack address
  $instr Q 1210 ? "Y A PO $inputs @ 0; $addr : PO $stack; $heap @ $addr : y"
  ; Read number and store it on heap at top-of-stack address
  $instr Q 1211 ? "Y PO $inputs; $addr : PO $stack; $heap @ $addr : y"
  ; Return from subroutine
  $instr Q 212 ? "$pc : PO $return_addrs"
  ; Halt
  $instr Q 222 ? "V k"
  ; Unrecognized instruction
  ""
}

P $program
P "------------"

;;;;;;;;;;;;;;;
;; Execution ;;
;;;;;;;;;;;;;;;

; Loop while the program counter hasn't gone past the end of the program
W $pc < # $program {
  ; Eval the current statement
  V $program @ $pc
  ; Increment the program counter
  U $pc
}


text:
How many countries are in the European Union?
Tonight, 31 January 2020, Brexit will happen and the United Kingdom will leave the European Union, the first time that the number of EU member states will decrease.
Your job is to take a date and output the number of EU1 members on that date, according to the following table:
| Start      | End        | Number of members
| 0          | 1957-12-31 | 0
| 1958-01-01 | 1972-12-31 | 6
| 1973-01-01 | 1980-12-31 | 9
| 1981-01-01 | 1985-12-31 | 10
| 1986-01-01 | 1994-12-31 | 12
| 1995-01-01 | 2004-04-30 | 15
| 2004-05-01 | 2006-12-31 | 25
| 2007-01-01 | 2013-06-30 | 27
| 2013-07-01 | 2020-01-31 | 28
| 2020-02-01 | Inf        | 27

Input may take one of the following forms:

your language's date format
any ordering of integers for year, month and day with any separator (e.g. YYYYMMDD or DD/MM/YYYY)
number of days lapsed since some epoch.

This is code-golf, so shortest code wins!
1. or EEC before 1993

I see the Python answer is using an input as the number of days since 1957-12-31 and the JavaScript answer is taking an input in the format yyyyMM without the dd. Are these both allowed according to the "in any reasonable format"? Both would save bytes in my answer as well.

@KevinCruijssen Number of days since some epoch is OK. yyyyMM is not, as it does not encode a date.

I feel like in any reasonable format is not objective enough...

@LuisMendo I think it's OK. It just has to uniquely specify the day. Are you worried there is some possible loophole?

@Anush The problem is how to tell if a format qualifies as "reasonable" or not. For instance, I wouldn't have guessed that Number of days since some epoch (or even months?) does. So a clearer specification is needed

@LuisMendo I have clarified the input format.

@RobinRyder Thanks. I have retracted my close vote

Note that the new input spec invalidates some answrs. You should notify the authors so they can fix them

@luismendo Thanks. Yes, I plan on notifying them as soon as I get back to a desktop computer.

Your data is incorrect as the European Union was founded on November 1, 1993

Looks like I was off by a year or so :/

@Rene I am also considering the EEC as the EU's predecessor.

@Robin Ryder, then you should refer to the EEC, not to the EU

pours a 1.18L for the UK *

Should that be -Inf as the starting point for the first line?

@ilkkachu You don't need to be able to handle dates Before the Common Era.

First, I thought you missed the addition of the GDR to EEC, but then I realisized that the GDR was added to the Federal Republic of Germany, and still counting as one country. So your numbers are still correct.

Javascript, 85 83 Bytes
a=d=>d<0?0:d<180?6:d<276?9:d<336?10:d<444?12:d<556?15:d<588?25:d<666?27:d<745?28:27

It takes an input as a float as the months / fractions of months passed since 1958-01-01
(0 for 1958-01-01T00:00:00 and a negative number for any previous date)
(Since number of days from some epoch is allowed, I assume that also a number of months is valid, as well)
Try it Online

80 Bytes
(credits: Arnauld)
a=d=>d<0?0:d<180?6:d<276?9:d<336?10:d<444?12:d<556?15:d<588?25:27+(d>=666&d<745)

Sad to see you go, UK

Awesome Arnauld!

I have clarified what counts as a reasonable input format for dates; number of days since an epoch is allowed but not number of months. Your input format was creative! But it was a loophole, which I have now closed. Your previous version based on number of days would be fine.

since JavaScript can't compete with many other golfing languages I wanted to at least be creative. :)

05AB1E, 29 27 26 25 33 bytes
¨12βŽ₅b-‘´`<lp€¸‘Ç.¥@•¿“0p•12в<*O

Try it online!
Input is in the form [yyyy, mm, dd].

The most impressive part about this answer is that you thought about using floats as input-format so the compressed integers can all be much shorter. :D

@KevinCruijssen I actually took this idea from the JS answer. I added credit to my answer.

@KevinCruijssen yes it was impressive, lol

I have clarified what counts as a reasonable input format for dates; number of days since an epoch is allowed but not number of months.

Python 2, 110 97 bytes
lambda d:ord('069:<?IKLK'[sum(d>i for i in(0,5479,8401,10227,13514,16922,17897,20270,22676))])-48

Try it online!
-13 bytes, thanks to Jonathan Allan
Takes input as number of days since 1957-12-31 (so 1958-01-01 is day 1)

Python 3, 93 bytes
lambda d:b'069:<?IKLK'[sum(d>i for i in(0,5479,8401,10227,13514,16922,17897,20270,22676))]-48

Try it online!
-4 bytes, thanks to mypetlion

Save 13 by avoiding the import of bisect

Python 3 port saves 4 bytes by replacing ord('069... with b'069...

@JonathanAllan Thanks!

@mypetlion Thanks :)

05AB1E, 42 36 bytes
•AÂʒë.š¡ε%ž·7í•ŽL}в.¥›O•=γ1sæΔ•₆вsè<

Input as number of days since 1957-12-31 (so 1957-12-30 is day -1; 1957-12-31 is day 0; 1958-01-01 is day 1; etc.)
Try it online or verify some more test cases.
Old 42 bytes answer taking input in the format yyyyMMdd:
¨¨•a3|}\§λ’Iœg½þ•ŽOΩв•32Ø•+@O•=γ1sæΔ•₆вsè<

Try it online or verify some more test cases.
•a3|}\§λ’Iœg½þ•ŽOΩв•32Ø•+ can alternatively be •Me1εä~.=ΔΩ»•Ž5ãв.¥•32Ù•+ for the same byte-count: Try it online or verify some more test cases.
Explanation:
•AÂʒë.š¡ε%ž·7í•    # Push compressed integer 813218926689775697373196902446
  ŽL}              # Push compressed integer 5480
     в             # Convert the larger integer to base-5480 as list:
                   #  [5479,2922,1826,3287,3408,975,2373,2406]
      .¥           # Undelta it with leading 0:
                   #  [0,5479,8401,10227,13514,16922,17897,20270,22676]
        ›          # Check for each if it's larger than the (implicit) input-integer
         O         # Take the sum to get the amount of truthy values
•=γ1sæΔ•           # Push compressed integer 122116126451824
 ₆в                # Convert it to base-36 as list:
                   #  [1,7,10,11,13,16,26,28,29,28]
   sè              # Swap to get the sum, and use it to index into this list
     <             # And decrease it by 1
                   # (since a compressed integer/list cannot contain a leading 0)
                   # (after which the result is output implicitly)

¨¨                 # Remove the last two digits from the (implicit) input (the "dd")
  •a3|}\§λ’Iœg½þ•  # Push compressed integer 2722385715080006519908031109868
   ŽOΩ             # Push compressed integer 6203
      в            # Convert the larger integer to base-6203 as list:
                   #  [1,1501,2301,2801,3701,4605,4901,5507,6202]
       •32Ø•       # Push compressed integer 195800
            +      # Add it to each value in the list:
                   #  [195801,197301,198101,198601,199501,200405,200701,201307,202002]
             @     # Check for each if it's larger than or equal to the input minus "dd"
O•=γ1sæΔ•₆вsè<     # Same as above

See this 05AB1E tip of mine (sections How to compress large integers? and How to compress integer lists?) to understand how the compression works.

Turing Machine Code, 972 1009 bytes
My input is the date in the format specified in the test cases YYYY-MM-DD.
0 0 0 * halt
* 1 _ r €
€ 9 _ r %
* 2 _ r $
$ 0 _ r £
* I 2 r ¢
% 5 _ r ^
% 6 6 r c
% 7 _ r x
% 8 _ r B
% 9 _ r i
% * _ r c
^ * 0 r c
^ 8 6 r c
^ 9 6 r c
B 0 9 r c
B 1 1 r r
B 2 1 r r
B 3 1 r r
B 4 1 r r
B 5 1 r r
B * 1 r e
r * 0 r c
e * 2 r c
x 0 6 r c
x 1 6 r c
x 2 6 r c
x * 9 r c
i 0 1 r
i 1 1 r
i 2 1 r
i 3 1 r
i 4 1 r
i * 1 r t
t * 5 r c
 * 2 r c
£ 0 _ r
£ 1 _ r ★
£ 2 _ r
 0 _ r !
 * 2 r ¢
! - _ r ~
~ 0 _ r 1
1 1 2 r ☆
1 * 2 r ¢
★ 0 2 r ¢
★ 1 2 r ¢
★ 2 2 r ¢
★ 3 _ r &
★ * 2 r ☆
& - _ r @
@ 0 _ r 6
6 0 2 r ¢
6 1 2 r ¢
6 2 2 r ¢
6 3 2 r ¢
6 4 2 r ¢
6 5 2 r ¢
6 6 2 r ¢
6 * 2 r ☆
☆ * 8 r c
 * 5 r c
 1 1 r
 2 1 r
 3 1 r
 4 _ r +
 5 2 r t
 6 2 r t
 * 2 r ¢
¢ * 7 r c
+ - _ r ¬
¬ 0 _ r 4
¬ * 2 r t
4 0 1 r t
4 1 1 r t
4 2 1 r t
4 3 1 r t
4 4 1 r t
4 * 2 r t
6 _ 6 l c
c * _ r c
c _ _ * halt

Try it online!
Added a few bytes thanks to Grimmy being a bit more thorough in testing my code than I was.

Seems like it’s all good now!

What's the point of the `` emoji and other multibyte characters? Can they be replaced with characters with lower bytecounts?

@cairdcoinheringaahing, It's the queen's crown. All of the multibyte characters were chosen for the occassion.

Charcoal, 48 bytes
Ｉ⌕γ§ &)*,/9;<;ＬΦ⪪”)¶↶⌕βγ⦄J≦σν{:Xδp⁴E⊙≕⍘Ｈ⊙βg”⁶‹ιθ

Try it online! Link is to verbose version of code. Takes input as YYYYMMDD. Explanation:
                 ”...”      Compressed string of YYYYMM values
                ⪪     ⁶     Split into substrings of length 6
              ＬΦ       ‹ιθ  Count those that appear before the input
   § &)*,/9;<;              Look the count up in a translation table
Ｉ⌕γ                         Subtract 32 from the ASCII code

Python 2, 158 150 bytes
i=int(input()[:6]);print((((((((27,28)[202002>i>201306],25)[i<200701],15)[i<200405],12)[i<199501],10)[i<198601],9)[i<198101],6)[i<197301],0)[i<195801]

Try it online!
Takes input as a string in YYYYMMDD format
Alternative Python 2 approach without imports. Simply uses nested list indexing to create the equivalent of a big if/elif structure.
NB: Posted by a British guy who is sorry to see us leave. I'm still all for the Community and working together (whether EU or here).

Here’s some improvements

Hey @Grimmy, that's well smart and different enough for you to post as your own answer. Fine by me. Same priciple, much cooler solution. I'll certainly upvote.

Jelly, 38 37 bytes
“€ɓ⁴5O/ṖṪOṁṪḋg’ḃ⁽×ỵÄŻ>⁸Sị“÷ñıÐ€½µ©¡ñ‘

Try it online!
A monadic link taking the zero-indexed count of days since 1958-01-01 as a integer argument and returning an integer.
Thanks to @JonathanAllan for saving a byte!

@RobinRyder revised to use days

>⁸TḢị“¡©µ½€Ðıñ÷ñ‘ -> >⁸Sị“÷ñıÐ€½µ©¡ñ‘ saves one (maybe with an off by 1 error to fix?)

Ah no, looks good, I was using wrong origin date. (d-1,d,d+1) :)

x86 (32-bit) assembly, 43 bytes (13 bytes code + 30 bytes data)
This routine expects input in ax as a signed short giving number of days since 1950-01-01, and returns output in al (clobbering edi along the way).
    .text
    .globl eu_members
eu_members:
    mov $.Ltbl-1, %edi
.Lloop:
    inc %edi
    scas (%edi), %ax
    jg .Lloop
    mov (%edi), %al
    ret
    .section .rodata
.Ltbl:
    .short 2921
    .byte 0
    .short 8400
    .byte 6
    .short 11322
    .byte 9
    .short 13148
    .byte 10
    .short 16435
    .byte 12
    .short 19843
    .byte 15
    .short 20818
    .byte 25
    .short 23191
    .byte 27
    .short 25597
    .byte 28
    .short 32767
    .byte 27

Exact opcodes of the code part (in a linked context so that the relocation of .Ltbl doesn't confuse things):
0804930b <eu_members>:
 804930b:       bf 49 a0 04 08          mov    $0x804a049,%edi
 8049310:       47                      inc    %edi
 8049311:       66 af                   scas   %es:(%edi),%ax
 8049313:       7f fb                   jg     8049310 <eu_members+0x5>
 8049315:       8a 07                   mov    (%edi),%al
 8049317:       c3                      ret

And here's the test harness I used (note that the assembly code is not PIC safe, so on Debian or Ubuntu systems you will need to pass -no-pie to gcc):
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>

unsigned char eu_members_wrap(short days_since_1950_01_01) {
    unsigned char res;
    __asm__("call eu_members" : "=a"(res) : "0"(days_since_1950_01_01) : "edi", "cc");
    return res;
}

int main(int argc, char* argv[]) {
  struct tm tm;
  time_t epoch, req;
  short days_since_epoch;
  memset(&tm, 0, sizeof(tm));
  tm.tm_year = 50;
  tm.tm_mon = 0;
  tm.tm_mday = 1;
  epoch = mktime(&tm);
  memset(&tm, 0, sizeof(tm));
  tm.tm_year = atoi(argv[1]) - 1900;
  tm.tm_mon = atoi(argv[2]) - 1;
  tm.tm_mday = atoi(argv[3]);
  req = mktime(&tm);
  days_since_epoch = (((unsigned int) (req - epoch)) / (24 * 60 * 60));
  /* printf("epoch = %ld, req = %ld\n", epoch, req);
  printf("Raw number of days: %hd\n", days_since_epoch); */
  printf("EU members: %hhu\n", eu_members_wrap(days_since_epoch));
  return 0;
}

Could you use lods (%edi), %al instead of mov    (%edi),%al? I am not sure about assembly syntax, but the opcode should work.

No, lods can only read from (%esi)

AWK, 98 bytes
{m=$1*12+$2-23496}1,$0=m<1?0:m<181?6:m<277?9:m<337?10:m<445?12:m<557?15:m<589?25:27+(m>666&&m<746)

Try it online!
Input format: YYYY MM DD

JavaScript (ES6), 95 bytes
Expects a number of days since 1957-12-31.
n=>[x=0,5479,2922,1826,3287,3408,975,2373,2406].map((d,i)=>x-=(n-=d)>0&&~('52012910'[i]||~1))|x

Try it online!
This is however a bit longer than @FabrizioCalderan's answer, even if it is fixed to use days instead of months.

Perl 5, 46 bytes
($q,%d)=split;$q--while!exists$d{$q};say$d{$q}

Try it online!
...or try like this on some decent command line:
query=19730101
data="0 0 19580101 6 19730101 9 19810101 10 19860101 12 19950101 15 20040501 25 20070101 27 20130701 28 20200201 27"
echo "$query $data" | perl -nE '($q,%d)=split;$q--while!exists$d{$q};say$d{$q}'

The data is supposed to be contained in the code, not passed as input.

Data is data, code is code, but sometimes code is data and data is code and E=mc²

source: Stack Exchange

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

sort: votes


text:
Choose 3 strings and output the exact minimum Hamming distance between any pair
Consider \$3\$ binary strings of length \$n\$ chosen independently and uniformly at random.   We are interested in computing the exact expected minimum Hamming distance between any pair. The Hamming distance between two strings of equal length is the number of positions at which the corresponding symbols are different.
Task
Given an input n between 2 and 10, inclusive, consider \$3\$ binary strings of length \$n\$ chosen independently and uniformly at random. Output the exact expected minimum Hamming distance between any pair.
Output should be given as a fraction.
Your code should run in TIO without timing out.

Challenges should be self-contained: Please add the definition of Hamming Distance.

I got slightly lost at the end, in the task section. You say "we sample" and then "compute the exact expected minimum hamming distance between any pair", but if we sampled, then there is no actual expectation, right? We just compute the Hamming distances? And then we output the minimum of the three?

@RGS Expected here means the mean average. I'll  change the wording to make it clearer. Thank you.

Can you clarify what you mean by between any pair? Is that any of the three pairs once the three strings have been chosen?

Could you please provide some test cases?

Also, do you actually have to generate the strings? Can you just choose a random value when comparing two characters?

@LuisMendo Yes that's right

@Anush Then please make it clear in the challenge text. People are not expected o read all comments

0.375, 0.75, 1.125, 1.5234375, 1.93505859375, ...?

Does "Output should be given as a fraction" mean decimals & floats are not allowed? (i.e. we should output a pair of integers)

@JonathanAllan. The answer has to be exact. The easiest way is a pair of integers but you could also output a possibly recurring decimal if you prefer.

The denominator will be a power of two, so the decimal will terminate.

I suggest the time restriction harder to miss in the spec, and tagging the challenge restricted-time. I suspect that the answers so far are too brute to meet the requirement.

I think the time limit is enough to stop fully brute forcing over the 2^30 triples of strings, but should allow setting one string to all zeroes, which doesn't affect the distribution, and brute forcing over the 2^20 values of the other two. I'd be interested to see faster methods.

@xnor My code may have three loops, but it only iterates over the $n+3 \choose 3$ ways to write $n$ as a sum of four nonnegative integers. For $n=10$ that is 286 cases.

@ChristianSievers I missed that. What a nice method! I added a formula to your post.

Pari/GP, 92 90 bytes
2 bytes saved thanks to @Nicolas!
n->sum(a=0,n,sum(b=0,n-a,sum(c=0,n-a-b,n!/a!/b!/c!/(n-a-b-c)!*min(a+b,min(a+c,b+c)))))/4^n

Try it online!
$$ f(n) = \frac{1}{4^n} \sum_{\substack{a+b+c+d=n\\a,b,c,d\geq 0}} \binom{n}{a,b,c,d}\min(a+b,a+c,b+c)$$
A more direct brute force approach may be shorter in some languages, but I'm not sure if that's true for Pari. Anyway, it's a shame that Pari's min only accepts two arguments.
I can avoid the min and be about 6 times faster, but the compensating additional code makes it longer. Maybe in another language this is the shorter way. And maybe it is possible to simplify further and get rid of the innermost sum.
n->sum(a=0,n,sum(b=a,n-a,sum(c=b,n-a-b,n!/a!/b!/c!/(n-a-b-c)!*(a+b)*6/(1+(a==b)+(b==c))!)))/4^n

Try it online!

This is a really elegant mathematical solution!

Would it be acceptable to place the f(n)= in the header section and save 5 bytes ? Asking as a new code-golfer.

@Nicolas The remaining part would be a term with n as free variable which is not okay, but I can rewrite it as f=n->... and don't count f=, then the remaining part states the function without binding it to a name. Thanks for reminding me!

Jelly, 31 bytes
Ḷṗ4S⁼¥Ƈɓ!×Ṗṁ4SƝṂƲ}:!P$}ð€S,4*$}

A monadic Link accepting an integer which yields a pair of integers, [numerator, denominator] (not reduced to simplest form).
Try it online! Or see all of n=2 to 10 reduced to simplest form.
How?
Uses the same approach as Christian Sievers' Pari/GP answer
Ḷṗ4S⁼¥Ƈɓ!×Ṗṁ4SƝṂƲ}:!P$}ð€S,4*$} - Link: integer, n
Ḷ                               - lowered range -> [0..n-1]
 ṗ4                             - Cartesian power 4 (all length 4 tuples using alphabet [0..n-1]
      Ƈ                         - filter keep those for which:
     ¥                          -   last two links as a dyad:
   S                            -     sum
    ⁼                           -     equals n?
       ɓ               ð€       - for each tuple do f(n, tuple):
        !                       -   factorial = n*(n-1)*...*1
                 }              -   use right argument:
                Ʋ               -     last four links as a monad:
          Ṗ                     -       pop i.e. (a,b,c,d)->(a,b,c)
           ṁ4                   -       mould like 4 -> (a,b,c,a)
              Ɲ                 -       for neighbours:
             S                  -         sum -> (a+b,b+c,c+a)
               Ṃ                -       minimum
         ×                      -   multiply
                      }         -   use right argument:
                     $          -     last two links as a monad:
                   !            -       factorial -> (a!,b!,c!,d!)
                    P           -       product -> a!×b!×c!×d!
                  :             -   integer division
                         S      - sum
                              } - use right argument:
                             $  -   last two links as a monad:
                           4    -     four
                            *   -     exponentiate -> 4^n
                          ,     - pair

Very nice. Maybe I should have made the range 2..30 :)

This does $n=30$ in ~18 seconds. It's much slower than the Pari/GP because I create all $n^4$ (a,b,c,d) tuples and filter to those that sum to $n$ (because it's golf).

05AB1E, 26 bytes
Ý4ãʒOQ}ε¨Ćü+ßI!*y!P÷}O4Im‚

Port of @JonathanAllan's Jelly answer, which uses the same formula as @ChristianSievers's Pari/GP answer.
Just like his answer, the output is not reduced to its simplest form.
Try it online or verify all test cases.
Explanation:
Ý                 # Push a list in the range [0, (implicit) input-integer]
                  # (NOTE: Jonathan's Jelly answer uses the range [0,input) instead of
                  #  [0,input], but that doesn't pose an issue, since the mapped value will
                  #  result in 0, not affecting the total sum)
 4ã               # Create all possible quartets by using the cartesian product with 4
   ʒ              # Filter these quartets by:
    O             #  Take the sum
     Q            #  And check if it's equal to the (implicit) input-integer
   }ε             # After the filter: map each remaining quartet [a,b,c,d] to:
     ¨            #  Remove the last item d: [a,b,c]
      Ć           #  Enclose the list, appending its own head: [a,b,c,a]
       ü+         #  Sum each consecutive pair: [a+b,b+c,c+a]
         ß        #  Pop and push the minimum of this
          I!      #  Push the input, and take its factorial
            *     #  Multiply both by each other
             y!   #  Take the factorial of each value in the quartet: [a!,b!,c!,d!]
               P  #  Take the product of this: a!*b!*c!*d!
                ÷ #  Integer-divide the two: (min(a+b,b+c,c+a)*n!) // (a!*b!*c!*d!)
    }O            # After the map: take the sum of all values in the list
       I          # Push the input-integer again
      4 m         # And take 4 to the power this
         ‚        # And finally pair both together
                  # (after which this pair is output implicitly as result)

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


text:
Repeat every other character in string starting with second character
Requirements:

Take a single word as input with only lowercase alphabetical characters (a-z)
Output a string where every other character is repeated, with the first repeated character being the second character in the string

Example:
Input: abcde
Output: abbcdde
Winning Criteria:
Standard code golf. Shortest number of bytes in program wins.
Clarification:
For languages with 1-based indexing the output must still match the above, aabccdee is not an acceptable solution.

May we start from 1 as the first character, for the benefit of languages with 1-based indexing?

Sure, i just called the first character 0th so my title "repeat odd index characters" makes sense. As long as you the output is repeating "Every other" character starting from the second character I the string (which I call index 1) then it's acceptable

i'll update the post to reflect that

To clarify, what I'm suggesting is that aabccdee is also a valid output for your lone testcase.

that is not acceptable

Is trailing white space permitted?

The title seems too long, I guess it can be shortened to just Repeat every other character.

I suggest you use standard I/O rules instead of requesting to use stdin (and never saying to use stdout, by the way). Or is there some reason to avoid it?

Also, python answer is already a function that actually uses argument for input and return for output, so I'm assuming that you actually allow default I/O ways and are not restricting to stdin.

@val i wasn't aware of the standard io rules, this is my first submission. Feel free to edit the post with the "community standard"

Excuse me but I don't understand the requirements. I'm not a native english speaker so maybe that's the problem : what does "every other character" means here ? 'Other' compared to what ? My understanding of the phrase "every other character" means to me that "abbccddee" is the right answer to the example...

@Neyt "Every other" is an English phrase that could mean all but one exception but in this case it does not.  It is similar to "alternating", for example "every other day" means "either all even days and no odd days or all odd days and no even days".  I don't think there is really any logic to it.  If you are still confused the ESL stack exchange is probably the place to ask about this further.

@PostRockGarfHunter Indeed, I don't see any logic behind this but thanks and good idea to post it on ESL (if not already) ^^

Jelly, 3 bytes
ḤÐe

A full program accepting a string which prints the result
Try it online!
How?
Utilises the fact that the implementation of the double atom, Ḥ, is multiplication by two, and that strings are lists of Python characters. In Python when a character is multiplied by two it becomes a Python string of length two (e.g. 'x'*2=='xx'). Lastly the implicit output of a list composed entirely of characters and strings (or lists thereof) is its content all smashed together.
ḤÐe - Main Link: list of characters  e.g. input abcd -> ['a','b','c','d']
 Ðe - apply to even indices (1-indexed):
Ḥ   -   multiply by 2                     -> ['a', 'bb', 'c', 'dd']
    - implicit, smashing print            -> abbcdd

sed, 12
s/.(.)/&\1/g

Try it online!

This is really lovely

brainfuck, 13 or 11 bytes
>,[.,[..,>]<]

Assumes EOF->0. :(
You can try it online!
(Assuming input also continues to give zeroes indefinitely after the first EOF, we can do it in 11 bytes:
,[.,[..>],]

though this eats memory.)

You may assume infinite time and memory for the purposes of code golf.

I don't necessarily agree with the "infinite time and memory" because BOGO sorting would be "allowed", which would be ridiculous. Imagine if a "check if a string is an anagram of another string" formula was "shuffle the second string, compare, and continue if unequal. If 2^n days have passed, where n is the length of the string, consider the strings non-anagrams". It would have an error rate less than the expected failure of a CPU while running a typical program.

@Mathgeek CPU failure is not usually a consideration for code golf, whereas program determinism is. And the expected runtime for Bogosort is O(n!), not O(2^n).

Python, 38 bytes
f=lambda s:s and s[:2]+s[1:2]+f(s[2:])

Try it online!
Takes the first two characters, then the second character, then removes the first two characters and recurses.

39 bytes
f=lambda s,c=2:s and s[:c]+f(s[1:],3-c)

Try it online!
Flips between taking the first two or first one character.

I really like these two answers, tbh

Oh, nice; two at a time!

I posted a 37 byte answer.

x86-16 machine code, IBM PC DOS, 14 12 bytes
Binary:
00000000: b401 cd21 f7d9 78f8 cd29 ebf4            ...!..x..)..

Unassembled:
    START:
B4 01   MOV  AH, 1      ; DOS read char from STDIN
CD 21   INT  21H        ; put char in AL
F7 D9   NEG  CX         ; toggle CX sign
78 F8   JS   START      ; if negative, loop to next char
CD 29   INT  29H        ; DOS write char to screen again
EB F1   JMP  START      ; loop until break/^C

A standalone executable DOS program.  Input via STDIN (pipe or keyboard interactive), output to STDOUT.
Output:

Python 2, 34 bytes (xnor's improvement)
lambda s:`[c*11for c in s]`[7::10]

Try it online!
Python 2, 36 bytes
lambda s:`sum(zip(s,s,s),())`[7::10]

Try it online!
Slices characters 7, 17, 27… out of a string like this:
('a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'e', 'e', 'e')
012345678901234567890123456789012345678901234567890123456789012345678901234
       ^         ^         ^         ^         ^         ^         ^
→ abbcdde

xnor's c*11 trick achieves the same thing, but with a string like:
['aaaaaaaaaaa', 'bbbbbbbbbbb', 'ccccccccccc', 'ddddddddddd', 'eeeeeeeeeee']
012345678901234567890123456789012345678901234567890123456789012345678901234
       ^         ^         ^         ^         ^         ^         ^
→ abbcdde

Python 3, 37 bytes
lambda s:''.join(c*3for c in s)[1::2]

Try it online!
If returning a tuple of characters is OK (which it isn't), lambda s:sum(zip(s,s,s),())[1::2] is a 33-byte solution.

What a clever idea! I've posted a bounty and will keep it up for the week.

It looks like you can save more bytes with a different string to slice, though interestingly also sliced [7::10]: TIO

J, 8 bytes
#~1 2$~#

Try it online!

1 2$~# Shape $~ the list 1 2 (repeating it cyclically as needed) until it matches the length # of the input.
#~ Use this 1 2 1 2... "mask" to Copy #~ the implicit input elementwise.  That is, make 1 copy of the first char, 2 copies of the 2nd char, 1 copy of the third char, etc.

Haskell, 33 24 bytes
By noticing that obviously f [] = [] also fits the pattern f s = s and removing one extra space, we get to
f(a:b:s)=a:b:b:f s
f s=s

from my starting point of
f []=[]
f (a:b:s)=a:b:b:f s
f s=s

Now my answer matches xnor's Haskell answer.
You can try it online!.

Haskell, 24 bytes
f(a:b:t)=a:b:b:f t
f s=s

Try it online!

This feels pretty similar to mine and now I feel stupid if I don't golf mine further. But then we'll have equal answers... So what now?

@RGS That's fine, go for it. Duplicate answers come up a fair bit here and are a good sign that the mutually found solution is indeed well-golfed.

Octave / MATLAB, 16 bytes
@(s)s(1:2/3:end)

Try it online!
Explanation
Non-integer values are automatically rounded (with a warning) in colon index expressions.

CJam, 9 8 bytes
q3e*1>2%

Try it online!
Explanation
  abcde             q     read input
→ aaabbbcccdddeee   3e*   repeat characters x3
→  aabbbcccdddeee   1>    drop first
→  a b b c d d e    2%    every other char

Esolanging Fruit saved 1 byte: 3f*s → 3e*.

Can you use 3e* instead of 3f*s?

It seems so! Good eye.

Python 3,  43 41  39 bytes
-2 thanks to mypetition (s[:1]*i can be s[:i] if we swap our order of is)
f=lambda s,i=2:s and s[:i]+f(s[1:],i^3)

A recursive function which accepts a string and returns a string.
Works in Python 2 too.
Try it online!
At each call we return s if it is empty or take the first up-to-i-characters of the given string (s[:i]) where i starts out as 2 and append (+) the result of another call to the function this time using a new s of all but the first character (s[1:]) and a new i found by XOR-ing with three (i^3) - i.e. 2, 1, 2, 1, ...

Really clever way of switching between 1 and 2!

f=lambda s,i=2:s and s[:i]+f(s[1:],i^3) saves 2 bytes

@mypetlion Good golf, thanks!

@mypetlion ...and it's just a short step from there to realising we can drop i entirely, which gives xnors f=lambda s:s and s[:2]+s[1:2]+f(s[2:]).

Japt -m, 4 bytes
+pVu

Try it
+pVu     :Implicitly map each character U at 0-based index V in the implicit input string
+        :Append to U
 p       :U repeated
  Vu     :  V mod 2 times
         :Implicit output of resulting string

What does the -m flag do?

@S.S.Anne, it enables the implicit map  mentioned in the explanation.

Scratch 3.0, 25 blocks/179 bytes

As SB Syntax:
define f(n
set[i v]to(1
set[o v]to(
repeat((length of(n))/(2
set[o v]to(join(o)(letter(i)of(n
change[i v]by(1
set[x v]to(letter(i)of(n
set[o v]to(join(o)(join(x)(x
change[i v]by(1

Oh boy, here I go Scratching again! This was quite an interesting one to solve, and I quite enjoyed it. Thanks for the challenge.
The output of the function is shown in the top left corner.
Finally, Try it online Scratch!

I really like this. Thabk you for the submission

124 bytes.TIO block syntax:http://scratchblocks.github.io/#?style=scratch3&lang=en&script=define%20f(n%0Aset%5Bi%20v%5Dto(0%0Aset%5Bo%20v%5Dto(%0Arepeat(length%20of(n%0Achange%5Bi%20v%5Dby(1%0Arepeat((2)-((i)mod(2%0Aset%5Bo%20v%5Dto(join(o)(letter(i)of(n

Unreadable, 43 bytes

'"""""'"""'""""'"'""""""""""'"'"'""""""""""

Try it online!
Displayed here in variable-width font, per the traditional tribute to the language name.
Exits with error after printing the correct output.
Explanation:
'"""""'"""      while(1)
'""""           do 2 things:
'"'""""""""""   print(read stdin)
'"'"'"""""""""" print(print(read stdin))

Uses the fact that '" both prints and returns its argument, which can thus be directly fed to a 2nd print command.

That's definitely unreadable.

Vyxal, 5 3 bytes
3•y

Try it Online!
3•  # Repeat each character three times
  y # Get every other character

Brainfuck, 52 31 bytes
,[>>+<[<..>->-]>[<<.>+>->]<<<,]

You can try it online or you can check my first submission, that I think is also simpler to understand:
+>+>>,[<<[-<->]<[->>+>>+<<<<]+>>>.>[-<.>]<,<[-<+>]>

Cell layout is
| 1 | aux | mult | inp | mult |

where mult is the number of extra times we have to print the current character. Feel free to drop me a line in the comments with feedback.
Try it online!

k4, 17 13 bytes
edit: make use of & (where operator) which for each index i of an int-list L give gives L[i] copies of i. eg &2 1 3 -> 0 0 1 2 2 2
{x@&(#x)#1 2}

{           } /lambda with implicit arg x
    (#x)      /count x
        #1 2  /takes #x items of 1 2 (eg 3#1 2 -> 1 2 1)
   &          /&1 2 1 -> 0 1 1 2
 x@           /index x

Shakespeare Programming Language, 126 bytes
,.Ajax,.Page,.Act I:.Scene I:.[Exeunt][Enter Page and Ajax]Ajax:Open mind.Speak thy.Open mind.Speak thy.Speak thy.Let usAct I.

Try it online!
Page reads the input one character at a time, and alternately prints it once or twice. Exits with error after printing the correct output.

PowerShell, 40 38 37 bytes
-join($args|% t*y|%{"$_"*(1+$i++%2)})

Try it online!
Takes input $args, transforms it toCharArray, pipes that into a loop. Each iteration, we repeat the character "$_" either 1 or 2 times based on a modulo-index. Those characters/strings are left on the pipeline, gathered up with a -join to turn it back into a single string, and output is implicit.
-2 bytes thanks to Veskah.
-1 byte thanks to mazzy.

Pretty sure you don't need quotes around $args for 38 bytes

@Veskah Thanks - that was a leftover from when I was originally writing the submission.

one more 37 bytes

@mazzy Clever. Thanks!

Ruby, 25 bytes
->s{s.gsub /.(.)/,'\0\1'}

Try it online!

brainfuck, 13 bytes
,[.<[>.>]>>,]

Try it online!
Handles odd and even length strings correctly. This takes an input and prints it once before checking if the previous cell contains the previous character. If so, it prints again and moves three spaces ahead, otherwise it just moves one cell ahead, and then it gets the next character.

This requires cells to the left of the tape.

@S.S.Anne While it is non-standard, multiple interpreters support it, including the ones on TIO and copy.sh (IIRC).

05AB1E, 5 4 bytes
€Ðιθ

I/O as a list of characters, which is allowed by default.
I have the feeling 4 bytes might be possible, but I'm unable to find it.
It is possible, by porting @emanresuA's Vyxal answer (so make sure to upvote him/her as well).
Try it online.
Explanation:
      #  (example input = ["a","b","c","d","e"])
€Ð    # Triplicate each character (which remains a flattened list)
      #  → ["a","a","a","b","b","b","c","c","c","d","d","d","e","e","e"]
  ι   # Uninterleave this list into two parts
      #  → [["a","a","b","c","c","d","e","e"],["a","b","b","c","d","d","e"]]
   θ  # Pop and leave just the second part
      #  → ["a","b","b","c","d","d","e"]
      # (which is output implicitly as result)

Python 3, 54 50 49 bytes
This looks incredibly long, I have no idea if something obvious is slipping under my nose... And already saved 5 bytes thanks to @Jonathan Allan! Check his 43 byte Python 3 answer! but here it is:
lambda s:''.join(c+i%2*c for i,c in enumerate(s))

You can try it online!

Save 2 with enumerate and 2 more by using a generator (dropping the []) - TIO

@JonathanAllan thanks for the tip!

Oh, another 1 by distributing over the addition and reordering to avoid % being treated as a format instruction: c*(1+i%2)->i%2*c+c (or c+i%2*c)

SNOBOL4 (CSNOBOL4), 84 bytes
	S =INPUT
S	S LEN(1) . L LEN(1) . R REM . S	:F(O)
	O =O L R R :(S)
O	OUTPUT =O S
END

Try it online!

Oh, nice! A fellow Bell Labs language.

Keg -ir -lp, 4 bytes
(,⑩,

Try it online!
Explanation
     # (Implicitly) take an input from the console
(    # For every item in the input:
 ,   # Print the first character, popping the stack
  ⑩  # Print the top of the stack w/o poping
   , # Print with popping, effectively doubling the second character

JavaScript (ES6), 28 bytes
Uses the same regex as @DigitalTrauma.
s=>s.replace(/.(.)/g,"$&$1")

Try it online!

JavaScript (ES6), 32 bytes
A recursive version.
f=([a,b,...c])=>b?a+b+b+f(c):[a]

Try it online!

Ruby, 25 bytes
->s{s.scan(/(.(.?))/)*''}

Try it online!
Same byte count as the other answer, different approach.

Rockstar, 95 81 bytes
listen to S
cut S
Y's 1
O's ""
while S
let O be+roll S*Y
let Y be Y-1 or 2

say O

Try it here (Code will need to be pasted in)

Could you replace the Y-1 or 2 with 3-Y?

Pip, 11 bytes
B X_%2+1MEa

Try it online!
-2 from Dlosc.

+1, very similar to my initial approach. You can use string repetition and a lambda expression to get down to 11 bytes: Try it online! (10 bytes in Pip 1.0 because _%2 -> %_.)

JavaScript (V8), 76 68 56 48 44 bytes
Thanks to Malivil for 12 bytes !
s=>s.split``.map((v,i)=>i%2==1?v+v:v).join``

Try it online!

Welcome to the site.  Your submission seems to take input by inserting it into the code.  The challenge requires that input be taken from standard in that would be the input field on TIO.

@PostRockGarfHunter Sorry about that, i've added an edited version.

I don't know javascript well enough to tell you since it is language specific.  The input box feeds its contents to stdin, which this question explains how to read in javascript.  If you want help doing it short you can ask in chat and some other javascript users will likely help you.

For what it is worth most challenges allow you to submit just a function as well as a complete program.  That is the agreed upon default.  Most js answers do that since it tends to be shorter.

You can save a few more bytes by changing v.repeat(2) to v+v

@PostRockGarfHunter by refering to this submission i was able to add the function definition in the header as well as the function call in the footer. which works great.

Actually you can save more by using the newer syntax for those empty string functions, like this

38 bytes: s=>[...s].map((v,i)=>i%2?v+v:v).join``

brainfuck, 18 bytes
>,[>,]<[<]>[.>..>]

Requires 0-termination for EOF. Prints two trailing null bytes for odd-length strings.
Try it online!

You should fix your answer rather than leave it invalid.

@JoKing Still figuring that out :).

Perl 5 -p, 13 bytes
s/.\K./$&$&/g

Try it online!

APL (Dyalog), 12 11 bytes
-1 byte thanks to Bubbler
∊⊢⍴⍨¨1 2⍴⍨≢

Try it online!
A train that takes a string and returns a string (or any list technically).
Explanation:
  ⍴⍨         ⍝ Reshape
    ¨        ⍝ Each of
 ⊢           ⍝ The input
     1 2     ⍝ To the array 1 2
        ⍴⍨   ⍝ Reshaped to
          ≢  ⍝ The length of the input
∊            ⍝ And flatten the result

PowerShell, 26 bytes
$args-replace'.(.)','$0$1'

Try it online!

Burlesque, 11 bytes
2co{J[-j}\m

Try it online!
2co # Split into chunks of 2 {"ab" "cd" "e"}
{
 J  # Duplicate pair of chars
 [- # Take the tail (returns empty for length 1 strings)
 j  # Swap to correct order for concat
}\m # For each pair, and then concatenate

Burlesque, 8 bytes
2co)+.\[

Try it online!
Works for even length strings only
2co # Same as above
)+. # For each group append the last char again
\[  # Concatenate

Lua, 34 bytes
print(((...):gsub('.(.)','%0%1')))

Try it online!
Takes input as an argument, prints result to stdout. Every two characters are replaced with themselves and second one appended.

Raku, 14 bytes
{S:g[.<(.]x=2}

Try it online!
Regex that matches every other character and substitutes it with itself string multiplied by 2.

C (gcc), 49 48 bytes
-1 thanks to ceilingcat
M;f(c){++M%3?c=getchar():0;M=~c&&f(putchar(c));}

Try it online!

PHP, 37 bytes
while($c=$argn[$i++])echo$c,$c[$i%2];

Try it online!

naz, 44 bytes
2a2x1v1x1f1r3x1v2e1o1r3x1v2e2o1f0x1x2f0a0x1f

Works for any input string terminated with the control character STX (U+0002).
Explanation (with 0x commands removed)
2a2x1v                     # Set variable 1 equal to 2
1x1f1r3x1v2e               # Function 1
                           # Read a byte of input
                           # Jump to function 2 if it equals variable 1
            1o             # Otherwise, output it once
              1r3x1v2e     # Read another byte of input
                           # Jump to function 2 if it equals variable 1
                      2o   # Otherwise, output it twice
                        1f # Jump back to the start of function 1
1x2f0a                     # Function 2
                           # Add 0 to the register
1f                         # Call function 1

Whitespace, 66 bytes
[S S S T    N
_Push_1][N
S S N
_Create_Label_LOOP][S S S T N
_Push_1][T  S S S _Add][S S S T S N
_Push_2][T  S T T   _Modulo][S N
S _Dupe][S N
S _Dupe][S N
S _Dupe][S N
S _Dupe][T  N
T   S _Read_STDIN_as_character][T   T   T   _Retrieve_input][T  N
S S _Print_as_character][N
T   S N
_If_0_Jump_to_Label_LOOP][T T   T   _Retrieve_input][T  N
S S _Print_as_character][N
S N
N
_Jump_to_label_LOOP]

Letters S (space), T (tab), and N (new-line) added as highlighting only.
[..._some_action] added as explanation only.
Try it online (with raw spaces, tabs and new-lines only).
Explanation in pseudo-code:
Integer n = 1
Start LOOP:
  n = (n+1) modulo-2
  Integer c = STDIN as character
  Print c as character to STDOUT
  If(n == 0):
    Go to the next iteration of LOOP
  Print c as character to STDOUT
  Go to the next iteration of LOOP

I really would like to master loops and conditional in WhiteSpace. Haven't quite been able to get one working yet.

@ouflak I can certainly recommend to use the vii5ard compiler when you're developing in Whitespace. It allows you to debug through the code, and see the values on the stack and heap in the memory-tab. You can even set breakpoints. Also, maybe the more in-depth explanation in this Whitespace interpreter challenge of mine might clarify a thing or two in comparison to the tutorial linked in the title.

@ouflak For a loop you basically mark a location with a Label, and you Jump to that label later on. Here for example an infinite loop printing a 1 every iteration: NSSN SSSTN TNST NSNN (create label (empty); push 1; pop and print as integer; jump to label (empty)). For an if-statement you'd have to make the value either 0 or negative, and use the conditional jumps. You usually do have to duplicate the value if you still need it later on however, since the conditional labels will pop the value.

@ouflak If you have any questions in particular, or want me to turn a provided pseudo-code into a Whitespace program with explanation, feel free to contact me again. PS: Unfortunately you can't save / link from the vii5ard compiler, which is why I have TIO links in my answers. I never create the programs in TIO though, always in vii5ard.

C (gcc), 66 \$\cdots\$ 59 57 bytes
Saved a 3 bytes thanks to ceilingcat!!!
Saved a byte thanks to S.S. Anne!!!
i;f(c){for(i=0;~(c=getchar());printf(&c))c*=i++%2?257:1;}

Try it online!

Save another by swapping c and i and initializing i at its definition.

@S.S.Anne Nice one - thanks! :-)

@ceilingcat Nice one - thanks! :-)

Hexagony, 13 12 bytes
,.<>,;/@/$;*

Try it online!
Expanded
  , . <
 > , ; /
@ / $ ; *
 . . . .
  . . .

Uses the very naive read-print, read-print twice approach.

Red, 51 bytes
func[s][foreach[a b]s[prin rejoin[a t: any[b""]t]]]

Try it online!

W d, 6 bytes
♀J,⌡I►

Uncompressed:
2V2m-*M

Explanation
Not a really good target for this challenge, I just feel that this is pretty fun to do.
Also the 1-indexed advantage seems to be a disadvantage here. If only W has a 0-index ...
% Note that W is one-indexed. (For the ease of the iterator protocols
% which have a 1-range as a built-in.)
 V2m    % Index of current item modulo 2
2   -   % Subtract 2 by the number (effectively yields
        % 1->1, 0->2 )
     *  % Repeat the character that many times
      M % Do this for every item in the input

GolfScript, 16 bytes
GolfScript doesn't have item count so you will need to do it yourself.
1:&;{]&):&2%)*}%

Try it online!
Explanation
# Implicitly pushed input
1:&;             # set count to 1
    {         }% # foreach item of input
     ]&):&       #     add count by one
          2%)*   #     repeat item by cnt % 2 + 1

Forth (gforth), 46 bytes
: f 0 do dup dup 1 type i 2 mod type 1+ loop ;

Try it online!
Code Explanation
: f              \ start a new word definition
  0 do           \ loop from 0 to string-len - 1
    dup dup      \ duplicate the current character address twice
    1 type       \ output the current letter
    i 2 mod type \ if odd, output again, if even do nothing (0 type = output nothing)
    1+           \ increment current character address
  loop           \ end loop
;                \ end word definition

.+?, 11 bytes
(.(.))
\1\2

The first answer in my new language. It's a simple language based around python regex substitution
Explanation
(.(.)) Replace each pair of characters with
\1\2   matching group 1 (both characters) followed by matching group 2 (the second character)

Try it online! (The second command line argument is input)

Nice approach! Isn't \0/$0 possible in Python or your language? I.e. .(.) and \0\1?

Sadly not, python's regexes are pretty limited compared to most other flavours

Pip, 10 bytes
WV(UWa!*h)

Try it online!
Explanation
I love it when I can abuse built-in numbers for some other purpose.
WV(UWa!*h)
     a      First command-line argument
   UW       Unweave into a list of two strings, each containing every other character
        h   100
      !*    Logically negate each digit
  (      )  Index into the list using each of those values
WV          Weave the resulting list of three strings back together

For instance, if the input is abcde:
   UWa      ["ace"; "bd"]
      !*h   [0; 1; 1]
  (      )  ["ace"; "bd"; "bd"]
WV          "abbcdde"

9 by porting my Vyxal (there's got to be a better way)

@emanresuA Hm... that's an interesting I/O format, but I think if it just uses the x flag without p it should be fine. However, since Pip -x is a different language, this solution ought to be posted separately. Feel free to do so yourself; also, an easy golf is @> -> S.

GNU AWK, 36 bytes
BEGIN{RS=".|";ORS=e}$0=NR%2?RT:RT RT

BEGIN{RS=".|";ORS=e}  This reads one character at a time,
                      which can be retrieved by the RT variable.

$0=NR%2?RT:RT RT      If NR=1 (mod 2), i.e., True, assigns "RT" to the output.
                      Otherwise, assigns "RT RT", which is RT concatenated to itself.
                      This conditional simply doubles the even occurrences.

Try it online!

SimpleTemplate, 44 bytes
This was easy, but also fun!
{@eachargv.0}{@echo_}{@if__ is mod2}{@echo_}

Loops through all the characters, and checks if the index of the character (__) is not a multiple of 2 (odd). If it isn't a multiple of 2, outputs it again.

Ungolfed:
Just in case you are curious.
{@each argv.0 as char key key}
    {@echo char}
    {@if key is not multiple of 2}
        {@echo char}
    {@/}
{@/}

The as char is optional, using the variable _ by default, to hold the array item/character from the string.
The key key is optional, using the variable __ by default, to hold the index.
All the {@/} ae optional and safe to remove.

You can try it on http://sandbox.onlinephpfunctions.com/code/5fc880374f58b72c4dc3ee2c573349e7a218aed8
You can check and try both golfed and ungolfed versions.

PowerShell, 88 bytes
$c={param($i)$c=0;$o;$i.toCharArray()|%{if($c%2-eq1){$o+="$_$_"}else{$o+="$_"}$c++;};$o}

Try it online!
PowerShell, 102 bytes
function b($i){$c=0;$o;$i.ToCharArray().ForEach{if($c%2-eq1){$o+="$_$_"}else{$o+="$_"}$c++;};write $o}

Try it online!

C (gcc), 59 bytes
i=1;f(c){for(;-~(c=getchar());i^=1)printf("%c%1$c"+i*2,c);}

Using original input rules.
Try it online!
C (gcc), 54 bytes
i=1;f(char*s){for(;*s;i^=1)printf("%c%1$c"+i*2,*s++);}

Using acceptable input.
Try it online!

53 bytes

Assuming your string are all alphabetically sorted, you can use:
Python 3, 42 bytes:
lambda x:''.join(sorted(x[1::2]*2+x[::2]))

Try it online!

APL+WIN, 13 bytes
Prompts for string:
((⍴s)⍴⍳2)/s←⎕

Try it online! Courtesy of Dyalog Classic.

Unix TMG, 59 bytes
p:parse((c={1}))parse((c={1 1}))\p;c:smark any(!<<>>)scopy;

@, 13 bytes
¤+ōČōōČ

Explanation
  ōČ    Take a character and print it.
    ōōČ Take a character and print it twice.
¤+      Repeat this forever.

Funky, 34 bytes
s=>fori=0i<#s i++write(s[i]*1+i%2)

A pretty simple solution to the problem.
Try it online!

Charcoal, 8 bytes
⭆Ｓ×ι⊕﹪κ²

Try it online! Link is to verbose version of code. Explanation:
 Ｓ          Input string
⭆           Map over characters and join
       ²    Literal 2
      κ     Current index
     ﹪      Modulo
    ⊕       Incremented
   ι        Current character
  ×         Repeated
            Implicitly print

CJam, 12 bytes
q2/{_La+1=}%

Try it online!
Explanation
q2/{_La+1=}%
q2/           Read the input and split it into groups of 2 characters.
   {      }%  For each group:
    _           Copy it.
     La+        Append an empty string.
        1=      Get its second element.
              Join the results.

Z80Golf, 12 bytes
00000000: d52e 76e5 2e07 e5cd 0380 38f6            ..v.......8.

Try it online!
  push de
Z:ld l, $76
  push hl
  ld l, G
  push hl
G:call $8003
  jr c, Z+1   ; halt on EOF, else fallthrough

Explanation
Z80golf is a small Z80 computer hooked up to $8000=putchar, $8003=getchar. (putchar prints byte A; getchar reads a byte into A or sets the carry flag on EOF.) Our code is placed at $0000 and all registers start at 0, including PC. The rest of memory is filled with zeroes.
Let's run through some sample input: uvwxyz.
We push three addresses to the stack: $0000, then $0076, then G.
Then (here's label G), we call getchar(), and on EOF jump to the HALT instruction ($76) hidden in the argument to ld l, $76.
Otherwise, control flow falls through a sea of NOPs into $8000. This is hardcoded to perform putchar(A); ret, so we print u and return back to G.
The next time we get here, we print v and return to $0076, amid the NOP sea: control flow runs back to $8000, we print v again, then return to $0000, where the code starts over.
Repeating this process, the output is uvvwxxyzz → HALT.

GolfScript, 9 bytes
2/{1/~.}%

2/{1/~.}% #Repeat every other character
2/        #Split string into bits of size 2
  {    }% #For every of those elements, do block
  {1/  }  #Divide into elements of size 1
  {  ~ }  #Pop from their array
  {   .}  #Duplicate the last element

Probably possible to shave a byte or two by refining the block. Unfortunately ) doesn't decouple properly.
Try it online!

Pyth, 9 8 7 bytes
And of course, the simple solution always prevails, and comes to me after I thought I'd done something clever :/
-1 byte because I literally put my laptop away and then remembered that s was a thing
%2ts*L3

Explanation:
%2tjk*L3
          # Implicit Q = eval(input())
%2        # Every second character of:
  t       #   All but the first character of:
   jk     #     Joined on the empty string:
     *L3  #       Each character of Q * 3

Previous version (9 bytes)
r9m,h=!Td

Falling behind a lot of other golfing languages unfortunately
Explanation:
           # Implicit T=10, Q=eval(input())
r9         # Run length decode
  m        # map over (implicit) Q
   ,h=!Td  # create a pair of:
    h=!T   # 1 + (T = not T) and
        d  # the character

Try it online!

Chevron - 96 bytes
(link goes to interpreter)
>^__>^a
^a~s>>^s
^__>^n
0>>^i
^i+1>>^i
->+6?^i>^s
^a,^i~c>>^l
^n^l>^n
->-4?^i~o
^n^l>^n
->-6
>^n

T-SQL, 88 bytes
DECLARE @x INT=len(@)/2*2WHILE @x>0SELECT
@=stuff(@,@x,0,substring(@,@x,1)),@x-=2PRINT @

Try it online

Retina, 9 bytes
.(.)
$0$1

Port of @DigitalTrauma's sed's answer, so make sure to upvote him as well!
Try it online.
Explanation:
.(.)  # MATCH:
.(.)  #  Every pair of characters,
      #  where the second character is saved in capture group 1

$0$1  # And replace it with:
$0    #  The entire match, so both characters
  $1  #  Followed by the character from capture group 1

Java 8, 30 bytes
s->s.replaceAll(".(.)","$0$1")

Same approach as my Retina answer, which was a port of @DigitalTrauma's sed's answer.
Try it online.

Clojure, 91 bytes
(defn d[s](apply str(map #(str(first %)(second %)(second %))(partition-all 2 2(into[]s)))))

Ungolfed version:
(defn dup-alternate-chars[s]
  (apply str (map #(str (first %) (second %) (second %)) (partition-all 2 2 (into [] s)))))

Test harness:
(println (d "abcde"))

which prints "abbcdde".
Try it online!

APL (dzaima/APL), 10 9 bytes
-1 thanks to Bubbler
Anonymous tacit prefix function. Requires 0-based indexing (⎕IO←0)
⊢⌿⍨1 2⍴⍨≢

Try it online!
≢ the length
2⍴⍨ use that to cyclically reshape [1,2]
⊢⌿⍨ use that to replicate the letters

9 bytes. Straightforward is better, I guess.

@Bubbler Yeah. Thanks.

Rabbit~, 13
_[.0:.>:.:.>]

Explanation:
_ - Move to input
 [.0 - start loop with input 0, and loop until you hit 0
    :. - print
      > - move along input
       :.:. - print twice
           > - move along input
            ] - end loop if we have reached past input

Wolfram Language (Mathematica), 30 bytes
StringReplace[a_~~b_:>a<>b<>b]

Try it online!
For every non-overlapping pair of characters, appends the second character.
""<>MapAt[#<>#&,#,;;;;2]& doesn't work on an empty input.

TI-Basic, 39 bytes
For(I,2,1.5length(Ans),3
sub(Ans,1,I)+sub(Ans,I,1-I+length(Ans
End

Same as this answer except for the first line. Input is taken in Ans. Output is stored in Ans.

APL (Dyalog Unicode), 11 chars
⊢(/⍨)1 2⍴⍨⍴

           ⍴   monadic: shape of the right argument (number of elements)

      1 2⍴⍨    repeat numbers 1 and 2 as many times as the right argument

⊢              the right argument

 (/⍨)          replicate each element of the left argument as many times as
               specified by the corresponding elements of the right argument

Try it online!

Ly, 17 bytes
irs[l!s[p:o0]po]>

Try it online!
This is pretty much a direct translation of the description of the challenge.  It reads in the all the input, then loops over the list printing each character once or twice.
ir                - read input as codepoints onto the stack, reverse the stack
  s               - save a codepoint to the backup cell, just has to be non-zero
   [           ]  - loop while the stack isn't empty
    l!s           - load the backup cell, flip 1/0, save it back
       [   0]p    - if/then, true for even numbered chars
        p         - pop (delete) the if/then test boolean
         :o       - duplicate top of stack and print as char
              o   - print the top of stack as a char
                > - switch stacks to avoid auto-printing

Thunno 2 t, 3 bytes
3Ḅz

Attempt This Online!
Port of emanresu A's Vyxal answer.
Thunno 2 J, 5 bytes
dŻɗ⁺×

Attempt This Online!
Explanation
3Ḅz  # Implicit input                      ->  "abcde"
3Ḅ   # Repeat each character three times   ->  "aaabbbcccdddeee"
  z  # Uninterleave into two parts         ->  ["aabccdee","abbcdde"]
     # Implicit output of last item        ->  "abbcdde"

dŻɗ⁺×  # Implicit input                    ->  "abcde"
d      # Cast to list of characters        ->  ["a","b","c","d","e"]
 Ż     # Push the length range             ->  ["a","b","c","d","e"]  [0,1,2,3,4]
  ɗ    # Pop and push each item mod two    ->  ["a","b","c","d","e"]  [0,1,0,1,0]
   ⁺   # Increment each value in the list  ->  ["a","b","c","d","e"]  [1,2,1,2,1]
    ×  # Multiply the two lists together   ->  ["a","bb","c","dd","e"]
       # Implicit output of joined list    ->  "abbcdde"

Arturo, 26 bytes
$=>[replace&{/.(.)}"$0$1"]

And non-regex:
Arturo, 41 bytes
$=>[i:0loop&=>[&if=1i%2[++<=]prints'i+1]]

Try it!

Grass, 47 bytes
wWWWWWwWWWWWWwwWWWWwwWWWWWwwWWWWWWwWWWWWWwwwwww

Try it online!
Exits with an error after printing out the string.
Ungolfed version:
w             (Function takes one argument)
WWWWWw        (Take one character from stdin)
WWWWWWww      (Take another character from stdin)
WWWWww        (Print first character, or error if no characters left)
WWWWWww       (Print second character, or error if no characters left)
WWWWWWw       (Print second character again)
WWWWWWwwwwww  (Call this function again)

Factor + sequences.repeating, 19 bytes
[ 3 repeat <odds> ]

Attempt This Online!
Repeat each character three times and take every other character starting with the second one. Port of emanresu A's Vyxal answer.

Python, 62 bytes
lambda s:''.join(c if i%2==0 else 2*c for i,c in enumerate(s))

Try it online!

Fig, \$4\log_{256}(96)\approx\$ 3.292 bytes
n2@h

Try it online!
n2@h
n @  # For every
 2   # Second character
   h # Double

Zsh, 32 bytes
for a b (`fold -1`)printf $a$b$b

Try it online!

Uiua, 8 bytes
▽+1◿2⇡⧻.

Try it!
▽+1◿2⇡⧻.
       .  # duplicate
      ⧻   # length
     ⇡    # range
   ◿2     # modulo two
 +1       # increment
▽         # keep


text:
Walk home one step at a time
You're at integer coordinates \$(x,y)\$ facing one of North, South, East, or West. Your goal is to walk home to \$(0,0)\$. At each step, you may do one of:

Walk one step in the current facing direction, that is to whichever of \$(x+1,y)\$, \$(x-1,y)\$, \$(x,y-1)\$, or \$(x,y+1)\$ you're facing.
Rotate 90 degrees left, staying in place.
Rotate 90 degrees right, staying in place.

Your goal is to write code that will eventually get you home to \$(0,0)\$ if called repeatedly, each time with your current position and facing. Your code must always give the same output for a given input, which precludes using randomness or past state.
Input:
Two integers \$(x,y)\$ and a facing direction. The 4 possible facing directions are given as numbers 0 through 3, or alternatively 1 through 4, matched as you choose. The position can also be taken as a vector or point or complex number.
You won't be given \$(0,0)\$ where you're already home. Don't worry about overflows caused by huge inputs.
Output:
One of three distinct consistent outputs corresponding to the possible actions of walking straight, turning left, and turning right.

Do we need three outputs if one is never used or will two be ok in that scenario?

@PostRockGarfHunter Definitely, I guess that's the same as having three output values one of which never happens.

The distinction I would make is that it would allow statically typed languages to output booleans.  There is no third value which is not output in that case.

@PostRockGarfHunter Ah, hadn't thought about that. Still totally fine. NASCAR drivers get home with only left turns!

@xnor can the direction be a complex number too (1,-1,i,-i)?

@ngn No, I want to stick with four indices for that.

@PostRockGarfHunter I think that is still fine in the rules, as you could argue that the other output is given via a particular error (that just won't ever occur).

Haskell, 21 bytes
(!!).([(<0),(>0)]<*>)

Try it online!
Outputs a boolean with True being move forward and False being turn right.
Haskell, 28 bytes
Here's a version that is easy to understand / translate into any language.
f(x,y)d=[x<0,y<0,x>0,y>0]!!d

Try it online!
Explanation
The idea here is two-fold

We notice that we only ever need to turn in one direction.  A turn left is just 3 turns right.  So we will limit ourselves to only right turns.
Now we notice that given a direction there is a simple condition that can check if we ought to move forward.  Namely the sign of one of the two variables.

With this information we construct out solution, by making a list of the conditions and indexing the list with the direction.  True means the condition was passed and we can move forward (so we do), False means the condition was failed and we should not move forward, so we rotate.
Now the specification allows us to just output these values as is, since they are distinct and we have no intention of turning left.

so, if you're on one of the axes (x=0 or y=0, but not x=y=0), [x<0,y<0,x>0,y>0] would be [False,False,False,False] and you would never return True for "move forward"?

@ngn If all four are false you must be on both of the axes.

oh.. you're right

Pyth, 7 bytes
qi<L0E2

Try it online!
Input is in the form:
3
[3, 4]

The solution is simple:

<L0E maps each coordinate to 0 if the coordinate is positive, and 1 if the coordinate is nonpositive.

i ... 2 converts the list to a number by interpreting it as binary.

q checks whether the resulting number is equal to the other input.

True means forward, False means turn, the direction is irrelevant, the third output is irrelevant.

We use the following mapping:

0: up - the positive y direction.
1: right - the positive x direction.
2: left - the negative x direction.
3: down - the negative y direction.

The path the walk takes is a sort of a staircase - from the (-, -) quadrant to (-, 1) to (1, 1) to (0, 1) to (0, 0) for instance.

Python 2, 30 bytes
lambda i,d:abs(i+1j**d)<abs(i)

Try it online!
Takes as input a Gaussian integer for position, and an integer in {0,1,2,3} for the direction; outputs True for forward, False for rotate counter-clockwise, and whatever you like for rotate clockwise, because that never happens :).

You need to take direction as a number. 1j**d should do.

@xnor: Good catch! Thanks.

Jelly, 4 bytes
>-Ḅ⁼

Try it online!
A dyadic link taking the co-ordinates as the left argument and the direction faced as the right. Returns 0 for turn and 1 for move forwards.
The TIO footer picks a random starting point and demonstrates that the link will ultimately reach [0,0]
Based on @isaacg’s Pyth answer so be sure to upvote that one too!
Explanation
>-   | Greater than -1
  Ḅ  | Convert from binary time decimal integer
   ⁼ | Equal to right argument

J, 12 11 bytes
[>&|[+0j1^]

Try it online!
idea
Our idea is simple: Walk straight, and see if that gets us closer in Euclidean distance.  If yes, return "walk straight".  If not, return "turn left".
input / output
Take position as a complex number (left arg) and direction as a 0-indexed int (right arg). Similar to @PostRockGarfHunter's answer, we constrain our output to two values:

1 - Walk straight
0 - Turn left

how

[+0j1^] First we convert our right arg integer to a complex number by raising i 0j1 to the right arg 0j1^]. Then we add that + to the left arg [.  This represents our "next position", if we were to walk straight.
[>&| Is the left arg [ (current position) greater than > the next position after converting both to Euclidean distance from origin &|?

APL (Dyalog Classic), 10 9 bytes
⊣⊃0(>,<)⊢

Try it online!
all credit to Post Rock Garf Hunter's answer
the tio link shows numbers of steps for the square area around (0,0) for the 4 initial directions
⊣ left arg: direction
⊢ right arg: coord pair
, concatenation
0(>,<)⊢ is equivalent to (0>⊢),(0<⊢), i.e. the 4-vector (0>x),(0>y),(0<x),(0<y)
⊣⊃.. indexing with the left arg

(>,<) <- emoji here

@tsh ..trying to stuff a shovel (⊣⊃) in its ear (0)

JavaScript (Node.js), 26 25 24 bytes
(x,y,d)=>--d%2*x<--d%2*y

Try it online!
d is direction one of [0, 1, 2, 3] for [west, north, east, south]
The expression
(d - 1) % 2 gives deltaX one of [-1, 0, 1, 0]and(d - 2) % 2 gives deltaY one of [0, -1, 0, 1]
Either x * deltaX or y * deltaY will be non zero and will be negative if we are heading towards home. So if
(deltaX * x + deltaY * y < 0) also expressed as
(deltaX * x < deltaY * -y)
we go forward = true, else we turn left = false.
To get to 24 I swapped north and south to change '-y' to 'y'

Nice answer and nice test suite!

JavaScript (ES6),  28  27 bytes
Takes input as (x,y,d) with \$d=0\$ for North, \$1\$ for South, \$2\$ for West, \$3\$ for East.
Output:

true : turn right
false : walk straight

(x,y,d)=>(x&&2|x<0||y<0)!=d

Try it online!
How?
This is parsed as:
           +--------------------> 0 if x = 0, 3 if x < 0, 2 if x > 0
           |                +---> 1 if the first expression is 0 and y < 0, 0 otherwise
   ________|_______        _|_
  /                \      /   \
((x && (2 | (x < 0))) || (y < 0)) != d

Looks like your directions are actually [south,north,west,east] and true means turn left.

@James Your interpretation is equivalent to mine, except you seem to assume that $y>0$ means South, while I assumed it means North.

C (gcc), 47 bytes
z;m(x,d)int*x;{x=abs(z=x[d/2])>abs(z+d%2*2-1);}

Returns 0 to move forward and 1 to turn clockwise. It never moves counterclockwise but let's just call that 2.
North is 3, south is 2, east is 1, and west is 0.
-2 bytes thanks to ceilingcat!
Try it online!

05AB1E, 4 bytes
d2βQ

Port of @NickKennedy's Jelly answer, so make sure to upvote him as well!
First input is the coordinate, second input is the current direction digit (in the range [0,3]).
Outputs 0 to turn, and 1 to move forward.
Try it online or verify a random coordinate will eventually result in [0,0] or verify all coordinates in the range [[-1,1],[1,1]] with all possible directions [0,3].
Explanation:
d     # Check for both values in the (implicit) input-coordinate whether it's non-negative (>=0)
 2β   # Convert this from a binary-list to an integer
   Q  # And check whether it's equal to the (implicit) direction input-integer
      # (after which this is output implicitly)

Retina 0.8.2, 38 35 bytes
. (-?).*( -?).*
$*-$2$1$1
^(-*) \1$

Try it online! Link includes demonstration of path taken from 5 3 to the origin. Takes input as direction first, then coordinates. Edit: Saved 3 bytes by porting @isaacg’s Pyth answer. Direction encodes as y--, x--, x++, y++. Outputs 1 to move, 0 to turn. Explanation:
. (-?).*( -?).*

Capture the signs of the coordinates.
$*-$2$1$1

Convert the direction to unary, and convert the coordinate signs from base 2, discarding everything else.
^(-*) \1$

Compare the direction to the base 2 decoded signs.

Pure Data, 65 bytes
#X obj 0 0 expr (8*($i1<0)+4*($i2<0)+2*($i1>0)+($i2>0)&1<<$i3)<1;

This line can be added to a pure data patch to make an object positioned at 0 0 which takes 3 inputs and produces one output.  The first two are the x and y and the last is the direction (range 0 to 3).
Here is an example of how it can be called:

This ports my haskell answer in logic, however since arrays are a nightmare in pure-data we use arithmetic and bitwise operations instead.  We pack the 4 booleans (ints in pd) into a four bit integer and use & to index them.

Charcoal, 13 9 bytes
⁼↨Ｅ²›⁰Ｎ²Ｎ

Try it online! Link is to verbose version of code. Edit: Saved 4 bytes by porting @isaacg’s Pyth answer. Uses the same "move or turn" approach; - means move, no output means turn. The directions encode as y--, x--, x++, y++. Explanation:
   ²        Literal 2
  Ｅ         Map over implicit range
     ⁰      Literal 0
    ›       Is greater than
      Ｎ     Input coordinate
 ↨     ²    Convert from base 2
⁼           Equals
        Ｎ   Input direction