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
27 Answers 27
J, (削除) 23 (削除ここまで) 22 bytes
(];/:')'=;)&|._2{.\cut
cut split by space
_2{.\ only odds
|. reverse
;/:')'=; join and sort by equality with ')'
-
2\$\begingroup\$ 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. \$\endgroup\$79037662– 790376622021年03月30日 16:15:11 +00:00Commented Mar 30, 2021 at 16:15
-
\$\begingroup\$ I didn't read carefully at all, my bad. \$\endgroup\$FrownyFrog– FrownyFrog2021年03月30日 16:21:13 +00:00Commented Mar 30, 2021 at 16:21
-
3\$\begingroup\$ Sorting the close parentheses to the right is clever. \$\endgroup\$Jonah– Jonah2021年03月30日 16:31:34 +00:00Commented Mar 30, 2021 at 16:31
Stax, 8 bytes
ßN¶e╣╨j,
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))))
-
3\$\begingroup\$ +1, You always make ultimate usage of Excel functions and teach us that VBA is no use \$\endgroup\$wasif– wasif2021年03月30日 17:00:37 +00:00Commented Mar 30, 2021 at 17:00
-
2\$\begingroup\$ 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. \$\endgroup\$Axuary– Axuary2021年03月30日 19:55:49 +00:00Commented Mar 30, 2021 at 19:55 -
\$\begingroup\$ Nice usage of Excel, I'm amazed @Axuary \$\endgroup\$Yassin Hajaj– Yassin Hajaj2021年03月31日 21:21:04 +00:00Commented Mar 31, 2021 at 21:21
-
\$\begingroup\$ You can get this down to 75 bytes by switching to
For Each
, dropping the intermediate variablea
, 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 -->
\$\endgroup\$Taylor Raine– Taylor Raine2021年04月02日 17:05:00 +00:00Commented Apr 2, 2021 at 17:05 -
\$\begingroup\$ 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 \$\endgroup\$Taylor Raine– Taylor Raine2021年04月02日 17:05:59 +00:00Commented Apr 2, 2021 at 17:05
Jelly, (削除) 11 (削除ここまで) 9 bytes
Ḳm2ɓṪṭ;μ/
-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), (削除) 105 (削除ここまで) (削除) 98 (削除ここまで) (削除) 87 (削除ここまで) 78 bytes
I =INPUT
S I ARB . L '|>' ARB . F ')' REM . R =F L ')' R :S(S)
OUTPUT =I
END
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__
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.
-
\$\begingroup\$ Alas Elixir function names tend to be very long compared to other languages since they're all prefixed with
Something.
. \$\endgroup\$79037662– 790376622021年03月30日 20:49:52 +00:00Commented Mar 30, 2021 at 20:49 -
\$\begingroup\$ @79037662 I guess that's why we don't see Elixir golfs very often. \$\endgroup\$Kirill L.– Kirill L.2021年03月31日 07:42:01 +00:00Commented Mar 31, 2021 at 7:42
-
1\$\begingroup\$ That, and it's simply not a very popular language, outside of golfing. \$\endgroup\$79037662– 790376622021年03月31日 13:10:21 +00:00Commented Mar 31, 2021 at 13:10
R, (削除) 94 (削除ここまで) (削除) 92 (削除ここまで) 86 bytes
Edit: -2 bytes thanks to Giuseppe
function(s,t=el(strsplit(s,"[)]?(.>|$)")))Reduce(paste,c(rev(t),")"[+grepl("[(]",t)]))
-
\$\begingroup\$
"[)]?(.>|$)"
instead? Assuming>
only ever appears in pipes... \$\endgroup\$Giuseppe– Giuseppe2021年03月30日 17:34:41 +00:00Commented Mar 30, 2021 at 17:34 -
\$\begingroup\$ @Giuseppe It is true, by the challenge specifications, that
|
and>
characters only appear in the pipe operators. \$\endgroup\$79037662– 790376622021年03月30日 18:03:29 +00:00Commented Mar 30, 2021 at 18:03 -
1\$\begingroup\$ @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. \$\endgroup\$Giuseppe– Giuseppe2021年03月30日 18:06:12 +00:00Commented Mar 30, 2021 at 18:06
-
1\$\begingroup\$ @Giuseppe - Thanks! I missed that, too. See you back in school! \$\endgroup\$Dominic van Essen– Dominic van Essen2021年03月30日 20:51:01 +00:00Commented Mar 30, 2021 at 20:51
Retina 0.8.2, (削除) 30 (削除ここまで) (削除) 23 (削除ここまで) 22 bytes
+`^(.+?).>(.+?\()
2ドル1ドル
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.
2ドル1ドル
Move the first term into the second term's argument.
-
\$\begingroup\$
+`(.*?).>(.*?\()(.*)
; Also, is there any flags to make it replace it only first occurrence every time? (So(.*)
and3ドル
may be removed) \$\endgroup\$tsh– tsh2021年03月31日 02:29:11 +00:00Commented Mar 31, 2021 at 2:29 -
\$\begingroup\$ @tsh Nothing better than my existing
^
to anchor the match at the start of the string... \$\endgroup\$Neil– Neil2021年03月31日 09:00:50 +00:00Commented Mar 31, 2021 at 9:00 -
\$\begingroup\$ So maybe
+`^(.*?).>(.*?\()
->2ドル1ドル
? \$\endgroup\$tsh– tsh2021年03月31日 09:13:25 +00:00Commented Mar 31, 2021 at 9:13 -
\$\begingroup\$ @tsh Ah yes, I was overthinking the removal of
3ドル
and overlooked the removal of the)
. \$\endgroup\$Neil– Neil2021年03月31日 09:27:54 +00:00Commented Mar 31, 2021 at 9:27
JavaScript (Node.js), 60 bytes
s=>s.match(/\w+\(?/g).reverse().join``+s.match(/\)/g).join``
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`|>`)
Charcoal, 20 bytes
≔⪪S|>θ⭆⮌θ...ι⊖Lι⭆θ✂ι±1
Try it online! Link is to verbose version of code. Explanation:
≔⪪S|>θ
Split the input on |>
.
⭆⮌θ...ι⊖Lι
Print the strings in reverse order without their last character.
⭆θ✂ι±1
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('|>'))
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)
Alternatively:
Python 3, 59 bytes
r=''
for x in input().split('|>'):r=x[:-1]+r+x[-1]
print(r)
Zsh, 41 bytes
for a (${(s:|>:)1})x=${a//\()/($x)}
<<<$x
${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).
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));}
Expects no spacing.
V (vim), 11 bytes
òf|xxd0f(pò
ò...ò 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 1θ
, }
can also be ]
, and θ
(only the one at the end) can be ¤
with no change in functionality.
Java, (削除) 103 (削除ここまで) (削除) 84 (削除ここまで) (削除) 80 (削除ここまで) 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.
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;}
-
1
-
\$\begingroup\$ @79037662 Good idea. \$\endgroup\$Unmitigated– Unmitigated2021年03月30日 15:30:48 +00:00Commented Mar 30, 2021 at 15:30
-
1\$\begingroup\$ -4 Try it online! \$\endgroup\$pxeger– pxeger2021年03月30日 15:31:20 +00:00Commented Mar 30, 2021 at 15:31
JavaScript (Node.js), 49 bytes
f=a=>a.replace(/(.*).>(.*)./,(_,x,y)=>y+f(x)+')')
Only works if no extra spaces are there.
JavaScript (Node.js), 50 bytes
a=>a.split`|>`.reduce((p,q)=>q.replace('(','('+p))
This works if the input does not contais "$"
character. Otherwise, '('+
need to be replaced by x=>x+
with +1 byte cost.
-
\$\begingroup\$ Indeed, the input will not contain the
$
character. \$\endgroup\$79037662– 790376622021年03月31日 02:37:10 +00:00Commented Mar 31, 2021 at 2:37 -
\$\begingroup\$ And what exactly happens if
$
is in fact there? \$\endgroup\$Roman Odaisky– Roman Odaisky2021年03月31日 20:27:28 +00:00Commented Mar 31, 2021 at 20:27 -
\$\begingroup\$ @RomanOdaisky
$$
will become a single$
, and$&
will become a(
, \$\endgroup\$tsh– tsh2021年04月02日 06:58:26 +00:00Commented Apr 2, 2021 at 6:58
PowerShell Core, 81 bytes
-join($t=$args|% Sp* "|>"|% *m ')')[($l=$t.Count)..0]+")"*($l-!($t[0]|% e*h '('))
Thanks to @Julian!
PowerShell, 108 bytes
param($s)$n=$s.split("|>");$k=(($n|%{$n[--$q]})|%{$_-replace"\)$"})-join"";$k+")"*($k-replace"[^\(]").length
- 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!
-
2
Red, 85 bytes
func[s][t: take s: split s"|>"forall s[t: rejoin[replace s/1"()"""mold to-paren t]]t]
PowerShell Core, (削除) 67 (削除ここまで) (削除) 57 (削除ここまで) (削除) 45 (削除ここまで) 44 bytes
$args-split'.>'|%{$r=$_|% rep* '(' "($r"}
$r
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)))
- 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.
-
\$\begingroup\$ Welcome to the site. You can use
from re import*;r=findall
for a shorter input. I count 2 bytes saved this way. \$\endgroup\$2021年04月01日 02:13:01 +00:00Commented Apr 1, 2021 at 2:13 -
Japt, (削除) 15 (削除ここまで) 12 bytes
q"|>" rÏiXJÉ
- saved 3 by assuming no whitespaces as suggested by OP @79037662
q"|>" - split on pipe r - reduce by ÏiXJÉ - inserting before )
-
\$\begingroup\$ The rules say you can assume the input has no whitespace, so you don't need to remove spaces. \$\endgroup\$79037662– 790376622021年03月30日 18:04:33 +00:00Commented Mar 30, 2021 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 split
s 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)
.
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))
-
-
\$\begingroup\$ @kops Doesn't work for the first test case
2|>myFunction()
. \$\endgroup\$Neil– Neil2021年03月30日 20:00:30 +00:00Commented Mar 30, 2021 at 20:00 -
\$\begingroup\$ @Neil shoot, thanks I missed that case in my answer as well... will have to go fix \$\endgroup\$kops– kops2021年03月30日 20:03:01 +00:00Commented Mar 30, 2021 at 20:03
-
\$\begingroup\$ @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 theb
variable being unnecessary. I've been experimenting with it and I've found this 81 byte solution. \$\endgroup\$qwatry– qwatry2021年03月30日 20:27:35 +00:00Commented Mar 30, 2021 at 20:27
Pyth, 13 bytes
.UXtlZZbcQ"|>
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}&
Takes and returns a list of characters. Requires no spacing.
Twue, 123 bytes
@::>*
^()::=()!
^_ ::=_ !
^_::=_^
!()::=!
!_::=_!
$!::=$;
|> $;::= $#(;%
##_::~_
$#::= $##
$::=$
_$::=$#_
%::~)
::=
^ @$
animation of the code running successfully
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 )
.
()
. \$\endgroup\$bar(baz(new_function(other_function())))
is not a function (for the purpose of this challenge). \$\endgroup\$