# Un-pipe an Elixir expression

Elixir is a programming language with a feature called the pipe operator, |>, similar to the pipe in Bash and other languages. It passes the result of an expression on the left as the first parameter of a given function on the right.

To clarify, here are some examples.

2 |> myFunction()


is equivalent to

myFunction(2)


Here, the expression 2 is passed as the first parameter of the function myFunction().

Now, consider how an expression with multiple pipes is evaluated. Multiple pipes are evaluated left to right, so all of these lines are equivalent:

other_function() |> new_function() |> baz() |> bar() |> foo()
new_function(other_function()) |> baz() |> bar() |> foo()
baz(new_function(other_function())) |> bar() |> foo()
bar(baz(new_function(other_function()))) |> foo()
foo(bar(baz(new_function(other_function()))))


Here, in each line the leftmost pipe is calculated, which takes the first expression and passes it to the second expression (which is a function).

## Challenge

Your challenge will be to write a program or function which, when given an Elixir expression with one or more pipes, will return or output an equivalent expression with no pipes. In real Elixir code the functions may have multiple parameters but to keep this challenge simpler, you may assume all functions will take only one parameter.

## Examples

Input                                                       -> Output
2 |> myFunction()                                           -> myFunction(2)
otherfunction() |> newfunction() |> baz() |> bar() |> foo() -> foo(bar(baz(newfunction(otherfunction()))))


## Rules

• Function names will only contain ASCII letters and underscores, and end in ()
• The leftmost expression will only contain alphanumeric ASCII, underscores, and parentheses
• You may assume there is no whitespace in the input (the examples here have spaces for readability)
• You may also assume there are spaces surrounding the pipe operators like in the examples, if you wish
• All functions only take one parameter
• Leading or trailing whitespace is allowed in output
• Whitespace around parentheses is allowed in output
• Any reasonable form of input/output is allowed
• No standard loopholes
• Shortest code in bytes for each language wins
• Can we assume that numbers will only appear at the start, before the first pipe? – caird coinheringaahing Mar 30 at 14:40
• @ChartZBelatedly Yes. As the rules say, function names (i.e. all expressions after the first pipe) will only include ASCII letters and underscores, and end in (). – 79037662 Mar 30 at 14:42
• Is excess whitespace around the parentheses ok? – pxeger Mar 30 at 15:44
• @JonathanAllan No, bar(baz(new_function(other_function()))) is not a function (for the purpose of this challenge). – 79037662 Mar 30 at 19:21
• @hakr14 That is not allowed. – 79037662 Mar 30 at 21:09

# J, 23 22 bytes

