text:
Convert Character Substrings to Numeric
I often have to take character data and categorize it numerically at work. A common thing I do is to take character type variables and convert them to numeric type characters, keeping same categories according to the level of work I'm doing. (The longer the substring, the more in depth and specific, shorter substrings for broad level). Enough backstory...
The challenge: In as few bytes as possible, convert the input part A, a vector/list of unique strings, into the output, a vector/list of numbers, keeping unique categories within the length of substrings the same length, which is input part B. Feel free to ask questions for clarification.
Input:

w, Vector/list of unique strings of equal character length. n <= 10

These strings may be any combination of uppercase letters and numbers. Sorry if it seems my examples follow a pattern, I just created them after a similar pattern I see in the data I work with.
Some random examples of what input could look like: "A1", "7LJ1", "J426SIR", "4AYE28TLSR", or any other random combination of uppercase letters up to 10 characters. To repeat: Each element in the vector/list will be the same length.
Input may already be ordered by group, or non-contiguous, meaning elements lying within one group may be separated by elements of a different group. (See example 2)

s, where 1 <= s <= n

Output:
Output should have the indexes of the sorted, de-duplicated, trimmed values. See example 2. (I've included comments in my output to clarify, this is not required) This can be 0-based or 1-based index, as per your language uses.
Example Input 1:
#Input already alphabetized, but this input is not always guaranteed

s = 3, w =
[ABC01,
 ABC11,
 ABC21,
 ABD01,
 ABE01,
 ABE02,
 ACA10,
 ACA11,
 ACB20,
 ACB21]

Example Output 1:
[1, #ABC
 1,
 1,
 2, #ABD
 3, #ABE
 3,
 4, #ACA
 4,
 5, #ACB
 5]

Example Input 2:
s = 4, w =
[X1Z123,
 X1Z134,
 X1Y123,
 X1Y134,
 X1Y145,
 X1Y156,
 X1X123,
 X1X124,
 X1X234,
 X2Z123,
 X2Z134,
 X1X255,
 X1Y124,
 X2Z222,
 X2Z223,
 X2Z224]

Example 2 Output:
#Categorize by order of appearance
[1, #X1Z1
 1,
 2, #X1Y1
 2,
 2,
 2,
 3, #X1X1
 3,
 4, #X1X2
 5, #X2Z1
 5,
 4, #X1X2 again (to show input can be non-contiguous)
 2, #X1Y1 again
 6, #X2Z2
 6,
 6]

OR

#Input not alphabetized, but indexes still match original input indexes.
[4, #X1Z1
 4,
 3, #X1Y1
 3,
 3,
 3,
 1, #X1X1
 1,
 2, #X1X2
 5, #X2Z1
 5,
 2, #X1X2 again (to show input can be non-contiguous)
 3, #X1Y1 again
 6, #X2Z2
 6,
 6]

May we use 0-based indexing for the output?

I always forget about that. I'm used to 1-based indexing in my preferred language. Yes, I will allow that.

Can the input contain two strings with the same prefix in a non-contiguous block? For example, might we receive an input like [ABC12, ABC34, ABD45, ABC41] (ABD45 between strings of ABC**)? In this case, I would suggest adding a test case to address this.

@Mr.Xcoder That was essentially the idea with saying that it doesn't necessarily need to be alphabetical, or as you also say non-contiguous. The second example follows this idea somewhat, but I can tweak it to be more non-contiguous.

If the input is not sorted alphabetically does that imply our output should have the indexes of the sorted, de-duplicated, trimmed values or not? Example 2 pt 2 is confusing me. Maybe an example with unsorted input would be worth adding?

@JonathanAllan You are correct, regardless if the input is sorted or not, output should match the indexes of the unchanged input. I've made some edits already.

@Sumner18 so I think example 2 pt 2 should just be example 3 and show what the input would have been

@JonathanAllan Sorry if my verbage isn't too clear, I'm trying to say that either output format works for any given non-alphabetically sorted input. Substring categories can be numbered in the order they appear or in the order they would appear if the substrings were sorted alphabetically, while still matching the indexes of the input. I'm still trying to learn Code Golf terminology and how to best describe things.

APL (Dyalog Extended), 8 7 6 bytesSBCS
Anonymous infix function. Takes s as left argument and w as a list of strings as right argument.
∪⍛⍳⍨↑¨

Try it online!
↑ take the first s characters from…
 ¨ each string in w
∪⍛…⍨ in the list of the ∪nique strings in that…
 ⍳ find the ɩndex of the first occurrence of each string

I'm always impressed with these Golfing languages. For once it would be great to stump a golfing language.

@Sumner18 APL absolutely isn't a golfing language, but rather an industrial strength production language detailed by a couple of ISO standards. (It even has an R bridge!) I'll be delighted to teach it to you over in the APL Orchard.

Not only is it not a golfung language but in this challenge it may be more terse!

Japt, 9 bytes
®¯V
m!bUâ

Try it

What even is Japt? I see that it is a shortened version of Javascript, but is it purely a golf language, or does it perform something more beyond Javascript's capabilities?

Hello @Shaggy ! I cannot understand why not simply using b instead of  !b doesn't work ? Is it equivalent to
£Uâ bX ?

bash, 44 bytes
cut -c-$1|awk '{print(x=a[$0])?x:a[$0]=++b}'

Try it online!
cut takes the first s characters, then awk remembers strings it's seen before and assigns them to ++b otherwise.

Jelly, 6 bytes
ḣ€µQiⱮ

A dyadic Link accepting a list on the left and an integer on the right which yields a list of integers.
Try it online!

You don’t need the Ṣ if I’ve understood the challenge correctly. I had ḣ€QiⱮ$ which is almost the same as yours so won’t post separately.

Example 2 part 2 seems to imply we need the sort

I understood it that you could sort alphabetically but it was optional.

Ruby, 47 46 bytes
Uses 0-indexing in the order of appearance.
->s,w{w.map!{|e|e[0,s]}.map{|e|(w&w).index e}}

Try it online!
->s,w{w.map!{|e|e[0,s]}.map{|e|(w&w).index e}}
->s,w{                                       }  # Proc that takes 2 arguments
      w.map!{|e|e[0,s]}                         # Replace each element of w with its prefix
                       .map{|e|             }   # For each element in the modified w
                               (w&w)            #  Deduplicated copy of the modified w
                                    .index e    #  Get the element's index in the dedup copy

J, 18 14 13 bytes
[:(~.i.]){."1

Try it online!

{."1 Extract first s of each item
(~.i.]) Within the uniq of that list ~. find the index of i. every item ]

Python 2, 94 65 bytes
def f(w,A):A=[a[:w]for a in A];return map(sorted(set(A)).index,A)

Try it online!
A whopping 29 bytes thx to Value Ink.
Uses 0-indexing; returns the index of the sorted list of possibilities (as per Example 2, alternate output).

92 bytes by constructing the deduplicated list manually instead of using list comprehension

Actually, looking at Example 2's alternate output, list(set(A)) is probably sufficient for your purposes.

@ValueInk: Ah, I missed that detail. I think it needs to be  sorted(set(A)) though.

Yes, you are probably right. I just did a test of list(set(A)) on example 2 and found X1Y1 was first, when it should be third when sorted alphabetically.

Charcoal, 17 bytes
≧…θηＩＥη⌕Φη¬№…ημλι

Try it online! Link is to verbose version of code. Explanation:
≧…θη

Truncate each string to the given length.
ＩＥη⌕Φη¬№…ημλι

Map over each string, finding its position in the filtered list given by the first occurrence of each string in the list, and cast the results to string for implicit print.

JavaScript (V8), 68 bytes
(z,L)=>(L=L.map(x=>x.slice(0,z))).map(x=>[...new Set(L)].indexOf(x))

Try it online!
0-indexed in order of appearance

(z,L)=>                      input : z= number of characters, L=list
(L=L.map(x=>x.slice(0,z)))   cut L saving it.
.map(x=>[... ].indexOf(x))   maps the result indexing in :
        [...new Set(L)]      builds an iterable object out of the Set of L

05AB1E, 6 bytes
€£DÙsk

String-list \$w\$ as first input, and integer \$s\$ as second input.
Output is categorized by order of appearance, and uses 0-based indexing.
Try it online or verify all test cases.
Output could also be categorized by alphabetical order for 6 bytes as well, by changing the Ù to ê.
Try it online or verify all test cases.
Explanation:
€       # For each string in the (implicit) input-list:
 £      #  Only leave the first (implicit) input-integer amount of characters
  D     # Then duplicate this list of strings
   Ù    # Uniquify the list
   ê    # (Alternative: Uniquify AND sort the list)
    s   # Swap to get the duplicated list again
     k  # And get the (0-based) index of each in the unified list
        # (after which the result is output implicitly)

R, 40 bytes
function(w,s)c(factor(substring(w,1,s)))

Try it online!
c() has the odd behavior of coercing its arguments into the lowest possible one in the following hierarchy:
NULL < raw < logical < integer < real < complex < character < list < expression

factors are internally held as integers, so this coerces to an integer list.

Wow you cut my possible R solution in half, though I don't want to answer my own questions. This is spectacular! Did you see my other question, Integer Keys and Duplicates. It was inspired by duplicated() where incomparables = k1 or k2 which results in some rather long code for a potential R response.  I'm curious how you would approach that.

@Sumner18 I did. I've been busy with work lately but I'll give it a go when I get a chance!

@Sumner18 out of curiosity, how did you approach it? I knew that factor(substring(w,1,s)) would be the core of the challenge (and IIRC I commented as such in the sandbox) but even longer golfs have useful tricks in them, so I'd be remiss if I didn't ask.

I appear to have deleted my code, but if I remember right, it was essentially the same approach. I converted the string to factor, then to integer, but using as.integer instead of c()


text:
Reversing and Shifting
Sandbox
Adapted from exercise 8 of 100 little Keg exercises
String manipulation is a very important part of any programming language. Consequently, that is what this challenge is about.
The Challenge
I want you to write a program that:

Takes a series of characters as input and,
Then takes another input (integer/letter) (we'll call this instruction) and,
Takes a single integer (we'll call this times) as the last input and then,
If instruction is equal to the letter R:

Reverse the string times times.

Otherwise, if instruction is equal to the letter l:

Shift the string left times times

Otherwise, for all other values of instruction:

Shift the string right times times

Test Cases
String, Instruction, Times -> Output
"Howdy!", R, 1 -> "!ydwoH"
"elloH", r, 1 -> "Hello"
"tedShif", l, 3 -> "Shifted"
"sn't it?Amazing, i", l, 8 -> "Amazing, isn't it?"

Rules

Input can be taken as any convenient format... if a list of three items works best for you, take the input as a list. If newline-separated input is how you choose to work, go ahead and use newline-separated input.
The string, instruction and times integer can be taken in any order
Output is also to be given in any convenient format.
The input string will not contain newlines, nor unprintable ascii characters.
You can substitute R and l for any other two characters, as long as you specify what the two characters are
All instructions are case sensitive. In other words, only input of R should reverse the string, not r.
The magnitude of a shift will always be less than the length of the string
The times integer is a positive integer (i.e. \$ n > 0 \$)

Scoring
This is code-golf, so the answer with the fewest bytes wins.

May we assume the magnitude of a shift is less than the length of the string?

Yes, you may indeed make that assumption.

And that the integer given will always be non-negative?

reverse the stack you mean string, right?

May the input requires Reverse the string 2 times?

@tsh yes, the input could possibly be reversed 2 times

It's a crime that there's no Keg answer here.

Python 3.8 (pre-release), 65 bytes
lambda s,i,t:[s[(n:=[-t,t][i=='l']):]+s[:n],s[::(-1)**t]][i=='R']

Try it online!
Abuses the de-facto ternary statement [a,b][condition].

If i=='R':

Return the string, read with step (-1)**t. This is -1 (reversed) for odd t and 1 (not reversed) for even t.

Else:

Let n be [-t,t][i=='l']. This is t when left-shifting and -t otherwise (right-shifting).
Return the string, spliced accordingly: s[n:] + s[:n]. Thanks to Python's negative indexing, this works like a charm for both cases.

APL (Dyalog Unicode), 20 bytesSBCS
Full program. Prompts for the string, then times, then instruction:

+ for reversal
1 for left shift
any other character for right shift

(⍎⍕⊃¯1,⍨⍞∩'+1')⌽⍣⎕⊢⍞

Try it online!
⍞ prompt for string
⊢ on that, do the following:
⎕ prompt for times
(…)⌽⍣ apply the ⌽ function that many times, with the following to its left:
 ∩'+1' intersection of the following and "+1":
 ⍞ prompt for instruction
 ¯1,⍨ append negative one
 ⊃ pick the first one
 ⍕ stringify
 ⍎ evaluate (gives 1 or -1 or the complex conjugate function +)
The function ⌽ does a:

left shift if it has 1 on its left
right shift if it has -1 on its left
reversal if it has any function on its left

+ negates the imaginary part of its argument but strings have no imaginary parts, so it does nothing

Python 2, 67 bytes
lambda s,t,i:[s[t:]+s[:t],s[::1-t%2*2],s[-t:]+s[:-t]]['lR'.find(i)]

Try it online!

Ruby, 63 bytes
->s,c,n{c==?R?[s,s.reverse][n%2]:s.chars.rotate(c==?l?n:-n)*''}

Try it online!
An anonymous lambda that takes 3 arguments. If the instruction is R, it returns the original or the reversed version based on whether n is even or odd. Otherwise, it converts the string into a character array and rotates that left or right based on the instruction specified (Ruby rotates left if the argument provided is positive) the joins the char array back together into a string using *''.

05AB1E, 16 bytes
²³F1¹QiRë0¹QiÀëÁ

Try it online!
1 instead of R, 0 instead of l.
I'm new to this language, would appreciate if anyone could give me tips.
²³F1¹QiRë0¹QiÀëÁ
²³               # Push the second and third inputs.
  F              # Do the following [third input] times:
   1¹Qi          # If the first input is equal to 1,
       R         # Reverse (at this point, the second input will be at the top of the stack).
        ë0¹Qi    # Else-if the first input is equal to 0,
             À   # Shift left.
              ëÁ # Else shift right.

F²iRë²_iÀëÁ (11 bytes) with the input-order changed a bit. Some tips: 1) Input is implicitly if nothing is on the stack, so you can take advantage of that. This is what I did with the initial F without explicitly using the first input, and I do the same with the R/À/Á and the third implicit input-string. 2) Only 1 is truthy in 05AB1E, so no need to explicitly do the 1Q check. Simply ²i is therefore enough to check if this second input-integer is exactly 1. As for the ²_i, the _ is a builtin to check if an integer is exactly 0.

C (clang), 72 bytes
j;f(char*s,z,i,t){for(j=0;j<z;++j)putchar(s[i?(z+t*i+j)%z:t%2?z+~j:j]);}

Try it online!
Input as: char* , length, instruction(r=-1 , R=0 , l =1), times
Loop into input string using a shifted index with modulo i?(z+t*i+j)%z or a length - index -1 for reverse

Burlesque, 32 bytes
pe{{so}{<-}{SO}{rt}{1}{RT}}cnjE!

Try it online!
Takes arguments as: "StringToMod" N "Op"
Where op is a reverse ordered string for reverse, a string in order for rotate right and anything else for rotate left, other short options or op could be space character, alpha character, other. If those are unacceptable input add 4 bytes for {'R==} & {'r==} as conditions.
pe         # Push inputs to stack
{
 {so} {<-} # If sorted push reverse
 {SO} {rt} # If reverse-sorted push rotate right
 {1}  {RT} # Else push rotate left
}cn        # Condition on op
jE!        # Evaluate N times

Jelly, 18 bytes
Ḣ⁾lRi‘ịUṛ¡ṭṙN,$}¥ɗ

