In @Adám's Dyalog APL Extended, the (under) operator means conjugation: apply one function, then a second function, then the inverse of the first. It's fun to think of real-life actions in terms of conjugation:

A problem is transformed by g into another domain where it more readily solved by f , and then transformed back into the original domain. An example from real life is “under anesthetics”:

apply anesthetics
    perform surgery
wake up from anesthetics


The inverse of a line g is "un" prepended to g, and vice versa. Define any line between s and its inverse, in that order, as being "under" s. For each line f in input in order:

  • If f and its inverse both occur, do nothing
  • If f is not "under" any other action, print f
  • If f is "under" a line g, print f + " under " + g where + is concatenation.


A nonempty multiline string, or list of strings, etc., consisting of spaces and lowercase letters (you may instead use uppercase). Exactly one line will begin with "un"; and it will be the inverse of some other line. No line will be empty.


Output in the same format you took input in, or as allowed by Standard I/O.

Test cases:

apply anesthetics
perform surgery
unapply anesthetics

perform surgery under apply anesthetics

unite asia
establish the silk road
ite asia

establish the silk road under unite asia

desire a book
walk to store
take the book
pay for the book
unwalk to store
read the book

desire a book
take the book under walk to store
pay for the book under walk to store
read the book

drink excessively
undrink excessively

[empty string]
  • 1
    I, too, have no output when I drink excessively – Stan Strum Dec 1 at 21:06
  • 1
    shouldn't it be "take the book and pay for the book under walk to store"? otherwise it's not clear that the transform is equivalent to the original... – Jonah Dec 2 at 21:41
  • 1
    @Jonah The idea is in an ideal world w="walk to store" and w^-1="unwalk to store" are inverses, so mathematically wfw^-1wg^-1 = wfgw^-1. – lirtosiast Dec 2 at 22:33
  • Ah fair enough, @lirtosiast. – Jonah Dec 2 at 23:22

Brachylog, 90 bytes

;Ṡ{hhH↰₂gB&hb~c[A,B,C]&tT;C↔↰U∧" under ",H,T;A↔↰,U|tT&hh,TgJ&hb;T↰Q∧J,Q|h}

I made this while being under the impression that this could be recursive and multiple unders could be stacked. Probably not optimized. Also as this is bracylog, plumbing takes quite some bytes.

Try it online!

Retina, 82 bytes

$4 under $1$1$5

Try it online! Link includes test cases. Explanation:


Run the whole program in multiline mode (so that ^ and $ match the beginning and end of individual lines) and repeat until there are no changes.


Look for lines that might begin with un and are followed by a line that begins with un only if the previous line does not while the rest of the line is the same, and delete both lines. (This is a change of behaviour from Retina 0.8.2, which splits the lines before trying to match and therefore can never delete lines if the match needs to span more than one line at once.)


Look for lines that might begin with un, followed by at least one line, followed by a line that begins with un only if the original line does not while the rest of the line is the same.

$4 under $1$1$5

Move the original line down one line, and also append it with under to the line just traversed. (Additional lines will be handled by the repeat.)

Python 2, 106 bytes

for i in s:
 if'un'==i[:2]or'un'+i in s:x=(' under '+i)*(not x)
print l

Try it online!

If the input can be a list from STDIN and the output be newline-separated, we then have this 94-byte solution:

for i in s:
 if'un'==i[:2]or'un'+i in s:x=(' under '+i)*(not x)
 else:print i+x

JavaScript (Babel Node), 91 bytes

Takes input as an array of strings in lowercase. Returns another array of strings.

a=>a.flatMap(s=>s==r|'un'+s==r?(u=u?'':' under '+s,[]):s+u,u='',r=a.find(s=>/^un/.test(s)))

Try it online!


a =>                     // a[] = input array
  a.flatMap(s =>         // for each string s in a[]:
    s == r |             //   if s matches the reference string
    'un' + s == r ? (    //   or its opposite:
      u =                //     update u:
        u ?              //       if u is not an empty string:
          ''             //         turn it to an empty string
        :                //       else:
          ' under ' + s, //         set it to s with the ' under ' prefix
      []                 //     yield an empty array so that this entry is removed
    ) :                  //   else:
      s + u,             //     yield s followed by u
    u = '',              //   initialize u to an empty string
    r = a.find(s =>      //   initialize r ...
      /^un/.test(s)      //     ... to the string beginning with 'un'
    )                    //
  )                      // end of flatMap()
  • Fail? – l4m2 Dec 1 at 0:45
  • @l4m2 Fail indeed. Now fixed. – Arnauld Dec 1 at 1:01

Clean, 147 bytes

import StdEnv,Data.List
$l=hd[w++[e++[' under ':u]\\e<-z]++y\\i<-a l&t<-b l,w<-a i&u<-i,z<-a t&[x:y]<-b t|u==['un':x]||x==['un':u]]

Try it online!

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.