(];/:')'=;)&|._2{.\cut


Try it online!

                    cut    split by space
_2{.\       only odds
|.            reverse
;/:')'=;                join and sort by equality with ')'

• Technically this breaks the rules due to it not working with whitespace-less inputs. However this is an edge case I didn't think about, and my intention was to allow submissions to assume there are spaces around the pipe operators. Therefore I will retroactively change the rules to allow this. – 79037662 Mar 30 at 16:15
• I didn't read carefully at all, my bad. – FrownyFrog Mar 30 at 16:21
• Sorting the close parentheses to the right is clever. – Jonah Mar 30 at 16:31

# Stax, 8 bytes

ßN¶e╣╨j,


Run and debug it

## Explanation(unpacked)

.|>/kNas++
.|>/       split the string on "|>"
k      reduce the list by:
N     push the 2nd string with the last element popped, then push the last element
a    put the previous iteration on top of the stack
s   swap the bracket with the prev iteration
++ concatenate into one string


# Excel VBA (Immediate Window), 85 75 bytes

-10 bytes thanks to @TaylorScott

For Each s In Split([A1],"|>"):o=IIf(o="",s,Left(s,len(s)-1)+o+")"):Next:?o


## Excel, 165 154 bytes

-11 bytes rethought the Excel based on changes to VBA

=LET(x,FILTERXML("<a><b>"&SUBSTITUTE(A1,"|>","</b><b>")&"</b></a>","//b"),n,ROWS(x),a,n+1-SEQUENCE(n),CONCAT(INDEX(LEFT(x,LEN(x)-(a<n)),a),REPT(")",n-1)))


=LET(                                                 'define variables
return last parameter
"<a><b>"&SUBSTITUTE(A1,"|>","</b><b>")&"</b></a>" 'Convert piped string to XML
x,FILTERXML(                                  ,"//b") 'x = XML converted to array
n,ROWS(x)                                             'n = # rows in x
a,n+1-SEQUENCE(n)                                     'a = n .. 1
CONCAT(INDEX(LEFT(x,LEN(x)-(a<n)),a),REPT(")",n-1))   'final calculation
INDEX(                    ,a)                  'x in reverse order
LEFT(x,LEN(x)-(a<n))                     'if not first element delete
rightmost char
REPT(")",n-1)    'n-1 ")"
CONCAT(                                           )   'concatenate everything


## Original

=LET(s,SUBSTITUTE(A7,")",""),x,FILTERXML("<a><b>"&SUBSTITUTE(s,"|>","</b><b>")&"</b></a>","//b"),n,ROWS(x),CONCAT(INDEX(x,n+1-SEQUENCE(n)),REPT(")",LEN(A7)-LEN(s))))

• +1, You always make ultimate usage of Excel functions and teach us that VBA is no use – Wasif Mar 30 at 17:00
• Thanks, @Wasif. I wouldn't say VBA is completely useless. However, the recent addition of the LET has allowed Excel to do a lot more without VBA. – Axuary Mar 30 at 19:55
• Nice usage of Excel, I'm amazed @Axuary – Yassin Hajaj Mar 31 at 21:21
• You can get this down to 75 bytes by switching to For Each, dropping the intermediate variable a, and using string addition rather than concatentation - For Each s In Split([A1],"|>"):o=IIf(o="",s,Left(s,len(s)-1)+o+")"):Next:?o - I would also explicitly state that this answer depends upon the assumption of no whitespace; And you can make the VBA answer look a little bit better by adding syntax highlighting with the HTML tag <!-- language: lang-vb --> – Taylor Scott Apr 2 at 17:05
• And you should also probably change the title of your response to specify that this is and Excel VBA answer, rather than a generic VBA answer – Taylor Scott Apr 2 at 17:05

# Jelly, 11 9 bytes

Ḳm2ɓṪṭ;µ/


Try it online!

-2 bytes thanks to Jonathan Allan!

The |> must be surrounded by spaces

## How it works

Ḳm2ɓṪṭ;µ/ - Main link. Takes a string S on the left
Ḳ         - Split S on spaces
m2       - Take every second element, ignoring the "|>" elements
ɓ   µ  - Create a new dyadic chain f(a, b):
Ṫ     -   Remove the trailing ")" from a and yield it
;   -   Concatenate the modified a and b
ṭ    -    Tack the ")" to the end
/ - Reduce the split S by this. The ɓ in the chain tells
the quick to reduce from the left with arguments reversed


# SNOBOL4 (CSNOBOL4), 1059887 78 bytes

	I =INPUT
S	I ARB . L '|>' ARB . F ')' REM . R =F L ')' R	:S(S)
OUTPUT =I
END


Try it online!

Thanks to Razetime for -2 bytes.

### Explanation:

	I =INPUT	;* read input, assign to I
S			;* label S
I [lhs] = [rhs]	;* replace the part of I matching the following pattern:
ARB . L '|>'	;* something followed by '|>' (assign to L)
ARB . F ')'	;* followed by something followed by a ')' (assign to F)
REM . R		;* and the rest of the string (assign to R)
;* with:
F L ')' R	;* F, L, ')', and R concatenated together
:S(S)	;* on SUCCESS (a match was found), goto S
OUTPUT =I	;* on FAILURE, proceed to output and end the program
END


# Elixir, 64 bytes

&Macro.to_string Macro.expand Code.string_to_quoted!(&1),__ENV__


Try it online!

Well, this looks a bit longish for a solution relying on built-in functionality, but I guess we need a "reference" implementation with Elixir doing it itself.

• Alas Elixir function names tend to be very long compared to other languages since they're all prefixed with Something.. – 79037662 Mar 30 at 20:49
• @79037662 I guess that's why we don't see Elixir golfs very often. – Kirill L. Mar 31 at 7:42
• That, and it's simply not a very popular language, outside of golfing. – 79037662 Mar 31 at 13:10

# R, 9492 86 bytes

Edit: -2 bytes thanks to Giuseppe

function(s,t=el(strsplit(s,"[)]?(.>|$)")))Reduce(paste,c(rev(t),")"[+grepl("[(]",t)]))  Try it online! • "[)]?(.>|$)" instead? Assuming > only ever appears in pipes... – Giuseppe Mar 30 at 17:34
• @Giuseppe It is true, by the challenge specifications, that | and > characters only appear in the pipe operators. – 79037662 Mar 30 at 18:03
• @79037662 that's the second time I've missed something in the spec, I think I need to go back to the first grade and learn how to read again. – Giuseppe Mar 30 at 18:06
• @Giuseppe - Thanks! I missed that, too. See you back in school! – Dominic van Essen Mar 30 at 20:51

+^(.+?).>(.+?$$) 21  Try it online! Link includes test cases. Edit: Saved 7 8 bytes thanks to @tsh. Explanation: +  Repeat until all pipes have been processed. +^(.+?).>(.+?\()  Match the first two terms up to the second term's opening bracket. 21  Move the first term into the second term's argument. • +(.*?).>(.*?\()(.*); Also, is there any flags to make it replace it only first occurrence every time? (So (.*) and 3 may be removed) – tsh Mar 31 at 2:29 • @tsh Nothing better than my existing ^ to anchor the match at the start of the string... – Neil Mar 31 at 9:00 • So maybe +^(.*?).>(.*?\() -> 21? – tsh Mar 31 at 9:13 • @tsh Ah yes, I was overthinking the removal of 3 and overlooked the removal of the ). – Neil Mar 31 at 9:27 # JavaScript (Node.js), 60 bytes s=>s.match(/\w+\(?/g).reverse().join+s.match(/$$/g).join


Try it online!

This would fail if there were no pipes (not possible according to challenge rules) but here's an alternative version which can also handle that:

## JavaScript (Node.js), 61 bytes

s=>(f=a=>a[1]?a.pop().slice(0,-1)+f(a)+')':a[0])(s.split|>)


Try it online!

# Charcoal, 20 bytes

≔⪪Ｓ|>θ⭆⮌θ…ι⊖Ｌι⭆θ✂ι±¹


Try it online! Link is to verbose version of code. Explanation:

≔⪪Ｓ|>θ


Split the input on |>.

⭆⮌θ…ι⊖Ｌι


Print the strings in reverse order without their last character.

⭆θ✂ι±¹


Print the last characters of the strings. This means that the first term gets reunited, while the remaining terms have their brackets moved to the end.

# Python 2, 54 bytes

lambda s:reduce(lambda r,x:x[:-1]+r+')',s.split('|>'))


Try it online!

For each function going to left to right, insert the string r we have so far between the parens of the function x.

string |> new_function() = new_function(string)


This is done by removing the last character (a close paren), appending the string, then adding back the close paren. Because reduce starts the accumulator at the first element by default, we don't need any special handling if it's not a function.

This is longer in Python 3, which lacks reduce but can use a starred assignment to extract the initial value.

Python 3, 59 bytes

r,*l=input().split('|>')
for x in l:r=x[:-1]+r+')'
print(r)


Try it online!

Alternatively:

Python 3, 59 bytes

r=''
for x in input().split('|>'):r=x[:-1]+r+x[-1]
print(r)


Try it online!

# Zsh, 41 bytes

for a (${(s:|>:)1})x=${a//$$)/(x)} <<<x  Try it online! • {1} - take the input • (s:|>:) - split on |> • for a () - for each element: • {a} - take the element • /// - replace: • \() - empty parentheses • (x) - with the current value of x, in more parentheses • x= and assign that to x (it starts as an empty string by default) • <<<x - print x # Jelly, 9 bytes Port of FrownyFrog's clever J answer! Ḳm2ṚF=Þ”)  A monadic Link accepting and yielding a list of characters (with the |> surrounded by a space on each side like the examples). Try it online! ### How? Ḳm2ṚF=Þ”) - Link: list of characters, S Ḳ - split at spaces m2 - modulo-2 slice [1st, 3rd, 5th, ...] Ṛ - reverse F - flatten Þ - sort by: = ”) - equals ')'?  # C (gcc), 90 bytes f(s,l,t)char*s;{for(t=0;--l&&s[l-1]-62;t++);s=printf("%.*s",t+!l,s+l)-t||f(")",f(s,l-2));}  Try it online! Expects no spacing. # V (vim), 11 bytes òf|xxd0f(pò  Try it online! ò…ò repeats the commands until the first error, the rest are normal Vim commands. # 05AB1E, 13 bytes „|>¡Å»¨ì')«}θ  Try it online! The annoying thing here is .» only reduces by the first command after it, not a } or ]-terminated function. And macros don't exist, so… ¯\_(ツ)_/¯ „|>¡Å»¨ì')«}θ # full program θ # last element of... Å» # cumulatively reduced... # implicit input... ¡ # split by... „|> # literal... » # to the right by... ') # literal... « # concatenated to... ¨ # all characters of... # (implicit) second element in current reduction step... ¨ # excluding the last... ì # prepended to... # (implicit) first element in current reduction step } # end cumulative reduce # implicit output  ') can also be Iθ, sθ, or ¹θ, } can also be ], and θ (only the one at the end) can be ¤ with no change in functionality. # Java, 1038480 77 bytes s->{var p="";for(var c:s.split("\\|>"))p=c.replace("()","("+p+")");return p;}  Saved 19 bytes thanks to 79037662. Saved 4 bytes thanks to pxeger. Try it online! A positive lookahead can be used for a solution of the same length. s->{var p="";for(var c:s.split("\\|>"))p=c.replaceAll("(?=\$$)",p);return p;}


Try it online!

• Save some bytes with a for-each loop: tio.run/… – 79037662 Mar 30 at 15:26
• @79037662 Good idea. – iota Mar 30 at 15:30
• – pxeger Mar 30 at 15:31

# JavaScript (Node.js), 49 bytes

f=a=>a.replace(/(.*).>(.*)./,(_,x,y)=>y+f(x)+')')


Try it online!

Only works if no extra spaces are there.

# JavaScript (Node.js), 50 bytes

a=>a.split|>.reduce((p,q)=>q.replace('(','('+p))


Try it online!

This works if the input does not contais "$" character. Otherwise, '('+ need to be replaced by x=>x+ with +1 byte cost. • Indeed, the input will not contain the $ character. – 79037662 Mar 31 at 2:37
• And what exactly happens if $ is in fact there? – Roman Odaisky Mar 31 at 20:27 • @RomanOdaisky $$ will become a single $, and $& will become a (, – tsh Apr 2 at 6:58 # PowerShell Core, 81 bytes -join($t=$args|% Sp* "|>"|% *m ')')[($l=$t.Count)..0]+")"*($l-!($t[0]|% e*h '('))  Try it online! Thanks to @Julian! # PowerShell, 108 bytes param($s)$n=$s.split("|>");$k=(($n|%{$n[--$q]})|%{$_-replace"\)$"})-join"";$k+")"*($k-replace"[^$$]").length  Try it online! • Take a string • Split it by |> • Save ^ to an array • Reverse the array • Loop on each element • Remove trailing ) • Join array • Append number of ( in the joined string amount ) • Print and bye bye! # Red, 85 bytes func[s][t: take s: split s"|>"forall s[t: rejoin[replace s/1"()"""mold to-paren t]]t]  Try it online! # PowerShell Core, 675745 44 bytes args-split'.>'|%{r=_|% rep* '(' "(r"} r  Try it online! The rep* is the shortcut for the replace method. # Python 3, 84 79 bytes import re;r=re.findall;i=input() print(''.join(r('[\w(]+',i)[::-1]+r('$$*',i)))


Try it online!

• Seems to be a complete solution: works whether there are spaces around the functions/constants/pipes or not, works whether first position contains constant or function.
• Doesn't technically look for pipes, so you could replace |> with |< and it would return the same output. Could add a positive lookforward to the regex but that would eat another ~10 bytes and the contest didn't specify.
• Pays a 27-byte 22-byte penalty just for importing one regex method. Thanks Python.
• Edited for small improvement.
• Welcome to the site. You can use from re import*;r=findall for a shorter input. I count 2 bytes saved this way. – Wheat Wizard Apr 1 at 2:13
• Welcome to code golf stack exchange. You can save a few bytes by using a lambda function: tio.run/… – 79037662 Apr 1 at 3:12

# Japt, 15 12 bytes

q"|>" rÏiXJÉ


Try it

• saved 3 by assuming no whitespaces as suggested by OP @79037662
 q"|>"    - split on pipe
r        - reduce by
ÏiXJÉ    - inserting before )
• The rules say you can assume the input has no whitespace, so you don't need to remove spaces. – 79037662 Mar 30 at 18:04

# Python 3, 70 bytes

*a,b=input().split("|>")[::-1]
print(*[f[:-1]for f in a],b,")"*len(a))


The program first splits the input into a list using the pipe operator, "|>", as the separator. Using multiple assignment, b is set equal to the last element of the list (previously the first element prior to being reversed). b contains a string of the first element in the pipe, which may or may not be a function. The rest of the list is assigned to a. All of the elements of a are strings of functions. Next, the program outputs all the elements of a with ) removed from each, b, and ")"*len(a).

Try it online!

If we're allowed to require that only the first item in the pipe has a space after it, but none of others, we can save 1 byte.

# 69 bytes

a=input().split("|>")[::-1]
print(*[f[:-1]for f in a],")"*(len(a)-1))


Try it online!

• Neat strategy, but I think your b variable isn't doing anything for -5 bytes – kops Mar 30 at 19:56
• @kops Doesn't work for the first test case 2|>myFunction(). – Neil Mar 30 at 20:00
• @Neil shoot, thanks I missed that case in my answer as well... will have to go fix – kops Mar 30 at 20:03
• @kops You're mostly right. If the first item in the pipe is a function the b variable isn't needed, but if it is a variable or number the last character of the variable will be removed and there will be an extra ) at the end. But I still think you're right about the b variable being unnecessary. I've been experimenting with it and I've found this 81 byte solution. – qwatry Mar 30 at 20:27

# Pyth, 13 bytes

.UXtlZZbcQ"|>


Test suite

Explanation:

.U      cQ"|> | Reduce the input split at "|>" on the following lambda, where b is the current value and Z is the next item:
XtlZZb      |  Insert b into Z at index len(Z)-1


# Wolfram Language (Mathematica), 42 bytes

#//.{a__,"|",_,b__,"(",c___}:>{b,"(",a,c}&


Try it online!

Takes and returns a list of characters. Requires no spacing.

# Twue, 123 bytes

@::>*
^()::=()!
^_ ::=_ !
^_::=_^
!()::=!
!_::=_!
$!::=$;
|> $;::=$#(;%
##_::~_
$#::=$##
$::=$
_$::=$#_
%::~)
::=
^ @$ Try it on the website! Twue is a spiritual successor to Thue I made. I initially tried answering this challenge in Thue, and had to manually describe moving each character one byte to the left, individually, so the byte count came out to ~1kb. Then, I realize I didn't properly handle constants and abandoned the code, not wanting to rewrite that mess from scratch. Enter Twue, which allows wildcards to be used (_) to refer to generic characters. Furthermore, it removes the random rule selection from the language, and creates a better standard for input/output. The language is still a bit of a work in progress, but most of the bugs have been ironed out, and most of the spec has been implemented. ## Explanation @::>*  This replaces all @ in the workspace with a line of input. Basically: readline. For an input of 1234 |> foo() |> bar(), this populates the workspace with: ^ 1234 |> foo() |> bar()$


^ and $ are characters we'll be using as pointers, of sorts, for iterating forward and backward through the code. ^()::=()! ^_ ::=_ ! ^_::=_^  This section moves the ^ pointer after the first expression, which may or may not contain parentheses. We want to preserve these. This inserts ! after the first expression, and we are ready to parse. !()::=! !_::=_!$!::=$;!  Now, for every expression afterwards, we want to strip the () from it. So, we move ! character by character through the input, removing () in front of it as we go. After these steps, the input will look like this:  1234 |> foo |> bar$;!


Now we are ready for the second stage of parsing. We will use ! later in the final stages of printing. Now, we have two pointers, $ and ;, which will define the range we're operating on.  |>$;::= $#(;% ##_::~_$#::= $##$::=$_$::=$#_  _$::=$#_ simply moves every character in front of a $ after it, prepending a # to it. This signifies we want to print that character. We repeat this until the $ pointer is at the leftmost part of the word, after a space. Since we are at the beginning of the word, we start printing the characters after $#, by first duplicating the #, and printing the character after #__. This allows us to only print when we want to—if we didn't duplicate, we'd print the strings in reverse, or lose track of the $ pointer. If we find the string |>$;, we've printed all the characters we could, and we still have more things to parse. We remove the |> and append a %, signifying we need to print a corresponding closing parenthesis.

These replacements repeat until they can't anymore.

%::~)


If there are no other substitutions we can possibly make, we simply take each % and output a corresponding )`.