Try it online!
A dyadic link taking a Jelly string prepended with the instruction as its left argument (e.g. RHello world) and the integer as its right argument. Returns a Jely string.

Charcoal, 27 25 bytes
≔×⌕RrηＩζδＦ×¬δＩζ≦⮌θ⭆θ§θ⁻κδ

Try it online! Link is to verbose version of code. Explanation:
≔×⌕RrηＩζζ

Convert the third input to integer, then multiply it by the index of the second input in Rr. This leaves it zero if the second input is R and unchanged if it is r but it negates the third input if the second input is anything else.
Ｆ×¬δＩζ≦⮌θ

If the third input is now zero then reverse the first input the original number of times.
⭆θ§θ⁻κζ

Shift the first input rightwards by the third input.

Pyth, 38 bytes
J.zKs@J2A<J2?qHd_FGK?qHN+>GK<GK+>KG<KG

Try it online!
This is a quite naive strategy but it works ¯\_(ツ)_/¯
Input is taken on three lines: the first is the input, second is the operation, third is the count.
Substitute R for  (space).
Substitute l for " (double quote).

JavaScript (Node.js), 74 bytes
i=>n=>g=a=>n--?g(a.map((_,p)=>a[(i-1?i-2?L+p-1:p+1:L+~p)%L],L=a.length)):a

Try it online!
Input i (instruction, 1 = Reverse, 2 = Left, 3 = Right), n (times), a (array of characters).
Output array of characters.

