My previous answer worked, but did not work very well. For example, if you change aboveglbskip and aboveglcskip values then all the hardcoded calculations would need to be tweaked very carefully. There were a lot of details which may help someone in the future, which is why I'm posting the new answer instead of editing the old one.
Improved Answer
I patched two commands within expex to allow a vbox to overlap the interlinear gloss lines. There is a difference in behavior between a single gloss line (i.e. only \gla) and using multiple gloss lines (e.g. \gla and \glb, or \gla and \glb and \glc).
CAVEAT: This does not work for nlevel glosses.
Comments are included for most lines. So, see MWE for comments on the explanation for why/what is happening.
\documentclass[a4paper,12pt,final]{memoir}
\usepackage{xpatch}
%%%%%%%%%%%%%%%%
% (begin) ExPex update to allow arrows
%%%%%%%%%%%%%%%%
\makeatletter
\@ifclassloaded{memoir}{\let\tt\texttt}{}%This is required, because expex uses \tt, which memoir does not allow
\makeatother
% Include ExPex for having sentences with glossing and translation
\usepackage{expex}
\makeatletter
% Create an additional \gl@maxhtlast (to complement existing \gl@maxdplast)
%% --inside \glw@updatelists
\newdimen\gl@maxhtlast
\xpatchcmd{\glw@updatelists}
{\global\gl@maxdplast=\glw@maxdp}
{\global\gl@maxhtlast=\glw@maxht
\global\gl@maxdplast=\glw@maxdp}
{}{}%
% Add a new box to overlay arrows (or whatever) to the left side of the top interlinear gloss line
%% --inside \glw@printilg@a
\xpatchcmd{\glw@printilg@a}
{\glw@printilg@b \par }
{\glw@printilg@b \par %
% DO NOTHING, IF NO GLARROW WAS SPECIFIED BY USER
\ifx\ling@glarrow\empty%
%do nothing
% OTHERWISE, USER DID SPECIFY A GLARROW
\else%
% Create new dimension for above skips (e.g. aboveglaskip, aboveglbskip, aboveglcskip etc.)
\newdimen\dim@aboveskip%
% Give a default value of 0pt
\global\dim@aboveskip=0pt%
% Create a new counter for the number if interlinear gloss lines
\newcount\numglwlines%
% Give a default value of 0
\global\numglwlines=0%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Loop through one GLWORD
%%% Calculate the abovegl<N>skip total (into \dim@aboveskip)
%%% and Count number of gloss lines (into \numglwlines)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% DON'T MODIFY EXISTING TOKENS, LISTS, OR OPERATORS (TO BE SAFE)
% INSTEAD, USE A TEMPORARY VERSION WITH THE SAME VALUE
\let\temp@currentitem\@currentitem%
\let\countlineslist\mainlist%
\let\gl@lop@temp\gl@lop%
% Get the first GLWORD from token list
% and use it to to count the interlinear gloss lines
\gl@lop@temp\countlineslist\to\temp@currentitem\relax%
% If the item is \empty, ignore. Otherwise, count the lines
\ifx\temp@currentitem\empty%
\else%
% DON'T MODIFY EXISTING TOKENS, LISTS, OR OPERATORS (TO BE SAFE)
% INSTEAD, USE A TEMPORARY VERSION WITH THE SAME VALUE
\let\temp@aboveskip\@aboveskip%
\let\tempaboveskiplist\aboveskiplist%
\let\gltoks@next@temp\gltoks@next%
\let\gl@lopTL@temp\gl@lopTL%
% GLWORD is not \empty, therefore it contains at least one line
% Add one to \numglwlines counter
\global\advance\numglwlines by 1%
% Set value to TRUE to loop through GLWORD lines
\gl@loopmoretrue%
\loop\ifgl@loopmore%
% Get the `aboveskip' value for current gloss line
\gl@lop\tempaboveskiplist\to\temp@aboveskip%
% If value is 0pt, do nothing
\ifdim\temp@aboveskip=0pt%
%do nothing
% Otherwise, above skip value is set to something
\else%
% Store current \dim@aboveskip value into temporary value
\let\dim@aboveskip@temp\dim@aboveskip%
% Add current `above skip' value to existing sum of `above skip' values
\global\dim@aboveskip=\dimexpr\dim@aboveskip@temp+\temp@aboveskip\relax%
\fi%
% Get the next token (i.e. line) of the GLWORD
\gl@lopTL\temp@currentitem\to\gltoks@next@temp%
% If token (line) is \empty, we are finished looping
\ifx\temp@currentitem\empty%
\gl@loopmorefalse%
% Otherwise, increment the number of lines, and continue looping
\else
\global\advance\numglwlines by 1%
\fi%
\repeat%
% Set to FALSE as a precaution
\gl@loopmorefalse%
% Free up memory of temporary items
\let\temp@aboveskip\relax%
\let\tempaboveskiplist\relax%
\let\gltoks@next@temp\relax%
\let\gl@lopTL@temp\relax%
\fi%
% Free up memory of temporary items
\let\temp@currentitem\relax%
\let\countlineslist\relax%
\let\gl@lop@temp\relax%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Countdown of wrapped lines in the interlinear glosses `paragraph' to zero
%% used for looping until we reach the final line
\newcount\ep@countdown@ilg@para@lines%
\ep@countdown@ilg@para@lines=\prevgraf%
% Number of wrapped lines in the interlinear glosses `paragraph'
\newcount\ep@num@ilg@para@lines%
\ep@num@ilg@para@lines=\prevgraf%
% Count the number of lines processed so far
\newcount\ep@num@lines%
\ep@num@lines=0%
% Create a \vbox to overlay on top of the interlinear glosses
\setbox0\vbox
{%
\ifnum\numglwlines=1%only gla exists
%do nothing
\else%
% If at least 2 paragraph lines, the initialize the vertical skip
%% (note: the first line does not contain an arrow, so only other lines are `processed')
\ifnum\ep@num@ilg@para@lines>1%
%Shift upwards, the amount of space between each interlinear line
%e.g. between \gla and \glb, between \glb and \glc, etc.
%these spaces are defined by variables: aboveglbskip, aboveglcskip, aboveglftskip, etc.
\vskip -\dimexpr\dim@aboveskip*(\ep@num@ilg@para@lines-1)\relax%
%Shift upwards, the amount of \gl@maxhtlast (height, not depth, of each glword)
\vskip -\dimexpr\gl@maxhtlast*\numglwlines*(\ep@num@ilg@para@lines-1)\relax%
%Shift upwards, the amount of \gl@maxdplast (depth, not height, of each glword)
\vskip -\dimexpr\gl@maxdplast*\numglwlines*(\ep@num@ilg@para@lines-1)\relax%
%Shift upwards, the amount of \lingextraglskip (interlinear skips)
\vskip -\dimexpr\lingextraglskip*(\ep@num@ilg@para@lines-2)\relax%
\fi%
\fi%
% For some reason, the paragraph glue values
% need be used in \vskip
% IS THIS ALWAYS TRUE?? ONLY SOMETIMES??
\vskip -\the\gluestretch\parskip%
\vskip -\the\glueshrink\parskip%
%Loop through the paragraph lines
\loop%
\ifnum\ep@countdown@ilg@para@lines=\ep@num@ilg@para@lines%
%do nothing
\else%
\ling@everygla%
\newdimen\ep@dim@arrow@indent%
\ep@dim@arrow@indent=0pt%
% If hangstyle is `normal' then use a consistent horizontal offset
\ifnum\ep@glhangstyle=1%
% Use the standard hanging indent
\ep@dim@arrow@indent=\dimexpr\ling@glhangindent\relax%
\fi%
% If hangstyle is `cascade' then use a cascading horizontal offset
\ifnum\ep@glhangstyle=2%
% Set offset to the hanging indent amount multiplied by the current line number
\ep@dim@arrow@indent=\dimexpr(\ling@glhangindent*\ep@num@lines)\relax%
\fi%
% Create \hbox to contain the arrow and indent offset
\hbox{%
% Create horizontal indentation
\hspace*{\ep@dim@arrow@indent}%
% Create the arrow
\raisebox{-\ling@aboveglarrowskip}[\height][0pt]{\llap{\ling@glarrow}}%
% Use a \vrule to make sure the line height is consistent
\vrule height\dimexpr\gl@maxhtlast\relax depth\dimexpr\gl@maxdplast\relax width 0pt%
}%
% Add `above skips' for one horizontal line of GLWORDS
\vskip \dim@aboveskip%
% Add remaining heights for one horizontal line of GLWORDS
\vskip \dimexpr(\gl@maxdplast)*\numexpr\numglwlines-1\relax\relax%
% Add remaining depths for one horizontal line of GLWORDS
\vskip \dimexpr(\gl@maxhtlast)*\numexpr\numglwlines-1\relax\relax%
% Add extraglskip vertical skip, if necessary
\ifnum\numglwlines=1%only gla exists, no \lingextraglskip is used in this case
%do nothing
\else%
% If there are 3 or more wrapped lines, then also add
% vertical skip defined by extraglskip (\lingextraglskip)
\ifnum\ep@countdown@ilg@para@lines>1%
\vskip \lingextraglskip%
\fi%
\fi%
\fi%
% Line countdown to zero (by increments of 1)
\advance\ep@countdown@ilg@para@lines -1%
% Processed line counter (by increments of 1)
\advance\ep@num@lines 1%
% If countdown has not reached zero yet, keep looping
\ifnum\ep@countdown@ilg@para@lines>0%
\repeat%
}%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Display the vbox content
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% If only one line, GLWORDS function similar to a regular paragraph
%% therefore, use a \raisebox to overlap the arrows
\ifnum\numglwlines=1
\raisebox{\dimexpr(\gl@maxhtlast+\gl@maxdplast)*(\ep@num@ilg@para@lines-1)\relax}[\height][0pt]{\box0}%
% Otherwise, display the box normally (because overlapping is already possible)
\else%
\box0%
\fi%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\fi%
}
{}{}%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% DEFINE TWO NEW KEYS FOR USE WITHIN \lingset{}
%%% glarrow -> an arrow symbol (but could be any symbol or text)
%%% aboveglarrowskip -> vertical space above the arrow (similar to aboveglbskip and aboveglcskip)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\define@lingkey{glarrow}{\def\ling@glarrow{#1}}%
\lingset{glarrow=}%
\define@lingkey{aboveglarrowskip}{\def\ling@aboveglarrowskip{#1}}%
\lingset{aboveglarrowskip=0pt}%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\makeatother
\lingset{numoffset=\leftmargin,%
textoffset=0.75em,%
extraglskip=!1.1ex,%
glspace=!0.01em,%
belowglpreambleskip=!0ex,%
aboveglbskip=-0.9ex,%
aboveglcskip=-0.9ex,%
aboveglftskip=-0.1ex,%
exnotype=chapter.arabic,%
aboveglarrowskip=0pt,%DEFAULT
glarrow=\tiny$\hookrightarrow$,%DEFAULT IS glarrow= (i.e. empty)
glhangstyle=cascade,%
glhangindent=2em}%
\begin{document}
\let\\=\textsc
\ex
\begingl
\gla
Hom\^{a}o sa \v{c}\^{o} p\^{o} tha \~{n}u nao ng\u{a} hmua. \~{N}u dj\u{a} g\u{a}, \~{n}u dj\u{a} \v{c}\u{o}ng \~{n}u, laih gui r\^{e}o \~{n}u. Todang bboi r\^{o}k jolan \~{n}u nao hma, \~{n}u bb\^{o}h sa droi mr\u{a} d\u{o} bboi gah, a, hruh \~{n}u. //
\glb
\\{exist} one \\{clf} person old \\{3s} go do field \\{3s} hold machete \\{3s} hold hoe \\{3s} and carry.on.back back.basket \\{3s} while at along trail \\{3s} go field \\{3s} see one \\{clf} peacock stay at \\{drct} -- nest \\{3s} //
\glft
`There was an old person who went to work in the field. He took along his machete, he took along his hoe, and he carried his basket on his back. While he was on his way to the farm, he saw a peacock beside its nest.' //
\endgl
\xe
\end{document}
Which results in:

Also works with normal hanging style. Changing \lingset{glhangstyle=cascade} to \lingset{glhangstyle=normal} results in:

If you want the arrow (in this case), to point at the middle of the text instead of the baseline, you can use aboveglarrowskip to tweak the position. Changing \lingset{aboveglarrowskip=0pt} (the default) to \lingset{aboveglarrowskip=-2pt} results in:

You can choose to use other arrow symbols from other packages. For example, \usepackage[mathb]{mathabx} and \lingset{glarrow=\tiny$\drsh$}

Or, you can use \usepackage{fdsymbol} and \lingset{glarrow=\tiny$\Rdsh$}

If you want to use something other than an arrow, that's also fine. For example, \lingset{glarrow=\tiny{--test--}}

You can add some spacing, for example, \lingset{glarrow={--test--\hspace*{5pt}}}

Really, this patch is quite flexible. For example, you can throw in a TikZ arrow that is really big. But because the height will be too large, you can surround it in \raisebox with zero height, using:
\usepackage{tikz}
\newcommand{\myarrow}[1][]{%
\begin{tikzpicture}[#1]%
\draw (0,2.7ex) -- (0,0) -- (0.75em,0);
\draw (0.55em,0.2em) -- (0.75em,0) -- (0.55em,-0.2em);
\end{tikzpicture}%
}
\lingset{numoffset=\leftmargin,%
textoffset=0.75em,%
extraglskip=!1.1ex,%
glspace=!0.01em,%
belowglpreambleskip=!0ex,%
aboveglbskip=-0.9ex,%
aboveglcskip=-0.9ex,%
aboveglftskip=-0.1ex,%
exnotype=chapter.arabic,%
glarrow={\raisebox{0pt}[0pt][0pt]{\myarrow[scale=1.35,draw=red]}},%
glhangstyle=cascade,%
glhangindent=2em}%

and glhangstyle=normal

It is also great because you can use it universally via \lingset{} or specify it for only individual \ex\xe or \pex\xe examples. You only need to be using the standard glossing (not nlevel) and specify the symbol/text you want and a vertical skip (if desired).
expex-demo.tex. – whatisit Dec 22 '17 at 05:45