17
\$\begingroup\$

This challenge is related to some of the MATL language's features, as part of the May 2018 Language of the Month event. Associated challenge: Function clipboard: paste.


Introduction

MATL has several clipboards, where you can store values (copy) to be retrieved later (paste). Some clipboards are automatic, which means that copying is automatically triggered by certain events. This challenge focuses on one of the automatic clipbards, called the function-input clipboard, or simply function clipboard.

This clipboard stores the inputs to the four most recent calls to normal, input-taking functions. Normal functions are the most common type of functions in MATL. Input-taking means that the function takes at least one input (functions that do not take any input are not considered by the function clipboard).

This is best explained with the following examples, which use two normal functions:

  • +, which pops two numbers from the stack and pushes their sum.
  • U, which pops one number and pushes its square.

Example 1:

3 2 + 6 + 12 4 U + +

produces the result 39. The code is interpreted as follows:

  • Number literals such as 3 or 12 get pushed to the stack
  • Functions such as + pop their inputs and push their outputs to the stack.

The function calls, in chronological order, are:

  1. 3 2 + gives 5
  2. 5 6 + gives 11
  3. 4 U gives 16
  4. 12 16 + 28
  5. 11 28 + gives 39.

The clipboard can be viewed as a list of four lists. Each inner list contains the inputs to a function call, with most recent calls first. Within each inner list, inputs are in their original order.

So after running the code the clipboard contents are (in Python notation):

[[11, 28], [12, 16], [4], [5, 6]]

Example 2:

10 20 U 30 +

leaves numbers 10 and 430 on the stack. The stack is displayed bottom to top at the end of the program.

The function calls are

  1. 20 U gives 400
  2. 400 30 + gives 430

Since there have been only two function calls, some of the inner lists defining the clipboard will be empty. Note also how 10 is not used as input to any function.

Thus, the clipboard contents after running the code are:

[[400, 30], [20], [], []]

Example 3 (invalid):

10 20 + +

is considered invalid, because an input to the second + is missing (in MATL this would implicitly trigger user input).

The challenge

Input: a string S with number literals, + and U, separated by spaces.

Output: the contents of the function clipboard after evaluating the string S.

Clarifications:

  • You may use any two consistent symbols to represent those functions, other than digits. Also, you can use any consistent symbol as separator, instead of space.
  • Only the two indicated functions will be considered.
  • The input string will contain at least one number literal and at least one function.
  • All numbers will be positive integers, possibly with more than one digit.
  • It is possible that some number literals are not used by any function, as in the example 2.
  • The input is guaranteed to be valid code, without requiring additional numbers. So a string as in example 3 will never occur.
  • Trailing empty inner lists in the output can be ommited. So the result in example 2 can be [[400, 30], [20]]
  • Any reasonable, unambiguous output format is acceptable. For example, a string with comma as inner separator and semicolon as outer separator: 400,30;20;;.

Additional rules:

Test cases

Input
Output

3 2 + 6 + 12 4 U + +
[[11, 28], [12, 16], [4], [5, 6]]

15 3 4 + 2 U 8 + U +
[[7, 144], [12], [4, 8], [2]]

3 6 9 12 + + 10 8 U 6
[[8], [6, 21], [9, 12], []]

8 41 12 25 4 5 33 7 9 10 + + + + + + + +
[[41, 105], [12, 93], [25, 68], [4, 64]]

10 1 1 + U U U U U
[[65536], [256], [16], [4]]
\$\endgroup\$
13
  • \$\begingroup\$ Is [[28, 11], [16, 12], [4], [6, 5]] valid output for the first example? \$\endgroup\$
    – ovs
    May 13, 2018 at 18:14
  • \$\begingroup\$ @ovs No, inputs within each inner list must be in the original order, that is, as in the function call \$\endgroup\$
    – Luis Mendo
    May 13, 2018 at 18:23
  • \$\begingroup\$ Hm, are we discouraged from, eh, just solving this in MATL? :P \$\endgroup\$ May 13, 2018 at 18:33
  • 1
    \$\begingroup\$ Is this clipboard M? \$\endgroup\$
    – Giuseppe
    May 13, 2018 at 19:44
  • 1
    \$\begingroup\$ @Giussepe Exactly! I haven’t mentioned that name here because we are not using function M. I will do it in the “paste” challenge \$\endgroup\$
    – Luis Mendo
    May 13, 2018 at 20:21

12 Answers 12

5
\$\begingroup\$

Bash, 43 bytes

sed s/+/rdnFPrp+/g\;s/U/p2^/g|dc|tac|sed 4q

Try it online!

This prints the clipboard in the following format, note the usage of \x0F as the separator.

item_1\x0Fitem_2
item_3
.
.
item_m\x0Fitem_n

The key idea is to pass this into dc, a stack-based language, such that the required stack items will be printed.