Vyxal D, 11 bytes
:[‛ǔǓiĖ|_(Ṙ

Try it Online!
Uses 0 for reverse, 1 for shift left, and 2 for shift right.

source: Stack Exchange

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

sort: votes


text:
Minified Intcode Computer
As the trip through the solar system on your way to rescue Santa gets a little droll, so perhaps some optimizations to your Intcode Computer are in order. Namely, making it as small as possible because you've got nothing better to do with your time.
Check out Advent of Code if you haven't already, the guy that makes the puzzles is amazing; Day 11 blew my mind. I might be cribbing the specs for the Intcode Computer, but why not challenge people to minify it?
Here are the specifications for an Intcode Computer:
Links to the day where the specifications are introduced will be included. These pages will contain example programs to use as test cases as well as supplemental explanation, as I presume I don't have to explain what it means to "read from" or "write to" a memory address.

An Intcode program is a list of integers (for example, 1,0,0,3,99). To run one, start by looking at the first integer (called position 0) this will be the opcode (enumerated below). Following an opcode will be its arguments (if any, each opcode will detail how many). Entries may take programs in any reasonable format, including how to handle any input to an Intcode program.
Intcode Computers have an instruction pointer that, after executing an instruction moves forward a number of positions based on the opcode (1 plus the number of arguments). (Day 2)
Each parameter of an instruction is handled based on its parameter mode. The rightmost two digits of an opcode indicate the opcode itself, while the remaining digits (read from right to left) indicate the argument mode (how the literal value of the argument is handled). (Day 5)

0 is position mode. Read from the position indicated; eg. mem[a]
1 is immediate mode. Read as a literal value; eg. a

Parameters that an instruction writes to will never be in immediate mode.

2 is relative mode. Read from the position indicated by adding the RelativeCounter to the value; eg. mem[a+r]

Intcode Computers have a RelativeCounter which is a value that is used as an offset for relative mode arguments. This value starts at 0 (during which, relative mode acts identically to position mode). (Day 9)

The RelativeCounter may hold a negative value.

The computer's available memory should be much larger than the initial program. Memory beyond the initial program starts with the value 0 and can be read or written like any other memory. (It is invalid to try to access memory at a negative address, though.)
The computer should have support for large numbers and negative numbers; longs are sufficient.

Opcodes:
Arguments will be noted as A, B, etc. where A is the first argument, B is the second, and so on.

1: Adds A and B and stores the result in C
2: Multiplies A and B and stores the result in C
3: Reads an integer from input and stores the result in A
4: Outputs the value read from A
5: Jump-if-true. If A is non-zero, it sets the instruction pointer to the value of B
6: Jump-if-equal. If A is zero, it sets the instruction pointer to the value B
7: Less than. If A is less than B, it stores 1 in the position given by C. Otherwise, it stores 0
8: Equals. If A is equal to B, it stores 1 in the position given by C. Otherwise, it stores 0
9 Adjusts the RelativeCounter by the value of A. The relative base increases (or decreases, if the value is negative) by the value of the parameter.
99: Terminates the program
Other opcodes are invalid.

Opcode & paramater mode detail
Taken from Day 5:
ABCDE
 1002

DE - two-digit opcode,      02 == opcode 2
 C - mode of 1st parameter,  0 == position mode
 B - mode of 2nd parameter,  1 == immediate mode
 A - mode of 3rd parameter,  0 == position mode,
                                  omitted due to being a leading zero

Test cases
[3,9,8,9,10,9,4,9,99,-1,8] Using position mode, consider whether the input is equal to 8; output 1 (if it is) or 0 (if it is not).
[3, 3, 1107, -1, 8, 3, 4, 3, 99 ] Using immediate mode, consider whether the input is less than 8; output 1 (if it is) or 0 (if it is not). (From Day 5)
[109, 1, 204, -1, 1001, 100, 1, 100, 1008, 100, 16, 101, 1006, 101, 0, 99] takes no input and produces a copy of itself as output.
[1102, 34915192, 34915192, 7, 4, 7, 99, 0] should output a 16-digit number.
[104, 1125899906842624, 99] should output the large number in the middle. (From Day 9)
[109, -1, 4, 1, 99] outputs -1
[109, -1, 104, 1, 99] outputs 1
[109, -1, 204, 1, 99] outputs 109
[109, 1, 9, 2, 204, -6, 99] outputs 204
[109, 1, 109, 9, 204, -6, 99] outputs 204
[109, 1, 209, -1, 204, -106, 99] outputs 204
[109, 1, 3, 3, 204, 2, 99] outputs the input
[109, 1, 203, 2, 204, 2, 99] outputs the input (From Reddit regarding Day 9)
[3, 11, 3, 12, 1, 11, 12, 9, 104, 0, 99] takes two inputs and outputs their sum
Day 9 features a self-test program that will output opcodes that do not appear to be operating correctly, provided that your Intcomputer is fully functional to Day 5 specifications. It is very long and contains per-user unique code relevant to part 2's puzzle, as such it is not included here.
Day 7, Day 11, Day 13, Day 15, Day 17, Day 19, Day 21, and Day 23 all contain Intcode programs as well (as does, presumably, Day 25 if the pattern holds).
And remember, this is code-golf! But that only applies to the Intcode Computer itself, any auxillary code to handle executing it is not counted towards your score.
A Helpful Hint
When testing your intcode computer, it is very helpful to run the diagnostic program. Here's a copy for those without an AOC account.
Sometimes, your program will constantly output 203 when running this program. That means that opcode 03 doesn't work when placed in "relative mode". Quite a few of us on the CGCC Discord were experiencing this issue.
For information on how to fix this, read here

Esolangs page

@Jono2906 Of course it has one. I didn't even think to look.

Also, where's my rewritten intcode interpreter when I need it! Probably on my home computer.

"The rightmost two digits of an opcode indicate the opcode itself" Do you mean decimal digits?

May RelativeCounter be negative during execution?

Do programs always be terminated by opcode 99? Or could they be terminated by setting instruction pointer out of bound? In another word, may I assume the instruction pointer would always be valid (in the range of 0 ~ program.length - 1)?

Are we supposed to support multiple inputs? It seems like there's no test case for that.

@tsh All of the puzzles in Advent of Code terminate with 99. Other opcodes are considered an error (meaning, the implementation is wrong). And yes, the decimal digits. 21002 is opcode 2 with parameter modes 0, 1, and 2.

@Arnauld Some of the Advenet of Code puzzles require piping more than one input in, starting with Day 7 (where you need to run 5 copies, with the output of the last copy creating a feedback loop back to the first copy). I'll see about crafting a simple test case that reads two input values.

@tsh Missed your other comment earlier: yes, it may be. But negative memory addresses don't exist. Day 9, For example, given a relative base of 50, a relative mode parameter of -7 refers to memory address 50 + -7 = 43. ... It is invalid to try to access memory at a negative address, though.

Python 3, 480 476 474 418  416 bytes
-56 bytes thanks to Value Ink
def a(c,i,o):
 p=g=r=0;c+=[0]*9999
 def v(b):r;x=c[p+b];return eval(["c[x]","x","c[x+r]"][m[b]])
 def s(b,e):c[c[p+b]+r*(m[b]>1)]=e
 while g!=99:
  g=c[p];m=[0]*4;k,g=g//100,g%100;n=1
  while k:k,m[n]=k//10,k%10;n+=1
  if g<3or 6<g<9:x,y=v(1),v(2);s(3,[x==y,x+y,x*y,x<y][g&3]);p+=4
  if g==3:s(1,i());p+=2
  if g==4:o(v(1));p+=2
  if g==5:p=v(2)if v(1)else p+3
  if g==6:p=p+3 if v(1)else v(2)
  if g==9:r+=v(1);p+=2

Takes as input the code, an input function (called with no arguments whenever the code requests input), and an output function (called with one argument, the value just output, whenever the program outputs something). I included all of the test cases given in the TIO link.
Try it online!

JavaScript (V8),  234  230 bytes
Expects ([program], [input]), where input is ordered from last to first. Prints to stdout.
f=(P,i,p=r=0)=>(n=P[p++])-99&&([A,B]=(g=n=>o--?[(v=P[p++],k=n%10|0)-1?P[v+=k>1&&r]||0:v,...g(n/10)]:[])(n/100,o=~-(n%=10)%6>>1||3),n<4?P[v]=n<2?A+B:n<3?A*B:i.pop():n<5?print(A):n<7?!A^n>5?0:p=B:n<9?P[v]=n<8?A<B:A==B:r+=A,f(P,i,p))

Try it online!
How?
The implementation is rather straightforward, except the computation of the number of parameters for a command \$n \le 9\$, for which we use the following formula:
(n - 1) % 6 >> 1 || 3

Which gives:
 n | -1 | %6 | >>1 | ||3 | action
---+----+----+-----+-----+--------------
 1 |  0 |  0 |  0  |  3  | A+B -> P[C]
 2 |  1 |  1 |  0  |  3  | A*B -> P[C]
 3 |  2 |  2 |  1  |  1  | input -> A
 4 |  3 |  3 |  1  |  1  | output A
 5 |  4 |  4 |  2  |  2  | p=B if A!=0
 6 |  5 |  5 |  2  |  2  | p=B if A==0
 7 |  6 |  0 |  0  |  3  | A<B  -> P[C]
 8 |  7 |  1 |  0  |  3  | A==B -> P[C]
 9 |  8 |  2 |  1  |  1  | r+=A

Commented
Helper function
\$g\$ is a helper function that retrieves \$o\$ parameters according to the upper digits of the current command, which are passed in \$n\$.
g = n =>                        // n = command / 100
  o-- ?                         // decrement o; if it was not equal to 0:
    [                           //   update the list of parameters
      (                         //
        v = P[p++],             //     v = next value read from the program
        k = n % 10 | 0          //     k = floor(n mod 10)
      ) - 1 ?                   //     if k is not equal to 1:
        P[v += k > 1 && r]      //       read P[v] if k = 0 or P[v + r] if k = 2
        || 0                    //       if undefined, use 0 instead
      :                         //     else:
        v,                      //       immediate mode: use v
      ...g(n / 10)              //     recursive call with n / 10
    ]                           //   end of update
  :                             // else:
    []                          //   stop recursion

Main function
f = (                           // f is a recursive function taking:
  P,                            //   P[] = program
  i,                            //   i[] = input
  p = r = 0                     //   p = program pointer, r = relative counter
) =>                            //
  (n = P[p++]) - 99 && (        // read the next command n and stop if it's 99; otherwise:
    [A, B] = g(                 //   retrieve the first 2 parameters A and B (the latter
                                //   may be undefined) by invoking g:
      n / 100,                  //     pass n / 100
      o = ~-(n %= 10) % 6 >> 1  //     set o = number of parameters for this command,
          || 3                  //             using the formula described above
    ),                          //   end of call to g
    n < 4 ?                     //   if n is less than 4:
      P[v] =                    //     update P[v]:
        n < 2 ? A + B           //       if n = 1, store A + B
              : n < 3 ? A * B   //       if n = 2, store A * B
                      : i.pop() //       if n = 3, store the next input
    :                           //   else:
      n < 5 ?                   //     if n = 4:
        print(A)                //       output A
      :                         //     else:
        n < 7 ?                 //       if n = 5 or n = 6:
          !A ^ n > 5 ? 0        //         jump if (A == 0) XOR (n == 6) is false
                     : p = B    //
        :                       //       else:
          n < 9 ?               //         if n = 7 or n = 8:
            P[v] =              //           update P[v]:
              n < 8 ? A < B     //             test A < B if n = 7
                    : A == B    //             or A == B if n = 8
          :                     //         else:
            r += A,             //           update r
    f(P, i, p)                  //   recursive call for the next command
  )                             // end

AWK, 285 283 bytes
{for(split(i,v);o<99;r+=o>8?x:0){o=$++p;a=int(o/100)%10;b=int(o/1000)%10;w=$++p+1+!!a*r;x=--a?$w:$p;y=$++p+1+!!b*r;y=--b?$y:$p;z=$++p+1+!(o<10^4)*r;o%=100;if(o~3)$w=v[++j];if(o~4)printf"%.f\n",x;if(o~/1|2|7|8/)$z=o<2?x+y:o<3?x*y:o<8?x<y:x==y;else{--p;p=o~5?x?y:p:o~6?!x?y:p:p-1}}}

Try it online!
This essentially works by treating the input fields as the locations in memory, instead of initializing an array to store the program.
An extra 3 bytes (included in score) are required for the -F, switch, which sets the comma as the field separator.
Usage examples
<code> stands for the program posted above.
Interpret an Intcode program stored in a file named intcode.txt:
awk -F, '<code>' intcode.txt

Interpret an Intcode program using a Here-string:
awk -F, '<code>' <<< 9,1,204,-1,2205,-1,8,99,0

Pass a value as input:
awk -F, -v i=1 '<code>' intcode.txt

Pass multiple input values:
awk -F, -v i=1,2,3 '<code>' intcode.txt

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


text:
Is this ordinal prime?
You are given an countable ordinal \$1 < r < \varepsilon_0\$. Determine whether or not it is prime. If not, provide exactly two ordinals \$r_0, r_1 < r\$ such that \$r_0r_1 = r\$, following rules of ordinal multiplication, and furthermore satisfy at least one (not necessarily both) of the following:

\$r_0\$ is a limit ordinal
\$r_0 \le r_1\$

More accurately, an ordinal expressed in Cantor normal form is a list \$[a_1, a_2, a_3, \dots, a_{n-1}, a_n]\$, where when \$1 \le i < n\$, \$a_i\$ is an ordinal expressed in Cantor normal form and \$a_n\$ is an integer. Furthermore, for \$1 < i < n\$, the ordinal inequality \$a_{i-1} \ge a_i\$ holds.
Input
Any input that can provably describe any ordinal also expressible in Cantor normal form is accepted. For input forms deviating greatly from Cantor normal form, please also provide a brief way to convert a Cantor normal form ordinal to input.
Output
If the given ordinal is prime, then a constant result, distinct from non-prime inputs must be returned.
Otherwise, return two ordinals, expressed the same way as the input, representing \$r_0\$ and \$r_1\$, respectively.
Scoring
This is code-golf, so shortest program (in bytes) wins.
Examples
An input of \$\omega^2+1\$, or [2,1] in Cantor normal form, would be marked prime.
On the other hand, an input of \$\omega+2\$, or [1,2] in Cantor normal form, would be composite and the program should return a pair ([2],[1,1]) in whatever form it accepted.
Remember that integers are ordinals too.
You do not need to consider \$r=1\$.
More examples:
[1,100] => [100] * [1, 1]
[2,1] => prime
[3,0] => [2,0] * [1,0]
[[1,1],2] => [2] * [[1,1],1]
[[1,1],0] => [[1,0],0] * [1,0]
[[1,0],0] => prime
[1,1,1] => [1,1] * [2]

Welcome to Code Golf Stack Exchange. Nice first challenge. Maybe some test cases?

I think the Wikipedia page clears up primness and multiplication well enough. For example, [2,1] would be prime, but [2] would be composite and output [1],[1].

Sure, but it is customary here to include some test cases, especially edge cases to ease testing and verification of solution posts.

Questions should be self contained, rather than link elsewhere. Can you add explanations for the linked sections, and maybe a short description of an algorithm to determine if an ordinal number is prime?

If the input is prime, do we have to always return the same result (eg, True)? Or does it suffice to have a different return type from non-prime inputs? For example, is the following allowed: if the input is not prime, return a pair with a possible factorization; if the input is prime, return something that is NOT a pair (but differs depending on the input)?

"but [2] would be composite and output [1],[1]" ... I think you mean "but [2,0] would be composite and output ([1,0],[1,0])". In fact, [2] represents 2, which is prime.

@JoKing While I agree in principle, I do think that this question is self contained.  You should not have to explain advanced mathematics, just to ask about it.

What should the factorisation of $\omega+2$ be?

@KritixiLithos That can be factored as $2(\omega+1)$.
Because $$2(\omega+1) = 2\omega + 2 = \omega + 2$$.

This is the 270th question about pr... never mind I thought ordinal primes as something trivial. Nice first challenge, though I would like to ask, so for an input [a, b], a denotes the power and b denotes the coefficient?

@ShieruAsakoto Not exactly. All non-last elements are taken as the power of $\omega$ and the last element is the integer constant.

Could you please add ⍵2+1 as a testcase?

Haskell, 1068 1042 1012 bytes
-30, mostly from replacing if/then with guards. I'm sure it can be golfed more.
data W=W[W]Int deriving Show
f EQ y=y
f x _=x
m=1<0
k=1>0
[]#[]=EQ
[]#_=LT
_#[]=GT
(W x y:z)#(W a b:d)=f(x#a)$f(compare y b)$z#d
x?y=x#y>EQ
b x=break(\(W y _)->y#x/=GT)
x&[]=x
d&(x@(W v w):u)=case b v d of(y,W f m:_)|f#v>LT->y++(W v$m+w):u;(y,_)->y++x:u
x![]=x
d!(W v w:u)=case b v d of(_:_,_)->d;(_,W f m:g)->if w<m then(W f$m-w):g else g!u
[]%_=([],k)
x@(W g h:d)%b@(W e f:_)|b?x=([],m)|g!e?[]=(\(q,r)->([W(g!e)h]&q,r))$d%b|k=(\q->(q,(foldl(&)[]$t b<$>q)#x==EQ))[W[]$div h f]
t(W x y:z)(W[]n)=(W x$y*n):z
t(W x _:_)(W b n)=[W(x&b)n]
l=all(\(W e _)->e?[])
q=max
o[]=0
o(W e n:u)=q n$q(o e)$o u
v[]=0
v(W e n:u)=q(1+length u)$q(v e)$v u
d[]=0
d(W e n:u)=q(1+d e)$d u
e(W x _:[])(W y _:_)=x?y
e(_:x)y=e x y
g _ 0_ n=[[W[]x]|x<-[1..n]]
g m d s n|p<-g m(d-1)s n=fst$h s$filter(m?)$p++[[W x y]|x<-p,y<-[1..n]]
h 1z=(z,z)
h n z|(a,p)<-h(n-1)z,n<-[x++y|x<-z,y<-p,e x y]=(a++n,n)
r x=p x$g x(d x)(v x)$o x
p _[]="p"
p x(y:z)|(q,r)<-x%y,x?y&&x?q&&r&&(l y||not(l y&&l q||d y<2&&d q<2)||y#q<GT)=show y++"*"++show q|k=p x z

Try it online!
Or try a version that pretty-prints the inputs and outputs.
Input Format
The input format is Cantor normal form, written as \$\omega ^{\beta _{1}}c_{1}+\omega ^{\beta _{2}}c_{2}+\cdots+\omega ^{\beta _{k}}c_{k}\$, where \$k\$ is a natural number, \$ c_{1},c_{2},\ldots ,c_{k}\$ are positive integers, and \$ \beta _{1}>\beta _{2}>\ldots >\beta _{k}\geq 0 \$ are ordinal numbers.
Each term \$\omega ^{b}c\$ is written as W b c and terms are written as a list in [] separated by commas.
Examples:
[]\$ = 0\$
[W[]1]\$ = 1\$
[W[W[]1]1]\$ = \omega\$
[W[W[]1]1,W[]1]\$ = \omega + 1\$
[W[W[]2]3,W[]4] \$=\omega^2\cdot 3 + 4\$
[W[W[W[]2]1]1,W[]4] \$=\omega^{\omega^2} + 4\$
[W[W[W[]1]1,W[]1]1,W[]1]\$ = \omega^{\omega+1} + 1\$
Test Cases
Output from the main version:
[W [W [] 2] 1,W [] 1] => p
[W [W [W [] 1] 1] 1] => p
[W [W [W [W [] 1] 1] 1] 1] => p
[W [W [] 1] 1,W [] 100] => [W [] 2]*[W [W [] 1] 1,W [] 50]
[W [W [] 3] 1] => [W [W [] 1] 1]*[W [W [] 2] 1]
[W [W [W [] 1] 1,W [] 1] 1,W [] 2] => [W [] 2]*[W [W [W [] 1] 1,W [] 1] 1,W [] 1]
[W [W [W [] 1] 1,W [] 1] 1] => [W [W [W [] 1] 1] 1]*[W [W [] 1] 1]
[W [W [] 1] 2,W [] 1] => [W [W [] 1] 1,W [] 1]*[W [] 2]
[W [] 2903591] => [W [] 1699]*[W [] 1709]

Output from the pretty-print version:
[W [W [] 2] 1,W [] 1] == w^2 + 1 => p
[W [W [W [] 1] 1] 1] == w^w => p
[W [W [W [W [] 1] 1] 1] 1] == w^(w^w) => p
[W [W [] 1] 1,W [] 100] == w + 100 => (2)*(w + 50)
[W [W [] 3] 1] == w^3 => (w)*(w^2)
[W [W [W [] 1] 1,W [] 1] 1,W [] 2] == w^(w + 1) + 2 => (2)*(w^(w + 1) + 1)
[W [W [W [] 1] 1,W [] 1] 1] == w^(w + 1) => (w^w)*(w)
[W [W [] 1] 2,W [] 1] == w*2 + 1 => (w + 1)*(2)
[W [] 2903591] == 2903591 => (1699)*(1709)

Strategy
This is probably not the fastest solution, but I thought it might be relatively short for code golf. It works for all of the test cases and works well for natural numbers. For ordinals with many terms, this may take a very long time to run.

Generate a sequence of ordinals which may divide the input.
Test each ordinal in the sequence to determine whether it divides the input and meets the additional criteria. If it does, return a formatted string containing the divisor and quotient.
If the sequence was exhausted, return "p" for prime.

Implementation
I started with code I found online that implements ordinal addition and multiplication and uses the QuickCheck library to test that properties (theorems) are true for a large number of inputs.
I implemented left subtraction and then left division with remainder and verified that the operations were consistent with the following theorems.
Left subtraction: Let \$x\$ and \$y\$ be ordinals such that \$x \geq y\$. Then there exists a unique ordinal \$z\$ such that \$x = y + z\$.
Left division: Let \$x\$ and \$y\$ be ordinals. Suppose \$y\neq0\$. Then there exist unique ordinals \$z\$ and \$w\$ such that \$x=y\cdot z+w\$ and \$w < y\$.
Generated Sequences
To test whether an ordinal is prime, I generate a list of potential divisors. This would be easy for natural numbers, but infinite ordinals are greater than infinitely many ordinals.
I check the given ordinal to determine the depth, maximum number of terms (at each depth), and maximum coefficient.
I then recursively generate ordinals that are less than the given one and up to the given depth, term count, maximum coefficient. I don't have a proof that this is sufficient, but intuitively it seems like it would be.
Here are some examples.
Example 1: \$\omega^2\cdot 3 + 4\$. Depth: 2, Max term count: 2, Max coefficient: 4. Generated list of potential divisors, length 26: \$1, 2, \omega, \omega + 1, \omega + 2, \omega\cdot2, \omega\cdot2 + 1, \omega\cdot2 + 2, \omega^2, \omega^2 + 1, \omega^2 + 2, \omega^2 + \omega, \omega^2 + \omega + 1, \omega^2 + \omega + 2, \omega^2 + \omega\cdot2, \omega^2 + \omega\cdot2 + 1, \omega^2 + \omega\cdot2 + 2, \omega^2\cdot2, \omega^2\cdot2 + 1, \omega^2\cdot2 + 2, \omega^2\cdot2 + \omega, \omega^2\cdot2 + \omega + 1, \omega^2\cdot2 + \omega + 2, \omega^2\cdot2 + \omega\cdot2, \omega^2\cdot2 + \omega\cdot2 + 1, \omega^2\cdot2 + \omega\cdot2 + 2\$
Example 2: \$\omega^\omega\cdot3+4\$. Depth: 3, Max term count: 2, Max coefficient: 4. Generated terms list length: 151,994.
Since that list is generated lazily, the program still gives a fast answer.
As the depth and maximum term count increase, the lengths of the generated sequences increase very quickly.
Note
For the last given test case, \$\omega\cdot2+1=(\omega+1)\cdot2\$, I was unable to satisfy either of the two given additional criteria (\$_0\$ is a limit ordinal, \$_0 \leq r_1\$). However, I was able to satisfy the following criteria stated on Wikipedia, which is a slight variation of the given criteria:

Every limit prime occurs before every successor prime
If two consecutive primes of the prime factorization are both limits or both finite, then the second one is at most the first one.

If anyone is interested, I could provide a less golfed version of this code.

Welcome to PPCG and nice first answer. Having you also seen the approach given at Wikipedia for factorisation in to primes https://en.wikipedia.org/wiki/Ordinal_arithmetic#Factorization_into_primes? It would appear only ordinal subtraction would need to be implemented, but I am not sure

I didn't fully understand it, but I'll take another look at some point.


text:
.-...--..---.-...--..... the red-nosed reindeer
Can you recover a sequence of letters from a sequence of dots and dashes? In Morse code, x is represented by -..-, but without the help of spaces, -..---.-... could represent xmas, or dole, or teettteteee, etc.
I took the lyrics from "Rudolph, the Red-Nosed Reindeer" to make the following sequence of letters:
youknowdasheranddancerandprancerandvixencometandcupidanddonnerandblitzenbutdoyourecallthemostfamousreindeerofallrudolphtherednosedreindeerhadaveryshinynoseandifyoueversawityouwouldevensayitglowsalloftheotherreindeerusedtolaughandcallhimnamestheyneverletpoorrudolphjoininanyreindeergamesthenonefoggychristmasevesantacametosayrudolphwithyournosesobrightwontyouguidemysleightonightthenhowthereindeerlovedhimastheyshoutedoutwithgleerudolphtherednosedreindeeryoullgodowninhistory

and then I converted each letter to its Morse code representation to get
-.-----..--.--.---.---...-.........-..--.-..-...--.-.-...-..--.-...--..-..--.-.-...-..--.-.....-..-..-.-.-.-.-----.-.--.-..-.-...-.--...-...--.-..-..----.-...-..--.-..-....-....---...-.-.....---..----.-----..-.-..-.-..-.-...-..-.....-----...-..-..------..-....-....-.-.....-.---..-..-.-...-...-...--..---.-...--.....-......-..-..-.---....-...-....-.-.....-......--...-...-..-.-.--.........-.-.---.---.....--.-......-.-.-----..-....-..-.....-.--..--.-----..-.-----..-.-..-......-.-.....--.--..---..-..---.--....-.-...-..---..-.-.....----......-..-....-.-.....-...-....-..----.-...-..---......--.-..-.-..-.-...-........---..---....-.....-.---.....-..-..-...-.--.------.-..-...--..---.-...--......------..-...-..--.-.--.-....-.-.....-.--..---....-.....-.----....-.-----.--.-.---.-......-......---.-.......-.....--.-.--.-..---.----....--.--.-...--..---.-...--......--..-....-.-----..-.-.-.---.......----....-...--.....-.------.--.-----..---...-..-...---.--....-.....--.....-----...--.....--.....-.....---.---......-....-.-.....-..-..---...-.-........--.-...-.....-.--.......---..--.-..---..--.--..-....--..-.....-...--..---.-...--.....-......-..-..-.---....-...-....-.-.....-.-.-----..-.-...-..--.----..---.---...-..........----.-.-.--

For reference, here are a few Morse code libraries:
a .- b -... c -.-. d -.. e . f ..-. g --. h .... i .. j .--- k -.- l .-.. m -- n -. o --- p .--. q --.- r .-. s ... t - u ..- v ...- w .-- x -..- y -.-- z --..

.- a -... b -.-. c -.. d . e ..-. f --. g .... h .. i .--- j -.- k .-.. l -- m -. n --- o .--. p --.- q .-. r ... s - t ..- u ...- v .-- w -..- x -.-- y --.. z

.- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --..

Write the shortest code that takes as input the sequence of dots and dashes above and one of the Morse code libraries above, and then outputs the sequence of letters above.
Edit 1: Since we are ignoring the letter spaces and word spaces that are typically used in Morse code, this challenge is nontrivial and significantly different from previous challenges involving Morse code. We are implicitly hunting for the relative Kolmogorov complexity of a fixed sequence of letters given the corresponding sequence of dots and dashes. This means your code only needs to run for the fixed inputs provided above, and produce the desired output provided above.
Edit 2: By popular request, I am relaxing the constraint on the Morse code library by providing two alternative libraries. If necessary, I am willing to add reasonable libraries in the future.

Python 3, 356, 302, 299 bytes
import sys
S,L,N="",input().split(),int("3EED3TD7OWRVC3DD9L9NKQY0NEADDU7704EYGXWLFF2PGCR6H6ET3DRODQ4O22XAAFV5KOSWET2D2CQZOMXRQWEO7I2US8FRU5Z2CU8D73B10GEG08YUJQPZND1978359JZOEUGKHT2HXO70Z6PK59T8RMY0BBRJ1D78AZEEYBWU4N7IW1TLUN57",36)
while N:S,N=S+chr(97+L.index(sys.stdin.read((N&3)+1))),N>>2
print(S)

Try it online!
Takes the library followed by a newline followed by the morsecode from the standard input.
The library used is .- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --..
Explanation:
The majority of the code is a precalculated number of morse widths.
A morse caracter in the library is between 1 and 4 dihs and dahs long. In the number i store this as two bits of information.
To recall this number i & it with 3 and shift the result over by two bits.
I then read the number of dihs and dahs from the standard input and lookup in the library what the offset of that caracter is from "a". Then repeat and print.
I think the best way to shave of bytes will be to store the number more compactly.

Edit: removed 54 bytes by changing the library format, and storing the number as base36 following the suggestions of A Rex and Chas Brown

Edit: -3 bytes for removing redundant parameter from str.split() - Chas Brown

Wow, nice first answer!

The question has been updated to allow different formats for the library. I believe this would let you skip the [1::2] in your answer.

308 by encoding your Magic Number as base 36 and putting the while loop on one line. (And, Welcome to codegolf!)

You can save 3 more by replacing .strip(" ") with .strip().

APL (Dyalog Extended), 189 188 bytesSBCS
Full program. Prompts for the Morse code. Doesn't need the library. Requires ⎕IO←0
⌊⌂morse⍞⊂⍨∊1↑⍨¨1+4⊤'⍳÷+≠í⍀÷<í∧○Ñ>å/∧∨êî∘ß∧äñ⍀○≠è[*⌷∨[î≠∇è⊂Øî⊃⍀[⌷Éäï\∘∧↑æ=íå⌿∧∨ëäÖ⌿ê/≤⌊∘[Å↓Öï○+Ü÷≥↓≤≥>⌷∘á⊃↑Ü⍳⊣[⌿-Ø↑ä/∧∧≠≠Ñíí+ßÜ+-○é↓↓≥≥×∧↑**⍨↑}∧⍨≥ç⍀∧}×⍀Àëç⍀Ø⍨∧∘[×/∘Å∧~≥○ëâ⊂å∨≥Àäè?'⍳⍨125↓⎕AV
Try it online!
⎕AV the Atomic Vector (the character set)
125↓ drop the first 125
'…'⍳⍨ the indices in that of these characters
4⊤ To-base four
1+ increment
This gives us the length of each Morse letter.
¨ for each of those lengths:
 1↑⍨ take that many elements from 1, padding with zeros when needed
∊ ϵnlist (flatten)
⊂⍨ use that as a mask indicating partition-beginnings to cut the following:
⍞ prompt for Morse code
⌂morse convert from Morse code to uppercase text
⌊ lowercase

APL (Dyalog) + dfns + Jelly's dictionary, 181 175 (172) bytesSBCS
Full program. Requires ⎕IO←0 and ⎕AV redefinition. Doesn't use the challenge's Morse code library.
M←∊∘morse¨D⋄C←∊(7⍴51)⊤246⊥5 17⍴¯7+⎕AV⍳'k%aÏ⍵FþfÅ⍵ìÆ⌶á≥å3¶cÒ⍺\ujü─⍳%S⊣ì⍙ÒÛÙ3Ùp`Ø,hÇñ⊂┴Ö⍪l∪⍒i1⍵Í:-îà⌽ì≥3€ã(⍝S]ÁGXræ∇O7Uæî'
C↓⍨←≢i↓⍨←≢M⊃⍨w←(⊃C)⌷∊(⍸M⍷⍨⊂)¨⌽,\24↑i
⍞←819⌶w⊃D
→2

Try it online! - 175 byte version, running at decent speed
M←∊∘morse¨D⋄C←∊(7⍴51)⊤246⊥5 17⍴¯7+⎕AV⍳'k%aÏ⍵FþfÅ⍵ìÆ⌶á≥å3¶cÒ⍺\ujü─⍳%S⊣ì⍙ÒÛ─3Ùp`Ø,hÇñ⊂┴Ö⍪l∪çi1⍵Û:-îà⌽ì≥3€ã(⍟S]ÁôXræ∇O7Uæî'
C↓⍨←≢i↓⍨←≢M⊃⍨w←(⊃C)⌷∊(⍸M⍷⍨⊂)¨⌽,\i
⍞←819⌶w⊃D
→2

Try it online! - 172 byte  version, taking about 20 times as long to finish (especially slow at beginning)
-3 bytes by packing base 51 into base 246 instead of base 64 into base 256 and losing the apostrophe
-3 bytes by ending with an error message instead of cleanly
-3 bytes by running about 20 times more slowly
When I saw this question, I thought that the ultimate solution, the one the question was made for, would involve combining both the Morse code and a dictionary. I was surprised when the only submitted solutions turned out to use a table of letter boundaries. My interest was sparked; I'd take a crack at it myself.
The first step was to look for a suitable dictionary (I tried a few). Then I implemented the first version of the algorithm in C++. This  enumerated all the possible words that could be at a given point, numbering them sequentially, until finding the one matching its corresponding value in an array made from running the same algorithm with the words of the song as a reference. This initial version enumerated the words in alphabetical order.
I was rather astonished to see just how ambiguous Morse code is without the inter-letter gaps. I expected it to be somewhat ambiguous, but not to the extent that it actually turns out to be! Some of the alternatives are pretty funny, too. Every time reindeer comes up, for example, it could also be leech. And the entire song can be mapped to completely different words, all the way from start to finish (gibberish, but present in the dictionary).
The dictionaries I tried turned out to be not so well-suited to the task. Either they were missing too many words, requiring them to be added to the dictionary for the algorithm to work, or they were too comprehensive, and the resulting array of "word choices" had elements exceeding 63, meaning it couldn't be packed into 6 bits per word.
Then it occurred to me to try Jelly's dictionary. It turned out to be perfect for this. Not every word is in the dictionary, including simple words like a, names, games, and glows, and the contractions won't (wont isn't in it either) and you'll, but I took advantage of the fact that there are no spaces in the output for this challenge, and cheated:

Blitzen → blitz en
had a → Ha DA
glows all → glow sall
names they → Nam EST hey
games then → gamest hen
won't you → won Ty ou
him as they → Hima ST hey
you'll → you LL

It was a spookily perfect fit for this challenge, even containing all of the proper nouns other than Blitzen. Another cheat was to use compound words to shrink the size of the array of word choices: outwith and godown. As result of all this, the word choice array had 116 elements in it, and with none exceeding 63, the whole thing could be packed into 87 bytes. (This, despite the compromise of encoding then as th en so as not to exceed the value of 63.) Contrast this with the array of Morse codeword boundaries, which takes 119 bytes (118.5 rounded up).
But that leads to the next problem: Although the data size is considerably smaller, the code complexity is ballooned in comparison. I didn't know any golfing languages, and most of them have very limited documentation that's quite hard to use to learn from scratch.
So I worked on refining the algorithm. The next optimization was to iterate through letters from longest Morse codeword length to shortest, still in C++. This actually decreased the maximum index value to 59, meaning that with arithmetic rather than bitwise packing it could use base 60 to fit in 86 bytes. (For illustrative purposes I also ported this one to Java, which was interesting... I learned a little more Java, and was surprised to see it run even faster than the C++ version, using >125% of a CPU core, even though the algorithm is inherently single-threaded. My best guess is that the hash function is multithreaded even for individual look-ups.) This data set would respond better to Huffman encoding than the previous one, though not enough to even break even.
I tried optimizing the C++ code for smaller compiled object code, evaluating if it was worthwhile to attempt hand-coding it in x86-32 assembly. It stubbornly remained way too large; the best I could do was to squeeze it in at just under 256 bytes, not including the data. So it wasn't worth hand-coding in asm (the letter-boundary version beats it by a huge margin).
So it seemed that the only way this algorithm would have justice done to it would be for me to learn a golfing language. Quite daunting, given that I've never used anything like these languages.
And then Adám offered to teach me APL. I jumped at the chance; while APL doesn't usually win challenges where there's also a Jelly or 05AB1E contender, it tends to come pretty close, has a deep and rich past, and formed the basis of or influenced many newer languages. Heck, I knew of it as a child, and was a bit curious about it even then, but never took a crack at learning it until now.
Many thanks to Adám for extensive help in teaching me various aspects of Dyalog APL and golfing down this program – my first APL program.
I initially tried porting the algorithm as it stood to Dyalog APL. It worked, but was very slow, even when compiled; in 60 seconds it only gets up to donner or so. Adám conferred with Marshall at Dyalog, and there wasn't really a way to speed it up any further. But it was suggested that encoding the entire dictionary in Morse code could result in a speedup. And I realized that this strategy could make for much better golf, too.
So the next stage in adapting the algorithm was to translate the entire dictionary to Morse code, and at each point in the encoded song, iterate through possible words in reverse order of their length in Morse dots+dashes (with the longest being 24). Not only is this approach far, far faster in APL (and probably many other languages), and far more concise, but even the data is more lightweight – far more of the "word choice" array elements are 0 or 1, the largest value is just 50, and there are only 115 elements (the then no longer needed or benefited from breaking up), meaning that in languages with arbitrary-precision base conversion, it could be packed in base 51 and take up only 82 bytes. In APL though, the overhead of implementing arbitrary-precision base conversion would override the benefit, and I stuck with packing groups of 7 elements, in base 51, into groups of 5 bytes in base 246 (as log246 517 ≈ 4.999295), taking up 85 bytes. This data set responds even better to Huffman encoding than the previous, but still wouldn't break even: 4 1 2 21 1 13 0 23 0 3 26 1 23 0 26 0 27 15 8 6 0 34 10 0 1 1 7 0 43 23 0 4 37 50 1 0 3 23(24) 22 6 15 6 16 3 2 17 10 12 5 0 9 31 1 3 9 21 0 32 16 9 20 32 8 12 31 5 0 4 27 14 1 7 13 16 0 0(1) 27 4 4 22 10 0 16 5 7 15 3 12 18 4 2 13 1 0 50 4 49 2 1 4 38 20 0 0 19 0 43 23 0 1 6 12 0 38 0
So as it turns out, in APL it still doesn't golf well enough to beat the existing letter-boundary solutions, even if the overhead for unpacking the "word choice" array (24 bytes) and for using Dyalog Unicode instead of Extended (7 bytes) are subtracted (yielding 144 (141) bytes code+data). I still think that it might be possible to make it shorter than 129 bytes in one of the languages more specialized towards golfing, and will likely try that eventually.
Of course, with bigger source material than the song this challenge uses, this dictionary-based approach would win hands-down. Some interesting extensions to it would be: Look 2 or more words ahead, and perhaps use an N-gram frequency table; Look all the way ahead, using a model of most-likely N-grams (probably would be incredibly slow).

Explanation of the code
Dyalog Unicode is used, even though Dyalog Extended could save 7 bytes (4+3, as described below), because the former allows compiling for speed, whereas the latter is very slow, to the point that it would be impractical for demonstration.
On my system, this version takes about 45 (or 901) seconds to finish (the first 7 seconds of this are taken converting the dictionary into Morse code). On TIO it doesn't quite finish within 60 seconds.
Header
⎕IO←0 - set Index Origin to 0 (for 0-based array indexing)
⎕AVU[62 63 60 93 11 94]←9016 9060 9056 8838 9018 9080 - modify the default Atomic Vector to match the actual Single-Byte Character Set we're using (£¢¥ýɫ· overwritten with ⌸⍤⍠⊆⌺⍸, at each character's respective index within the Atomic Vector)
'morse'⎕CY'dfns' - import the Dyalog APL Morse code dfn – I decided to keep this in the header because Dyalog Extended has it by default
D←1(819⌶)'^\w+ = ''{3}|''{3}\.split\(\)$'⎕R''⊃⎕NGET'/usr/local/lib/python3.7/site-packages/jelly/dictionary.py'1

Load Jelly's dictionary, and convert it to lowercase:
⊃⎕NGET'/usr/local/lib/python3.7/site-packages/jelly/dictionary.py'1 - read the file as a set of newline-delimited lines into an array (with empty lines dropped, of which there is one)
'^\w+ = ''{3}|''{3}\.split\(\)$'⎕R'' - using a regex (PCRE) Replace, remove the Python code that surrounds the dictionary's two word lists (short and long), resulting in a merged list that keeps everything from short before everything from long (but is otherwise in case-insensitive alphabetical order)
1(819⌶) - convert to uppercase, so that the morse dfn will work on it (since it only takes/gives uppercase input/output)
D← - assign to the variable D
∇D R i;C;M;w

Define the tradfn R, taking left argument D (dictionary word list) and right argument i (the input, i.e. the song in undelimited Morse code), and having local variables C (word choice array), M (dictionary translated to Morse code), and w (array listing the indices into the dictionary of what the current word could be). The arguments are passed and the local variables are declared to allow the R to be compiled properly (see footer).
Code
M←∊∘morse¨D⋄C←∊(7⍴51)⊤246⊥5 17⍴¯7+⎕AV⍳'k%aÏ⍵FþfÅ⍵ìÆ⌶á≥å3¶cÒ⍺\ujü─⍳%S⊣ì⍙ÒÛÙ3Ùp`Ø,hÇñ⊂┴Ö⍪l∪⍒i1⍵Í:-îà⌽ì≥3€ã(⍝S]ÁGXræ∇O7Uæî'

∊∘morse¨D - compose the two functions ∊ (Enlist - flatten / join) and morse, and apply the composed function to the dictionary D. Without the ∊ composed in, morse returns an array of Morse codewords when given an alphabetical string as input, but we need the Morse-encoded dictionary to leave out inter-letter gaps, thus the ∊ flattening.
M← - assign the result to M, the Morse-encoded dictionary.
⋄ - statement separator
'k%aÏ⍵FþfÅ⍵ìÆ⌶á≥å3¶cÒ⍺\ujü─⍳%S⊣ì⍙ÒÛÙ3Ùp`Ø,hÇñ⊂┴Ö⍪l∪⍒i1⍵Í:-îà⌽ì≥3€ã(⍝S]ÁGXræ∇O7Uæî' - word choice array, packed into a string using Dyalog APL's updated SBCS. For this to work, the encoding must not contain newlines, i.e. ⎕UCS 10, 12, or 13 (⎕AV[2 3 5]), and any apostrophes must be doubled (but there are none).
⎕AV⍳ - map characters to SBCS indices (in the range 0-255) using the modified Atomic Vector.
¯7+ - add −7 to all SBCS indices. The corresponding addition of 7 was done during the encoding, to avoid occurrences of any of the three types of newlines. Due to use of base 246, this addend is quite flexible, and could range from 6 to 10 and be guaranteed to stay within range regardless of the data; thus it can be adjusted to minimize the number of apostrophes (which would each cost 1 byte, as they need to be doubled in a quoted string). As it happened, it was possible to have zero apostrophes.
5 17⍴ - arrange into a matrix for base conversion; each of the 17 columns will be converted as a unit. (In Dyalog Extended, this could be done as 5 ¯1⍴.)
246⊥ - base-convert the 5 values in each column that range 0-245 (base 246) into a single number ranging 0-900897818975, the top row being most significant, yielding a flat array. (But due to the nature of the underlying data, it will actually range 0-897410677850.)
(7⍴51)⊤ - base-convert each array element back into a column, with 7 rows, each number in the range 0-50 (base 51). (In Dyalog Extended, this could be done as 51⊤. The number of rows would be autodetected, so if by a coincidence all values were less than 516, this shorthand syntax wouldn't work properly. In this case though, in would work, and would save 4 bytes.)
∊ - flatten the matrix into an array, row by row.
C← - assign to the variable C, the word choice array.
C↓⍨←≢i↓⍨←≢M⊃⍨w←(⊃C)⌷∊(⍸M⍷⍨⊂)¨⌽,\24↑i

This is Line 2 (as referred to by the :GoTo at the end of the loop):
i - take the current value of the input (with the parts of it that have already been processed deleted)
\24↑ - truncate to 24 characters (dots+dashes). That is the length of the longest Morse encodings (rudolph and christmas). This step is omitted in the  version, which results in almost identical operation, but far slower; the word choice array only needs to be modified in two places (increasing the choice value by 1 at the and in andifyoueversawit and at christmas), meaning that at all other words, no matches for >24 dots+dashes are found in the dictionary.
,\ - make a list of Morse subsequences starting at the beginning of this, ranging from 1 dot/dash long to 24 dots/dashes long (or maximum length, in the  version), from shortest to longest (e.g., at the very beginning, would be '-' '-.' '-.-' '-.--' '-.---' '-.----' '-.-----' '-.-----.'...'-.-----..--.--.---.---..')
⌽ - reverse that list, so that it goes from longest to shortest (this way of encoding results in smaller element values for the word choice array on average)
(⍸M⍷⍨⊂)¨ - to each item in this list, apply the function ⍸M⍷⍨⊂: ⊂=enclose one level of nesting deeper, to match the nesting of the Morse-encoded dictionary; M⍷⍨=return an array the same size as the dictionary, where values of 0 mean "not found" and 1 means "found", ⍸=convert the list of 0s and 1s into a list of the indices of the 1s. The result is a matrix with 24 rows (ranging from longest to shortest Morse, top to bottom), each of which contains a variable number of columns (minimum zero), listing the indices of all the words in the dictionary that match the Morse sequence from the input of the corresponding length (in alphabetical order, but with Jelly's short dictionary entries preceding its long ones).
∊ - flatten this. The end result is a list of the indices of all the words in the dictionary that match any item in the list of Morse sequences from the input that range from 24 to 1 dots+dashes long, retaining the sorting of longest to shortest (and within each length, entries from Jelly's short come before those from its long, and within that, they're alphabetically ordered).
(⊃C)⌷ - from the resulting list, take the element at the index of the current word choice (⊃=first element of) from the word choice array C. Equivalent to wrapping everything to the right in ( ) and putting [⊃C] to the right of it, but saves 2 bytes.
w← - assign this (the index into the dictionary of the correct current word in the song) to the variable w, returning it as a result
M⊃⍨ - return the wth element of M (the Morse code of the current word), unwrapped. Equivalent ⊃M followed by wrapping everything to the right in [ ], but saves 1 byte.
≢ - return the length of the Morse code of this word (in characters, i.e. dots+dashes). If it had not been unwrapped by ⊃, the result would always be 1.
i↓⍨← - delete that many characters (the length of the word in Morse code) from the beginning of the input i, so that on the next iteration of the loop, the next word will be handled, and return the number of characters deleted as the result
≢ - return the length of the number of characters; since that is a scalar, it will always be 1
C↓⍨← - delete that many (1) characters from the beginning of C, the word choice array, so that on the next iteration of the loop, the next word choice will be ready. This saves 1 byte relative to what a separate statement (C↓⍨←1) would take.
⍞←819⌶w⊃D

w⊃D - Take the wth element of D (the current alphabetical word) and unwrap it, so that when printed, there are no spaces to its left or right. Equivalent to ⊃D[w].
819⌶ - Convert to lowercase. Equivalent to 0(819⌶). (In Dyalog Extended, this could be done as ⌊, saving 3 bytes.)
⍞← - Print the result without a newline. In TIO, this prints to stderr.
→2

:GoTo Line 2 (the beginning of the loop), unconditionally. A line number is used to save the 2 bytes that defining a label (e.g. L:) would cost. The lack of a looping condition results in the program ending with * Command Execution Failed: INDEX ERROR when it tries to access the first element of an empty array (after it has successfully printed the entire song).
If running this program locally, note that the error prevents ]runtime from working. To work around this, the program may be called with :Trap 3...:Else ⋄ :EndTrap wrapping it.
The clean version, avoiding this error, would be →2⊣¨i, meaning :GoTo Line 2 while i is not empty. This would work because 2⊣¨i returns an array of 2s matching the length of i, and the :GoTo goes to the line number of the first value in the array, if one exists.
Footer
∇ - end the tradfn R
2(400⌶)'R' 'morse' - compile the user tradfn R and the built-in dfn morse. Without this, the program would run far slower.
⍎'D R⍞⋄⍬' - Call tradfn R with dictionary D as its left argument and the input (⍞) as its right argument. This passing of arguments is done only for speed, so that the compile can work properly (it doesn't like global variables, or directly using input). The ⍎ and ⍬ constitute a workaround Adám wrote for me for the way the APLs work currently on TIO. They expect code in the input, but I wanted a clean separation between code and input.

Jelly, 138 135 bytes
ḲiⱮ“Q®ḃƁ⁼ṇÑ1¿Ọɠ\ƥȥ⁼ṙ⁴EŀƥŒEæʋØ>þ>⁴þʋ[⁾Ƒ]eÞḍ8ß®ⱮȮø⁹ç÷R?g®=,¥ėµ@ØU~"/Xçq®ÆƬ°ɠsṭṭ?dC#Ċ?gÑ¶PÇH5p@ʂEœ⁹½G6ḌƘṪµɦ8€(S¦Ḥ⁸ṫ"ḟḢlṾ¦ƤḃƭẊ@’ḃ4$ÄṬk⁹¤ịØa

Try it online!
A dyadic link taking the library as the left argument and the Morse code input as the right argument. Returns a Jelly string of the lyrics. The long integer that takes the majority of the code has the lengths of each Morse code character encoded within it.
Explanation
Ḳ                      | Split at spaces
 iⱮ              ¤     | Find index of these in each of the following:
   “Q...@’             | - Base-250-encoded integer 742925387377430937422864458121941352705403867269973650879937105837755604647313120541399315429452997316260711263757137193164236124383957174543961671910365268304120327243209050996915401898167278257845227193061059012165352924148307417330452740236835399667569278751322913192633409885614815
          ḃ4$          | - Bijevtive base 4
             Ä         | - Cumulative sum
              Ṭ        | - Convert to logical list with 1s at the appropriate indices
               k⁹      | - Split right argument at those positions
                  ịØa  | Finally, index into lowercase letters

Python, 487 bytes
lambda a,b:'youknowdasheranddancerandprancerandvixencometandcupidanddonnerandblitzenbutdoyourecallthemostfamousreindeerofallrudolphtherednosedreindeerhadaveryshinynoseandifyoueversawityouwouldevensayitglowsalloftheotherreindeerusedtolaughandcallhimnamestheyneverletpoorrudolphjoininanyreindeergamesthenonefoggychristmasevesantacametosayrudolphwithyournosesobrightwontyouguidemysleightonightthenhowthereindeerlovedhimastheyshoutedoutwithgleerudolphtherednosedreindeeryoullgodowninhistory'
Takes morse code and any of the three libraries as input, returns the text.

Heh; I wonder if any language could save anything by packing the string from 8-bit characters down to 5 or 6-bit characters (all lower case letters so 32 code points is sufficient).  That would leave ~180 bytes for decompression code with bit-shifts (back to ASCII / UTF-8) for this to break even.  Maybe good for assembly language / machine code.  I'm assuming we can't justify using a 5 or 6-bit character set for the actual output without also counting the size in 5-bit bytes.

I saw what you did there :-)

@PeterCordes I had a similar idea and took a crack at it. Feel free to suggest improvements!

05AB1E, 149 131 129 bytes
•Nα0Ω¤èGë™jƒć›
Ù¾₂¶É¨=Yàf§ì[ðEÎλ`÷¡2Ä|~āΔí¹–4₂≠āó3Tv₁‰[Öò‚S»‰CþEηFA‡γ÷¯¿Þ₃âÖ.³εûV^ÕÜ₄Ú¹þ‘ΘVÅÍÅΘΛ9m|\Ó8g8ì&ÓiUΩÎQ:ÇºZÎgöæ•4в>£I#A‡

-18 bytes thanks to @Deadcode.
-2 bytes thanks to @Grimmy.
Uses the complete morse-string as first input, and the lookup format as second input.
Try it online. (Outputs as a list of characters, so the J in the footer is to join it together to a single string to pretty-print.)
Explanation:
•Nα0...göæ• # Push compressed integer 2178625864988239449532491166807818445418276694861550892023336765049187401437036816274840827319861935617150192366925629812414499033245212320687403711053517272798896860734190937884895522347710320033920004354990136205425279052925026955638024859428057287730519725429748232597858786841294379
   4в       # Converted to base-4 as list: [3,2,2,2,1,2,2,2,1,2,3,0,2,1,1,2,2,1,1,3,0,2,1,1,2,3,2,1,1,3,0,2,1,1,2,3,1,3,0,1,3,2,1,0,0,1,1,2,3,2,3,1,2,1,1,2,2,2,1,1,0,2,1,1,2,3,3,1,0,3,0,1,3,2,0,2,2,3,2,2,2,0,3,1,3,3,0,3,0,1,2,2,0,3,1,1,2,2,2,2,0,1,1,2,0,0,2,2,3,1,3,3,2,2,2,2,3,3,3,0,3,0,2,0,2,1,2,2,0,2,2,0,1,1,2,0,0,2,3,1,2,1,3,0,2,3,2,3,1,1,3,1,2,2,0,1,1,2,1,3,3,2,2,0,3,0,2,2,1,2,1,0,3,2,2,2,2,2,3,2,0,3,0,1,2,1,3,1,0,2,3,2,2,2,1,3,3,2,3,0,3,0,2,0,3,0,2,2,0,1,1,2,0,0,2,2,2,0,2,0,2,3,1,2,2,3,1,1,2,3,1,3,3,3,1,1,1,1,1,0,2,0,3,0,3,1,0,3,0,2,3,0,0,3,2,2,2,2,2,2,2,3,3,3,3,2,1,1,1,1,1,1,3,2,0,1,1,2,0,0,2,2,1,1,0,2,0,3,0,1,2,1,0,3,2,2,2,3,3,3,2,1,2,0,1,1,2,0,3,0,2,1,1,0,1,3,1,1,0,0,2,2,1,3,2,2,2,2,3,3,3,2,1,0,3,3,2,2,2,1,2,2,0,2,2,3,2,1,2,3,0,2,2,1,0,3,2,2,2,2,1,2,0,1,3,2,3,0,1,2,3,0,2,1,1,2,3,0,0,3,0,1,3,2,2,0,3,0,2,0,1,1,2,0,0,2,3,2,3,0,2,3,1,1,1,2,0,3,0,3,2,3,2,2,0,0,2,2,2,0,2,1,0,3,2,3,0,0,2,2,2,2,3,3,3,0,3,0,2,0,2,1,2,2,0,2,2,0,1,1,2,0,0,2,3,2,2,3,3,2,2,2,2,2,1,1,1,3,1,2,0,2,2,3]
     >      # Increase each value by 1
      £     # Split the first (implicit) input-string into parts of that size
       I#   # Push the second input-string spit by spaces
         A  # Push the lowercase alphabet: "abcdefghijklmnopqrstuvwxyz"
          ‡ # Transliterate all morse-strings in the list by the characters in the alphabet
            # (after which the resulting character-list is output implicitly)

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

Also, since I was curious what the program length would be if we wouldn't take any input and just use the 05AB1E dictionary to output the string, I created a program for that as well, which is 266 bytes:
’4ƒ€Þßer0–›r0prancer0vixen†„t0ï›id0¥Úner0bÙîØˆ€³€·4¾Î3‚¢£–2€‚€Ÿ13†¾5d2‚†a‚Òshiny5€ƒ€¬4ˆë–æ€•4€ÞƒÎ…è€•é»s€Ÿ€‚3€¶2‚›€„ÇÇ0„Ò„šŒî€»†™†³—‹1…¯€†€Æ2ƒ‚‚½€µÚƒgyŒÎ»ˆš´‹é€„…è1€Ž€ž5€Ê®Á¢²t4„²€¯slŸ¯o†æ‚½€ß32®œ„š€œ€»sh€Äed€Ä€Žgï³13†¾5d24ll‚œ„‹€†„ª’5Ý’€ƒ rudolph reinÆÓ €€ €î ÄÃ’#:

Try it online.
Explanation:
’4ƒ€Þßer0–›r0prancer0vixen†„t0ï›id0¥Úner0bÙîØˆ€³€·4¾Î3‚¢£–2€‚€Ÿ13†¾5d2‚†a‚Òshiny5€ƒ€¬4ˆë–æ€•4€ÞƒÎ…è€•é»s€Ÿ€‚3€¶2‚›€„ÇÇ0„Ò„šŒî€»†™†³—‹1…¯€†€Æ2ƒ‚‚½€µÚƒgyŒÎ»ˆš´‹é€„…è1€Ž€ž5€Ê®Á¢²t4„²€¯slŸ¯o†æ‚½€ß32®œ„š€œ€»sh€Äed€Ä€Žgï³13†¾5d24ll‚œ„‹€†„ª’
      # Push dictionary string "4knowdasher0dancer0prancer0vixencomet0cupid0donner0blitzenbutdo4recall3mostfamous2ofall13red5d2hadaveryshiny5andif4eversawit4wouldevensayitglowsallof3other2usedtolaugh0callhimnamestheyneverletpoor1joininany2gamesthenonefoggychristmasevesantacametosay1withyour5sobrightwont4guidemysleightonightthenhow32lovedhimastheyshoutedoutwithglee13red5d24llgodowninhistory"
 5Ý   # Push a list in the range [0,5]: [0,1,2,3,4,5]
   ’€ƒ rudolph reinÆÓ €€ €î ÄÃ’
      # Push dictionary string "and rudolph reindeer the you nose"
  #   # Split it on spaces: ["and","rudolph","reindeer","the","you","nose"]
   :  # Replace all [0,1,2,3,4,5] with ["and","rudolph","reindeer","the","you","nose"] in the string
      # (after which the result is output implicitly)

See the same 05AB1E tip as linked above (but section How to use the dictionary? this time), to understand how the dictionary strings work.

Why not store the list in base 4 instead of base 5, and add 1 to every element after unpacking it? Surely that wouldn't add 19 bytes to the code, as is wasted by the data by using base 5?

@Deadcode Thanks, that indeed saves quite a few bytes.

Awesome that it only took one byte to do the incrementation by 1! I honestly didn't know, but hoped it would be one byte.

@Deadcode Yeah, 05AB1E has single-byte builtins for +1, -1, +2, and -2. And it automatically vectorizes on the inner most values of (nested) list. :)

I think you need to add a ,3 to the end of your list. history is being truncated to histor.

Do you think it would be possible to implement an algorithm like this in 05AB1E, with Jelly's dictionary (in list form) passed to it like a library? This Morse code problem sparked my interest and I'm thinking of learning 05AB1E or Jelly to take a crack at doing it in fewer bytes than the split-by-letter-length method can do. Would it run in better than geological time in 05AB1E? I ask because I have a feeling it might naturally be implemented in a rather breadth-first fashion, which would take far more resources than the depth-first way.

@Deadcode Ah oops, thanks for noticing, fixed. As for your second comment, I'm not sure. I guess it would be possible to implement that algorithm in 05AB1E, but I'm not too good at C++ to modify it. Also, it seems to use Jelly's dictionary, but you could probably also access 05AB1E's library by using the Elixir compiler library, as apposed to the python3.7 it currently uses in that C++ program. As for your second question, I'm again not sure. The new 05AB1E's performance isn't too great to begin with. The legacy version which was written in Python was ok though.

Ah, I was expecting 05AB1E to be faster than Jelly because Python is quite slow in my experience... is Elixir even slower? In any case, Jelly's 248,298 word dictionary is the perfect choice because it maps this entire song without any words needing to be added, whereas as you found, 05AB1E's 10,000 word dictionary is missing words like "prancer", "vixen", shiny", "rudolph", and many more. Here is my algorithm ported to Java.

I think if you wanted to encode the message w/o input you could get ~166. Basically, split the morse code up into 7-bit blocks and prepend a 1. Then convert to base-255, and that's ~154 bytes.

@MagicOctopusUrn I'm not sure I follow tbh. How is the morse code as 7-bit blocks, with 1s prepended to each, and then converted to base-255, useful to get the intended output with lowercase letters? As explained in the challenge description, -..---.-... could be xmas, dole, teettteteee, etc. So without any input, how would the compressed morse code alone be helpful in getting the letters output? Also, how did you get that 154/166 bytes? I'm getting around 174 bytes, but I'm probably doing something wrong. Could you show me your code as clarification?

k followed by è is just ‡. 129 with •constant•4в>£I#A‡ and swapped inputs (TIO link too long for a comment).

@Grimmy Ah, I remember you gave me that tip before.. Thanks!

Charcoal, 145 141 bytes
≔⪪⮌θ¹θＦ”)“1§μX↶)⟧¶»-↘3ω◧i⌊⊞⁸Ｑ9m;T›|ＬDμ…›Ｏ⦄hTYＩO5x÷↶×‹,⟲"yＭLUＣgq.ＢNＥ2⁴⎇c⬤χＮ±⸿↙＆7⟧χ⁰‹Ｙs´ΣC⁼{9ω�Pi＆◧êKσＰDfY9wi⟲f[Φτ³Ｊ‹‴V[^ＷＲEαF[-T^ς”§β⌕⪪η ⭆⊕ι⊟θ

Try it online! Link is to verbose version of code. Edit: Saved 3 4 bytes by using a less inconvenient library format. (Thanks to @Deadcode for pointing out that I'd pasted in the wrong version.) Explanation:
≔⪪⮌θ¹θ

Reverse the sequence and split it into individual characters.
Ｆ...

Loop over the characters of a compressed string which are the digits 0..3 (which compress better than 1..4 for some reason).
§β⌕⪪η ⭆⊕ι⊟θ

For each digit, pop one more than that many characters from the sequence, concatenate them, look them up in the library split in spaces and output the desired character (using the predefined lowercase alphabet).
137 bytes with an even more convenient library format:
≔⪪⮌θ¹θＦ”)“1§μX↶)⟧¶»-↘3ω◧i⌊⊞⁸Ｑ9m;T›|ＬDμ…›Ｏ⦄hTYＩO5x÷↶×‹,⟲"yＭLUＣgq.ＢNＥ2⁴⎇c⬤χＮ±⸿↙＆7⟧χ⁰‹Ｙs´ΣC⁼{9ω�Pi＆◧êKσＰDfY9wi⟲f[Φτ³Ｊ‹‴V[^ＷＲEαF[-T^ς”§η⭆⊕ι⊟θ

Try it online! Link is to verbose version of code. Explanation:
≔⪪⮌θ¹θ

Reverse the sequence and split it into individual characters.
Ｆ...

Loop over the characters of a compressed string which are the digits 0..3 (which compress better than 1..4 for some reason).
§η⭆⊕ι⊟θ

For each digit, pop one more than that many characters from the sequence, concatenate them, look them up in the library and output the desired character.

Shame. I at least managed to golf a byte off the code to read the inconvenient output...

It appears the question has been relaxed to allow some other library formats. How much does that help you?

@A.Rex I originally thought it would only save me a byte but I managed to golf a couple of further bytes off.

There's a typo in your current 142 byte version. When fixed, it's actually 141 bytes: Try it online!

@Deadcode Bah, I remember fixing that, I don't know how I managed to paste in the wrong version...

Perl 5, 283 244 bytes
$s=<>;$s=~s/..{$_}//+print$s=~/(.) \Q$& / for map{vec unpack('u',q{MJZDYEM98;HWE31N4>Y9:6'Y,BZYRSZ1<JI2@]ZH_(Z8H)7@V[G5*V2NC&:NZM3':XVCLCHY2@(IY>WE\5,L<XK*K^6U5+"5K(9*S^)B5CT07:JK_Q:HINCL:J=23LYEL.T,E*".U[)[`HJQ@ZJ/R.F*"6XOJK5B0X`}),$_,2}0..473

Try it online!
This corresponds to:
$L = <<'';                            # length bits in base64
MJZDYEM98;HWE31N4>Y9:6'Y,BZYRSZ1<JI2@]ZH_(Z8H)7@V[G5*V2NC&:NZM3':XVCLCHY2@(IY>WE\5,L<XK*K^6U5+"5K(9*S^)B5CT07:JK_Q:HINCL:J=23LYEL.T,E*".U[)[`HJQ@ZJ/R.F*"6XOJK5B0X`

$s = <>;                              # read inputs
$s =~ s/..{$_}//                      # take current length morse code from start
  + print $s=~/(.) \Q$& /             # ...and print corresponding letter
  for map vec(unpack('u',$L), $_, 2), # find morse code lengths of the letters
      0..473                          # 474 letters

This could perhaps be further shortened by encoding in base128 or directly in "base256". Huffman encoding the lengths could shorten the length data, but most probably enlarge the rest of the code by too much.

MATLAB R2016a, 290 285 277 266 245 223 219 bytes (99+119+1)
function r(m,d);[a,b]=ismember(mat2cell(m,1,fread(fopen('j'),474,'bit2')+3),strsplit(d));char(b+96)

The inputs are the Morse code sequence m and the dictionary d in the third format. The function uses a 119-byte file j available here that contains the lengths of the 474 Morse codewords. According to the rules of scoring multiple files, this adds an additional byte to the score.

Pyth + Jelly's dictionary, 135 134 131 130 129 (126) bytesSBCS
The algorithm and data in this answer were originally implemented in this APL answer, and their explanation is there. But as implemented there, it failed in its entire purpose, which was to beat the previously lowest-scoring submission to this challenge, Kevin Cruijssen's 129 byte 05AB1E answer. Here, it finally succeeds in its very purpose for existing, and just barely manages to beat that answer's length. I learned Pyth to do this; it was a promising choice with very good documentation. It's unclear if any of the other golfing languages would be able to implement an imperative algorithm like this in fewer bytes.
With a longer Morse code message this algorithm would win by a significantly larger margin.
Kcwd=bmsm@KxGkdTVjC"êêVÞøA?cUqg´§¼F¦e~zEºÊú[!Áw¶uQå´çý½Ê*¤jrkIæwÐó*S.(4áëÌöÅ×¹ñp.ÑQÐgBê "51=>zl@bJ@sxRb_._<z24Np@TJ

(contains C1 control characters, forbidden by HTML5, thus the above can't be copied to clipboard and is for illustration purposes only)
Try it online! - 129 byte version, running at decent speed
Kcwd=bmsm@KxGkdTVjC"êêVÞøA?cUqg´§¼F¦e~zEºÊúvMÇìý÷¼]¾I/||ÊÁê,Ømø×i]Z8©b¤0åé'½bIý>ä
lGùUK½"51=>zl@bJ@sxRb_._zNp@TJ

(contains C1 control characters, forbidden by HTML5, thus the above can't be copied to clipboard and is for illustration purposes only)
Try it online! - 126 byte  version, taking about 20 times as long to finish (especially slow at beginning)
Explanation of the code
Header
 $exec('

Anything in $...$ is evaled as Python code. Open an exec block here (since statements can't be executed in eval). The leading space suppresses imp_print.
def Pprint(a): print(a, end="", flush=True); return a

On my system, this program takes 46.4 (or 921) seconds to finish, but on TIO, it is on the very edge between not finishing in 60 seconds or just barely finishing. If it didn't manage to finish, no output would be shown. If it was manually interrupted before finishing, the incomplete output would be shown – so it appears TIO sends a SIGINT (Ctrl+C) to the process for this, but something more powerful (perhaps even SIGKILL) when reaching the 60 second limit.
By default, Python only flushes its standard output on newlines. The -u command line argument forces stdout (and stderr) to be unbuffered, but TIO does not provide a way to send arguments to the host Python process that spawns Pyth.
This header line redefines Pyth's Pprint() macro to flush its output, so that if the program does not finish within 60 seconds, the incomplete output will still be shown. It's the next best thing to -u.
Funnily enough, forcing each individual print to flush seems to actually make it run faster on TIO; it was able to finish in under 58 seconds with this, whereas in my tests on TIO the 134 byte version never finished without this.
_imp_print = imp_print;
def imp_print(a): globals()["imp_print"] = globals()["_imp_print "]; return a

Work around the newline inserted by TIO between the Header and Code sections, which would trigger an imp_print() on the first expression otherwise. Suppress only the very first imp_print that happens next, and then allow all subsequent ones.
')$

End the exec block.
=TrL0$exec('from jelly import dictionary') or dictionary.short + dictionary.long$

Import Jelly's dictionary and assign the concatenation of its short and long dictionaries, changed to all-lowercase, to the Pyth variable T. Equivalent to:
from jelly import dictionary
T = list(map(lambda arg:arg.lower(), dictionary.short + dictionary.long))
Code
Kcwd

The Morse code version of the song has already been read from input implicitly, as z = input().
Read the Morse code look-up table from input. Equivalent to K = input().split(' ').
=bmsm@KxGkdT

Translate Jelly's dictionary into Morse code, with the inter-letter gaps deleted. Equivalent to:
b = list(map(lambda d:''.join(map(lambda k:K[string.ascii_lowercase.index(k)], d)), T))
(The outer lambda uses d as its argument, whereas the inner lambda automatically advances to using k as its argument.)
jC"êêVÞøA?cUqg´§¼F¦e~zEºÊú[!Áw¶uQå´çý½Ê*¤jrkIæwÐó*S.(4áëÌöÅ×¹ñp.ÑQÐgBê "51
jC"êêVÞøA?cUqg´§¼F¦e~zEºÊúvMÇìý÷¼]¾I/||ÊÁê,Ømø×i]Z8©b¤0åé'½bIý>ä␊lGùUK½"51
(contains C1 control characters, forbidden by HTML5, thus the above can't be copied to clipboard and is for illustration purposes only)
Unpack the word choice array (115 elements), packed in base 51 in an 82 byte base 256 encoded string. Luckily there happened to be no characters that needed escaping.
C"..." - convert the base 256 encoded string into an arbitrary-precision integer
j...51 - convert the base 51 integer into a list of integers

V...=>zl@bJ@sxRb_._<z24Np@TJ
V...=>zl@bJ@sxRb_._zNp@TJ
Main loop.
V... - for N in ...: - for each element N of the list decoded above, execute all of the following statements:
_._<z24 - reverse(list(map(lambda arg1:z[:arg1], range(1, 24+1)))) - make a list of Morse subsequences starting at the beginning of input (z), ranging from 24 to 0 dots/dashes long (from longest to shortest)
_._z  - reverse(list(map(lambda arg1:z[:arg1], range(1, len(z))))) - make a list of Morse subsequences starting at the beginning of input (z), ranging from maximum length to 0 dots/dashes long (from longest to shortest)
J@sxRb...N - J = sum(map(lambda arg2:index(arg2,b), ...), [])[N], where index(arg2,b) finds all occurrences of arg2 in b - enumerate all words that match the Morse code at the current position in the input, up to 24 dots+dashes, and store this list of dictionary indices (which apply to both b and T) in J
=>zl@bJ - z = z[len(b[J]):] - remove the processed Morse code from the beginning of the input
p@TJ - print(T[J]) - look up this word in the dictionary and print it

JavaScript (Node.js),  270  269 bytes
Takes input as (string)(lookup), where lookup is in the 3rd format.
s=>t=>(B=Buffer)("SNB6>B5>V]@a5U)McAQ>@a/;3bRD7;2?R:1P_Sb7K@22MHO5V?O:AWZPATRV4A/VBW[0K:1PJ`Q?Fg=-ZD46TRRgC=]:1P-ZLYRgN<Z@9?H^RfCdRQPC6BTR1U;6>64UZ0MHc`=ZTSH2.cHRg4JQP<*VfRB]1b").map(n=>[0,2,4].map(i=>o+=B([97+t.split` `.indexOf(s.slice(p++,p+=n-40>>i&3))])),o=p='')&&o

Try it online!
How?
For each character in the data string, we take the ASCII code minus \$40\$ to get a 6-bit value holding the lengths of the next 3 morse codes.
Example:
"S" --> ASCII code 83 --> 43 --> 101011 --> 10 10 11
                                             |  |  |
                                             |  |  +--> 3+1 = 4 -> -.-- (y)
                                             |  +-----> 2+1 = 3 -> ---  (o)
                                             +--------> 2+1 = 3 -> ..-  (u)

Python 3, 452 bytes
lambda a,b:''.join([chr(96+int(''.join([f'{ord(c):07b}'for c in'''ezVswP,A8BpeH	A82dDY
po4ZqVHDw,A8AMa+!ezd(a1J+/NCkuN"Rq'LJRdQd)>2I)8BK3!2ssIY>Rl,StiKu]zX!6iCJ4Go,1s(A/Qe)8BK3J`5\0\ a1DkA4YhA98[R_Uv BO%d\YHT\!%HpZ,t Wq&<sr&:eXYBuK#s*#lAS">Y|eMq$IhRw]&/TzR!-f6
IhQw:Q\CwQd*.RdcvDh3QsVBH}4];*H{"D$9yJ$E%b
,Y>V;d>wr	N'''])[i:i+5],2))for i in range(0,2346,5)])+'tory'

Try it online!
Same morse-ignoring, hardcoding approach as ScoopGracie's answer, but with each character's 5 LSB concatenated and re-encoded in printable ASCII (i.e. 7 free bits out of each byte).
This shortens the string from 474 to 339 bytes, not counting delimiters (which need to be multiline for the encoded string) and an escape sequence in place of a NUL byte. I also cut the string off at the last clean byte boundary (to not deal with partial bytes) so I had to hardcode the final four characters.
Then there's not-insignificant overhead for the decoding process, so it's not much shorter this way. Improvement suggestions welcome!
Using the standard library instead to compress the lyrics with base64.b64encode(gzip.compress(...)) actually saves 2 bytes:
Python 3, 450 bytes
lambda a,b:decompress(b64decode('H4sIAAaPGF4C/3WQ0XbsIAhFv5UJRG2VkyU41n79xdzJY19cBE62WxbGt2IyWZZOykx63MXVn+pdfkQPNPH4OMZVeOegek9ftfiv6Gs4Y2F0OahWz9JgflLDsC5FWaTjjEkfjHrlCHRhhQk/40xMb+nLctG1JwEvZyAlukazeNQTo3I01GgVTxXTAoozeNjMBzYC7Kg0Ut7SkcmlKTWxSC3dyCp+Af0j9IWiRUnXQ0ifsELlRErryL2YN7L42Uidjkg4QuSDCMO8N7DdDa9eUvYJ3dppFJa2rMpuQve52Rnz3sT/KyvewuFJt6RlDBeOY4NT3a/6a3dxRa0JjBmPyKGJvv4BRj4fyNoBAAA=')).decode('ascii')
from gzip import*
from base64 import*

Try it online!

Python 3, 265 261 259 255 bytes
Uses the same base-256-in-a-string data-encoding method as my other Python answer, but actually uses the Morse code input. Like many of the other answers, encodes the lengths of the 474 Morse codewords into 119 bytes using base 4. The Morse stage of the decoding is based on steviestickman's answer, with some further golfing.
Takes the Morse library and representation as two lines from stdin and outputs to stdout:
#coding=L1
i=int.from_bytes('Õª¾¸%(¦#?ªÆ*\nìÉ^;R2´Ã9;IªÆnjñ¿ªÚÑc%&þ¬dÈZ    KU[þª¬8Ç2_Þ^" £#;Ú¸vLº«£+ÙJuî6x%(¦#?ª÷ ª\¤Ïr®L~XZ{MånXÖ9©«'.encode('L1'),'big')
*m,I=input().split()
while i:j=i%4+1;print(end=chr(97+m.index(I[:j])));I=I[j:];i//=4

(contains C1 control characters, forbidden by HTML5, thus the above can't be copied to clipboard and is for illustration purposes only)
Try it online! (can't use the actual Latin-1 coding header, since TIO only accepts UTF-8)
Try it on repl.it (demonstrates the actual 255 byte source code file)
-4 bytes by using the alias 437 for cp437
-2 bytes by using L1 instead of 437
-4 bytes by separating the Morse code library and representation in the input with a space instead of a newline
Here's a Python program (TIO) to generate the full program with choice of string encoding.

Pyth, 142 bytesSBCS
Like many of the other answers, and my Python answer, encodes the lengths of the 474 Morse codewords into 119 bytes using base 4. Shares many similarities with my Pyth + Jelly's dictionary answer.
My primary reason for posting this answer is to show that in Pyth, apparently the 474-codeword-lengths method does not beat the 115-Jelly-dictionary-word-indices method!
Takes the Morse representation and library as two lines from stdin and outputs to stdout:
Kcwdsm@GxK<~>zddhMjC"¦¦Éir[%·AnÙjR[Ó+¨ß1£Z¡`ú¯Ì¢ÙËµÚ~¦NªãÒê~Ì¡`¨k[UHÍ2Ãª«þU^
R1«ùu
z¯äú+):¦ÆÉl1èÈX.ËV3º
;
¯Ì¢ëê¥v+"4

(contains C1 control characters, forbidden by HTML5, thus the above can't be copied to clipboard and is for illustration purposes only)
Try it online!
Explanation of the code
Kcwd

The Morse code version of the song has already been read from input implicitly, as z = input().
Read the Morse code look-up table from input. Equivalent to K = input().split(' ').
hMjC"¦¦Éir[%·AnÙjR[Ó+¨ß1£Z¡`ú¯Ì¢ÙËµÚ~¦NªãÒê~Ì¡`¨k[UHÍ2Ãª«þU^
R1«ùu
z¯äú+):¦ÆÉl1èÈX.ËV3º
;
¯Ì¢ëê¥v+"4

Unpack the array that stores the Morse code width (in dots+dashes) of each letter of the song (474 elements), packed in base 4 (with 1 subtracted from each element) in an 119 byte base 256 encoded string. Luckily there happened to be no characters that needed escaping.
C"..." - convert the base 256 encoded string into an arbitrary-precision integer
j...4 - convert the base 4 integer into a list of integers
hM - add 1 to all elements
sm@GxK<~>zdd

m - map each element d of the list decoded above through the following lambda:
~>zd - z = z[d:] - remove the first d dots+dashes from the input (z), and return the previous value of z (let's call it ʐ)
@GxK<ʐd - string.ascii_lowercase[K.index(ʐ[:d])] - alphabetical letter decoded from the first d dots+dashes from the input
s - join the resulting list of characters into a string

Vyxal s, 131 bytes
»ʀAλT‛⊍½⇧ṗ.‹ẇṡN↳ḢZµẊ₃r#≤*₂⇩vǐ†⁰₈{≬√¬Ṗ}↑żPǍĊṁ⟑ZUżǓ∧∞:Yβv₴ǒ›ƈĖβ•„†G€
→C≬⁋İꜝ[≠₴m∑E¼ y±⋎\↲Ċ„ġQ Ṙ₍ṘQ∵«1}w⌊×+×⇩e⌊-¨T⁰ɽoṪḊ$⁰+‡∪»4τ›⟑;ẇ⁰⌈yĿ

Try it Online!
Port of 05AB1E.
-1 byte thanks to Deadcode

You beat me to it... but you got an answer 2 bytes less than mine anyway. Mine - 134 bytes - I found it VERY hard to figure out how to use lambdas or for loops to do this. I think they're documented very poorly. And even your 132 comes far short of 05AB1E... I am disappointed.

131 bytes - but I don't understand the parts of your code that differ from mine. Can you explain please? Mainly what is ⟑; doing? It's a lambda that's closed immediately – an empty lambda? It should have no effect. I don't understand.

It just seems like really poor design in the language if a two-byte identity lambda is needed just to not apply any transformation to the chunks.

Okay, so it looks like 129 bytes should work in theory but it fails due to RecursionError: maximum recursion depth exceeded. That definitely seems like bad language design, needing to add 2 bytes just to make it actually work when it should already work in theory.

⟑; is just a bug-fix to convert a LazyList to a list. I need to report the bug, but I forgot. You're right that it should have no effect. Also, it's an apply lambda (aka non-lazy mapping lambda), not a lambda. It's not bad language design, just a bug.

I'm glad to hear it's just a bug, and look forward to the fix! :-)

Python 3, 381 375 372 bytes
Just like Seb's answer and ScoopGracie's answer, gracefully takes the Morse code representation and any of the three libraries as input, blithely ignores them and gives you the output.
Takes Seb's strategy a step further, encoding the text in base 26 in an integer encoded in base 256 in a string (as opposed to Seb's which encodes in base 32 in base 128 in a string). Both of our solutions are confined by not being able to contain the bytes NUL (0x00) or CR (0x0D), which Python interprets as end-of-file and LF (0x0A), respectively, even when found in a triple-quoted raw string literal. CR+LF is also interpreted as LF. Backslash escape codes are interpreted (unless the raw prefix r is used). Backslash followed by any kind of newline is treated as nothing, stripping both the backslash and the newline. And the string can't end in a backslash. (So it's really sort of a slightly-less-than-base-254 masquerading with the help of luck as base 256.)
To work around this problem I had to complicate the encoding a bit. Neither ASCII-97 nor 122-ASCII, nor using base 27 instead of 26 (and optionally adding 1), avoided containing these bytes or sequences, so I settled upon adding 1 to the encoded integer before each multiplication by 26, which luckily costs only 3 bytes (compare i//=26 to i=i//26-1). With significantly larger text, the luck would have to be incredible, or every NUL, CR, and \ would have to be replaced with \0, \r, and \\ respectively. On the other hand, with better luck, newlines might be absent altogether, meaning single-quoting could be used instead of double-quoting.
The #coding=L1 costs 11 bytes (without this it'd be 361 bytes), but this beats the cost of using base 128 (which would take 319 bytes for the string, whereas base 256 takes 279 bytes, and thus would cost 40 bytes instead of 11, not counting the different Python code that would be needed to decode it). An alternative coding is 437, which would cost a further 2 bytes, since the encoding name is used twice. Note that the disadvantage of using L1 instead of 437 is that ISO 8859-1 doesn't map as cleanly to UTF-8, and there may be difficulty faithfully copying and/or pasting it in some software.
This standalone program, written in the ISO 8859-1 codepage, ignores the Morse code representation and library taken as command-line parameters, and prints the output to stdout:
#coding=L1
i=int.from_bytes(' îã¸ÌÒ^ë9|iéëMþ³\H0Äï;ÿÒ¸FÈªÎ©«|°M®QcWtgUî[¡U*¤ßºN¨øA¡:¾ç¢Àãþú/æòêåá\IÕi#vv³Ü¡\'jîÐtÄí6.ñÎé¤¥Yî³d}fLLEXµ*îB§ ç^eleW?Ð|¶S¯±[Iûçä2ý¥ð°,üTÃ·0èÅEÛçå\LW&uMeÑ@ûÍÿ`Ñ3CÒæ%2¿¬ÌïÆçGÌîXë[MDØmI¥íâÃ½9t±¤]#ÏYî8M·Ckò¡"J'.encode('L1'),'big')
while i:print(end=chr(i%26+97));i=i//26-1

(contains C1 control characters, forbidden by HTML5, thus the above can't be copied to clipboard and is for illustration purposes only)
Try it online! (can't use the actual coding header, since TIO only accepts UTF-8)
Try it on repl.it (demonstrates the actual 372 byte source code file)
-6 bytes by using L1 instead of cp437
-3 bytes by using i=i//26-1 instead of i=i//26^4, resulting in no newlines, allowing single-quoting
Here's a Python program (TIO) to generate the full program with choice of string encoding.

If it absolutely has to be a function and not a program, then it's 382 bytes (not counting the #coding=L1):
def R(a,b):
    s='';i=int.from_bytes('…'.encode('L1'),'big')
    while i:s+=chr(i%26+97);i=i//26-1
    return s

Try it online!
If it has to be a lambda, 391 bytes (not counting the #coding=L1):
lambda a,b,i=int.from_bytes('…'.encode('L1'),'big'):exec("global s;s=''\nwhile i:s+=chr(i%26+97);i=i//26-1")or s - Try it online!
If it has to be a lambda that doesn't modify any globals, 395 bytes (not counting the #coding=L1):
lambda a,b,l={'i':int.from_bytes('…'.encode('L1'),'big')}:exec("s=''\nwhile i:s+=chr(i%26+97);i=i//26-1",l)or l['s'] - Try it online!

Deadfish~, 2496 bytes
{{i}}{ii}ic{d}ciiiiiic{d}ciiicic{i}ddc{dd}icdddc{ii}ddc{d}dcdddc{i}iiic{dd}iiic{i}iiic{d}ccdddc{i}iiic{d}dciic{i}iiic{dd}iiic{i}iiic{d}c{i}iiciic{dd}iiic{i}iiic{d}dciic{i}iiic{dd}iiic{i}iiic{d}c{ii}ddc{d}dddc{i}iiiiic{dd}ic{i}dc{d}dc{i}iicddc{d}iic{i}iiiiic{dd}ic{i}iiic{d}cdc{ii}ddcdddddc{d}iiicdddddcdddc{i}iiic{d}cc{i}icdcc{d}ic{i}iiic{dd}iiic{i}iiic{d}cddc{i}cdddc{i}iciiiiiic{dd}dc{i}dc{d}ddc{ii}dcdc{d}ddddddc{i}ic{i}c{d}ciiiiiicdddc{d}dddcddcddc{i}icc{i}ddc{d}ddcdddc{i}ddciiciiiicic{d}ddddcdddddc{i}iiciiciiiiiicddcdc{d}dddciiiiciiiiic{d}cicc{i}iiicdddc{d}icdddddc{i}icciiiiiiciiic{dd}iiic{i}icdddciiiic{d}iic{i}iic{d}ddcdddc{i}iiic{d}dddcdc{i}ciciiiic{d}ddddcdc{i}iiiic{d}dddciiiiciiiiic{d}cicc{i}iiic{d}c{d}iiiciiicdddc{ii}ic{dd}iiic{i}iiic{i}dddcddddddc{d}dciciiiiic{i}ic{d}dciciiiic{d}ddddcddddc{i}iiic{d}ciiiiicdddc{ii}dc{d}ciiiiiic{d}ddddddc{ii}dddc{dd}iiic{i}iiicic{dd}iic{ii}iic{d}ddddc{i}iciiiiic{d}ciiiiiiciic{d}iiciiiiiic{d}ic{d}iicic{ii}dddc{dd}iiic{i}dciiiiic{dd}iic{ii}iiiic{d}ddddddc{i}ic{d}dddciiiiiciiic{i}ddcddddc{dd}iic{i}icciiic{d}ic{i}iiiic{d}ddcdddc{i}ciiiiic{d}ddcdddc{i}iiicc{d}dddciiiiciiiiic{d}cicc{i}iiiciiicddc{d}ddddcdc{i}iiiiiicdddddcdddc{d}dc{ii}c{d}ddddcic{d}iiic{i}iiic{d}cdcddc{i}iccddddciciiiicic{d}dddc{i}iic{d}iic{i}iiiicic{d}ddcdddc{ii}c{d}dc{d}ic{ii}dddc{dd}iiic{i}iiicddddddc{d}iiic{i}iiiiicddddcdcciiicciiic{dd}iiic{i}icdddciiiic{d}iiciiciiiiicddddddciiiiicdddddciiiiic{d}dddc{i}iiic{i}ic{d}iiic{d}dddciiiiciiiiic{d}cicc{i}iiic{d}dcddddddc{i}iic{d}iic{i}iiiicic{d}ddcdddc{i}dcicdc{d}icic{i}dc{d}iicc{ii}ddc{dd}ddciiiiic{i}c{d}ic{i}cic{d}iiic{d}ddc{ii}ddc{d}ddddc{ii}dddc{dd}iiic{i}iiiic{dd}iic{i}iiiciiiiiic{dd}iciicddc{i}iic{d}iic{i}iiiiicdddddciiiic{dd}iic{ii}iiiic{d}iiiciiic{dd}iiic{i}icdddciiiic{d}iic{i}iiiiic{d}ddddc{i}ic{d}ddc{ii}dddc{d}ciiiiiicdddcddddciciiiic{d}ddddc{i}iiiicddddc{d}dddc{i}iiiiiic{d}icddcic{i}iiciiic{d}iicdciiiiiiciiiiic{d}ciiiiiic{d}ddddc{i}iiiic{d}ddcdddddcic{i}ddc{i}iicddddddc{d}iiic{d}iiiciiiicddcic{i}iicdddddcdcdddddcddcic{i}iicc{d}ddcdddc{i}dcddddddc{i}dddc{i}ddcdddc{d}ddcdddc{i}iiic{d}dddciiiiciiiiic{d}cicc{i}iiicddddddciiic{i}dddc{dd}iiicdciiiiciciiiic{d}ddc{ii}ddcic{d}ddcdddc{ii}cddddddc{d}dc{i}dddciiiiiicdc{d}dddddcdc{i}iciiiiiicdciiic{d}ddddc{i}ic{d}ddcdciiiiic{d}iiicc{i}iiiciiic{dd}iiic{i}icdddciiiic{d}iic{i}iic{d}ddcdddc{i}iiic{d}dddcdc{i}ciciiiic{d}ddddcdc{i}iiiic{d}dddciiiiciiiiic{d}cicc{i}iiic{i}dddc{d}ciiiiiic{d}iccdddddc{i}ddc{d}dc{i}ic{i}ddc{d}icdddddciiiiicddddddcic{i}cicdddddciiic{i}dddc

Uses an alternative interpreter. But in the ordinary one, you can give it input. It's not going to do anything though.
Try it online!