The input is piped to sed where every + is replaced with rdnFPrp+, which in dc prints the second number on the stack followed by \x0F and then the top number before performing addition. sed also replaces every U with p2^, print the top stack element and square it.

The first substitution command s replaces all, as is denoted by the global flag g, +s with rdnFPrp+. In dc, r swaps the top two stack items, d duplicates the top item, n prints it without a newline, F pushes 15 onto the stack and P prints it as a character (which is the delimiter), r swaps again, p prints the top stack item and then + performs addition on the top two stack items.

We have another command, and in sed, commands are separated by either semicolons or newlines, of which the first option is chosen. Simply having ; will make bash interpret that as the end of the sed command, so it is escaped with a \.

In the last substitution command, U is replaced globally with p2^. In dc, p prints, and 2^ raises it to the second power.

The result of sed is eval'ed as dc code, printing the entire clipboard.

The pipe to dc makes dc interpret that as dc code. Now, the most recent calls are at the bottom and the older ones at the top.

Since the lines are in reverse order, tac (reverse cat) is used to fix that.

And finally, sed picks the first 4 lines from tac.

This is a shorter way of doing head -4. sed performs the commands to every line of the input one at a time. If there are no commands, nothing is done to the input, and it is returned as it is. 4q tells sed to perform the command q on line 4. When sed is processing line 4 of the input, the first three inputs have already been printed. The command q quits the program, so it prints the fourth line and quits, thus performing the equivalent of head -4.

\$\endgroup\$
4
\$\begingroup\$

Python 2, 126 bytes

s=[0];b=[]
for c in input().split():k='U+'.find(c)+1;b=[s[k-1::-1]][:k]+b;s=[int([c,s[0]**2,sum(s[:2])][k])]+s[k:]
print b[:4]

Try it online!

\$\endgroup\$
4
\$\begingroup\$

Haskell, 113 109 bytes

take 4.([]#).words
x:y:s#"+":r=(x+y:s#r)++[[y,x]]
x:s#"U":r=(x*x:s#r)++[[x]]
s#n:r=read n:s#r
_#_=[]
infix 4#

The first line defines an anonymous function which takes a string, e.g. "3 2 + 6 + 12 4 U + +", and returns a list of lists of ints: [[11,28],[12,16],[4],[5,6]]. Try it online!

\$\endgroup\$
3
\$\begingroup\$

05AB1E, 20 bytes

A"D¸ˆn‚DˆO"4ô‡.V¯R4£

Try it online!

-4 thanks to Emigna (as well as -8 thanks to him updating me about rules).

  • U: a
  • + : b
\$\endgroup\$
3
2
\$\begingroup\$

Clean, 140 bytes

import StdEnv,Text
k[a,b:n]["+":s]=k[a+b:n]s++[[b,a]]
k[a:n]["U":s]=k[a^2:n]s++[[a]]
k n[v:s]=k[toInt v:n]s
k _[]=[]
$s=k[](split" "s)%(0,3)

Try it online!

In classical Clean style, it's the Haskell solution except about 50% longer.

\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES6), 107 bytes

Takes input as a list consisting of integers, '+' and 'U'. Returns another list consisting of integers, arrays of 2 integers and '_' for empty slots.

a=>a.map(x=>s.push(+x?x:(c=[x>[a=s.pop(),r=a*a]?a:[r=s.pop(),(r+=a,a)],...c],r)),s=[c='___'])&&c.slice(0,4)

Try it online!

Commented

a =>                          // a[] = input array
  a.map(x =>                  // for each entry x in a[]:
    s.push(                   //   update the stack:
      +x ?                    //     if x is a positive integer:
        x                     //       push x onto the stack
      :                       //     else:
        ( c = [               //       update the clipboard:
            x > [             //         compare x with '['
              a = s.pop(),    //         a = first operand
              r = a * a       //         use a² as the default result
            ] ?               //         if x is 'U' (greater than '['):
              a               //           save the 1st operand in the clipboard
            :                 //         else:
              [ r = s.pop(),  //           r = 2nd operand
                (r += a, a)   //           add the 1st operand
              ],              //           save both operands in the clipboard
            ...c              //         append the previous clipboard entries
          ],                  //       end of clipboard update
          r                   //       push r onto the stack
        )                     //
    ),                        //     end of stack update
    s = [c = '___']           //   initialize the stack; start with c = '___'
  ) &&                        // end of map()
  c.slice(0, 4)               // return the last 4 entries of the clipboard
\$\endgroup\$
2
\$\begingroup\$

Go, 305 303 295 bytes

Dropped 8 bytes thanks to @ovs

func e(s string){b,v,w,x,r:=[][]int{{},{},{},{}},[]int{},0,0,0;for _,d:=range Split(s," "){if d=="+"{w,x,v=v[0],v[1],v[2:];r=w+x;b=append([][]int{[]int{x,w}},b...)}else if d=="U"{w,v=v[0],v[1:];r=w*w;b=append([][]int{[]int{w}},b...)}else{n,_:=Atoi(d);r=n};v=append([]int{r},v...)};Print(b[0:4])}

Try it online!

\$\endgroup\$
0
2
\$\begingroup\$

Octave, 206 bytes

s=strsplit(input(''));m=t=[];for z=s
if(q=str2num(p=z{1}))t=[t q];else
if(p-43)m{end+1}=(k=t(end));t(end)=k^2;else
m{end+1}=(k=t(end-1:end));t(end-1:end)=[];t(end+1)=sum(k);end
end
end
m(1:end-4)=[];flip(m)

Try it online!

If only Octave had a pop syntax. m is the memory clipboard, t the stack.

\$\endgroup\$
3
  • \$\begingroup\$ could you construct m and t in reverse, adding elements to the front rather than the end? \$\endgroup\$
    – Giuseppe
    May 16, 2018 at 14:51
  • \$\begingroup\$ 178 bytes using the strategy outlined above \$\endgroup\$
    – Giuseppe
    May 16, 2018 at 14:56
  • \$\begingroup\$ @Guiseppe Clever. I always have this feeling that appending is generally shorter than prepending but in this case the large number of "end"s should have made me reconsider \$\endgroup\$
    – Sanchises
    May 16, 2018 at 15:05
1
\$\begingroup\$

Python 3, 218 204 bytes

-14 bytes thanks to ovs

from collections import*
def f(s):
	a=deque(maxlen=4);z=a.appendleft;b=[];x=b.pop
	for i in s.split():
		if'+'==i:c=x(),x();z(c);r=sum(c)
		elif'U'==i:c=x();z(c);r=c*c
		else:r=int(i)
		b+=r,
	print([*a])

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

Red, 335 330 bytes

func[s][b: copy[]foreach c split s" "[append b either c >"+"and(c <"U")[do c][c]]r: copy[]until[t: 0 until[not parse
b[to copy c[2 integer!"+"](insert/only r reduce[c/1 c/2]replace b c c/1 + c/2 t: 1)to end]]until[not parse b[to copy
c[integer!"U"](insert/only r to-block c/1 replace b c c/1 ** 2 t: 1)to end]]t = 0]take/part r 4]

Try it online!

More readable:

f: func[s] [
    s: split s " "
    b: copy []
    foreach c s [
        append b either (c > "+") and (c < "U")[do c] [c]
    ]
    r: copy []
    until [
        t: 0
        until [
            not parse b [to copy c[2 integer! "+"]
            (insert/only r reduce[c/1 c/2]
            replace b c c/1 + c/2
            t: 1)
            to end]
        ]
        until [
            not parse b [to copy c[integer! "U"]
            (insert/only r to-block c/1
            replace b c c/1 ** 2
            t: 1)
            to end]
        ]
        t = 0
    ]
    take/part r 4  
]
\$\endgroup\$
1
\$\begingroup\$

R, 205 182 bytes

function(P){S=F
M=list()
for(K in el(strsplit(P," "))){if(is.na(x<-strtoi(K))){if(K>1){M=c(m<-S[1],M)
S[1]=m^2}else{M=c(list(m<-S[2:1]),M)
S=c(sum(m),S[-2:0])}}else S=c(x,S)}
M[1:4]}

Try it online!

M is the memory clipboard, P is the program, and S is the stack.

Technically S is initialized as a vector containing a single zero but since we never get an invalid input, it saves me a byte from S={}.

\$\endgroup\$
1
\$\begingroup\$

C (gcc), 264 249 bytes

  • -15 bytes from @ceilingcat

I used recursion so that I could use the function stack as the data stack: the input list is walked through and the operations are performed: the results are displayed in reverse order, with stack pushes not displayed.

The stack is implemented as a linked list. Here's how it works:

  • The current node is set up with [pointer to value,pointer to previous node]
  • To push a value, it is stored and the function is called again with the current node.
  • To pop a value or modify the value on the top of the stack, a previous node's value is modified and the function is called again with the previous node.

I originally used a structure for the nodes, but I switched to bare pointers to save space. An interesting feature of this linked list is that it cleans itself up when the recursion completes.

#define _ printf(
f(char**s,int**p){int v,*y[]={&v,p},**w=y,m,n,t,z=1;return*s?**s-85?**s-43?--z,t=14,v=atoi(*s):(t=6,w=p[1],m=**w,**w+=n=**p):(t=0,w=p,**w*=m=**p),_(v=f(s+1,w))<4?",[%d]\0,[%d,%d]"+t+!v:"",m,n),v+z:0;}g(int*s){_"[");f(s,0);_"]\n");}

Try it online!

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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