32
\$\begingroup\$

Over is a higher-order function in multiple languages such as APL (). It takes 2 functions and 2 values as arguments, applies the first function to both values, then applies the second to their result. For example, using to represent Over:

1 ²⍥+ 2

We would first calculate ² of each argument: 1² = 1 and 2² = 4. We then apply + to these, yielding 5.

You are to take as input:

  • A black box function, \$f\$, which takes an integer as input and returns an integer
  • A black box function, \$g\$, which takes 2 integers as input and returns a single integer
  • 2 integers, \$a\$ and \$b\$.

You should then return the result of \$g(f(a), f(b))\$.

If you have a builtin specifically for this (e.g. APL's , Husk's ¤ etc.), consider including a non-builtin answer as well. It might even get you an upvote :)

You may input and output in the most convenient format for your language, and in any convenient method, including taking \$a\$ and \$b\$ as a pair/list/tuple [a, b]

For the sake of simplicity, you can assume that the black-box function will always input and output integers within your language's integer domain, and that \$a\$, \$b\$ and the output will be with your language's integer domain.

This is , so the shortest code in bytes wins

Test cases

f
g
a, b -> out

f(x) = x²
g(x,y) = x - y
-2, 2 -> 0

f(x) = φ(x)     (Euler totient function)
g(x,y) = 2x + y
5, 9 -> 14

f(x) = x³-x²-x-1
g(x,y) = y⁴-x³-y²-x
-1, -1 -> 22

f(x) = x
g(x,y) = x / y   (Integer division)
-25, 5 -> -5
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Can we take a & b as an array [a,b]? \$\endgroup\$
    – Shaggy
    Apr 20, 2021 at 7:12
  • \$\begingroup\$ @Shaggy Yes you can \$\endgroup\$ Apr 20, 2021 at 11:31

42 Answers 42

22
\$\begingroup\$

Haskell, 12 bytes

f?g=(.f).g.f

Try it online!

Haskell was made for this.

Let's unpack it:

(f?g) x y =
(((.f).g.f) x) y =
(.f)(g (f x)) y =
((g (f x)).f) y =
g (f x) (f y)

If you're wondering what happens if we make this further pointfree in f and g, we can express (?) as:

\f->((.f).).(.f)
(.).(.).flip(.)<*>flip(.)

The flipped version of ? that's invoked as g?f is a little nicer:

((.).flip(.)<*>).(.)

(I used pointfree.io for these.)

Test cases copied from Unrelated String.


Haskell, 10 bytes

(.map).(.)

Try it online!

If the input [x,y] is a two-element list, and the binary function g accepts its two arguments as such a list. The main function takes is arguments as g then `f.

\$\endgroup\$
1
  • \$\begingroup\$ I really need to get better at pointfree \$\endgroup\$ Apr 20, 2021 at 0:49
11
\$\begingroup\$

Factor, 16 bytes

[ bi@ rot call ]

Try it online!

Explanation:

It's a quotation (anonymous function) that takes a quotation with stack effect ( x x -- x ), two integers, and a quotation with stack effect ( x -- x ) on the data stack as input. It takes them in that order, as that allows for what I believe is the shortest code. Assuming the data stack looks like [ + ] 1 2 [ sq ] when this quotation is called...

  • bi@ Apply a quotation to two objects.

    Stack: [ + ] 1 4

  • rot Move the object third from the top to the top.

    Stack: 1 4 [ + ]

  • call Call a quotation.

    Stack: 5

Factor, 10 bytes

map-reduce

Try it online!

Built-in.

\$\endgroup\$
1
  • \$\begingroup\$ Exactly what I had in mind :) \$\endgroup\$
    – Bubbler
    Apr 20, 2021 at 2:10
9
\$\begingroup\$

J, 12 bytes

2 :'(u v)~v'

Try it online!

Non-built-in solution. This is an explicit conjunction that takes two functions on two sides and evaluates to a train that acts like "u over v", but with flipped arguments.

x ((u v)~v) y
x (u v)~ v y
(v y) (u v) x
(v y) u v x

J, 1 byte

&

Try it online!

J's built-in conjunctions can be assigned to a variable, unlike in Dyalog APL.

\$\endgroup\$
1
  • \$\begingroup\$ "unlike in Dyalog APL" ― works fine in, say, NARS2000. \$\endgroup\$
    – Adám
    Apr 20, 2021 at 20:20
7
\$\begingroup\$

JavaScript (ES6), 23 bytes

(f,g,x,y)=>g(f(x),f(y))

Try it online!

\$\endgroup\$
2
  • 5
    \$\begingroup\$ Ninja'd by ten seconds :/ \$\endgroup\$ Apr 20, 2021 at 0:26
  • \$\begingroup\$ No need to Over-complexify, life is Overly simple \$\endgroup\$
    – Kaddath
    Apr 20, 2021 at 8:18
7
\$\begingroup\$

Rust, 21 bytes

|f,g,x,y|g(f(x),f(y))

Try it online!

An anonymous function that has the signature

fn(fn(i32)->i32,fn(i32,i32)->i32,i32,i32)->i32

Don't you love it when the function signature is twice as long as the function itself?

\$\endgroup\$
6
\$\begingroup\$

APL (Dyalog Classic), 9 bytes

{⍺⍺/⍵⍵¨⍵}
{⍺⍺/⍵⍵¨⍵}
 ⍺⍺          left operand (function argument)
   /         reduce
    ⍵⍵       right operand
      ¨      each
       ⍵     right argument

APL has a builtin for this, ⍥, but here's a non builtin solution as an operator taking an array of arguments.

Alternative 'proper' definition: {(⍵⍵⍺)⍺⍺⍵⍵⍵}, or more readably as {(⍵⍵ ⍺) ⍺⍺ ⍵⍵ ⍵}

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ ⎕/⎕¨⎕ \$\endgroup\$
    – Adám
    Apr 20, 2021 at 20:15
  • \$\begingroup\$ @Adám not a fan particularly, you can post that as a separate answer if you want \$\endgroup\$
    – rak1507
    Apr 20, 2021 at 20:20
6
\$\begingroup\$

Racket, 26 bytes

(λ(f g x y)(g(f x)(f y)))

Try it online!

λ is 2 bytes, BTW.

Pretty self-explanatory, but:

(λ(f g x y)(g(f x)(f y)))  Anonymous function submission
(λ                      )  Lambda;
  (f g x y)                accept functions f, g and arguments x, y and return
           (g          )   g(
             (f x)           f(x),
                  (f y)            f(y))
\$\endgroup\$
6
\$\begingroup\$

R, 29 bytes

function(f,g,a,b)g(f(a),f(b))

Try it online!

No surprises here. In a future version of R, function will be replaceable with \ (which is supposed to look like a lambda).

\$\endgroup\$
6
\$\begingroup\$

Haskell, 17 16 15 bytes

(f!k)x=k(f x).f

Try it online!

-1 thanks to Wheat Wizard repatterning the use of infix

\$\endgroup\$
3
  • 3
    \$\begingroup\$ Also worth pointing out this exists in the standard library as 'on' in Data.Function \$\endgroup\$
    – rak1507
    Apr 20, 2021 at 0:43
  • \$\begingroup\$ @rak1507 Thanks! Like, actually, thanks--I knew something like that had to exist but instead of searching the type signature I've been stuck on the idea that it has to be one of those infix operators from Control.Arrow :P \$\endgroup\$ Apr 20, 2021 at 0:44
  • 1
    \$\begingroup\$ You can shave off a byte with virtually no modification \$\endgroup\$
    – Wheat Wizard
    Feb 6 at 17:00
5
\$\begingroup\$

Wolfram Language (Mathematica), 10 bytes

#2@@#/@#3&

Try it online!

Input [f, g, {x, y}].

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Nice ... argh, Inner is so close to doing this task \$\endgroup\$ Apr 23, 2021 at 1:55
5
\$\begingroup\$

SKI-calculus, 71 bytes

S(S(KS)(S(K(S(KS)))(S(K(S(K(S(KS)))))(S(K(S(K(S(KK)))))(S(KS)K)))))(KK)

Edit: Another go at hand-translating the lambda calculus expression into SKI using the rules in Wikipedia, this time arriving at the same answer as @Bubbler.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ According to SKI interpreter by aditsu, your expression evaluates to (x0->(x1->(x2->x0(x1(x2))))) which doesn't look quite correct. \$\endgroup\$
    – Bubbler
    Apr 21, 2021 at 0:44
  • \$\begingroup\$ Working 71 bytes: S(S(KS)(S(K(S(KS)))(S(K(S(K(S(KS)))))(S(K(S(K(S(KK)))))(S(KS)K)))))(KK). I guess there must be a language like Binary Lambda Calculus that can express SKI calculus in binary or something... \$\endgroup\$
    – Bubbler
    Apr 21, 2021 at 1:09
  • \$\begingroup\$ ...and there's Binary Combinatory Logic. Time to build an online interpreter... \$\endgroup\$
    – Bubbler
    Apr 21, 2021 at 1:15
  • \$\begingroup\$ @Bubbler Nice, I hadn't realised that S(KK)I is just K for a start, so I'll take another crack at it. \$\endgroup\$
    – Neil
    Apr 21, 2021 at 14:54
  • \$\begingroup\$ @Bubbler OK I've tried again and come up with your answer. \$\endgroup\$
    – Neil
    Apr 21, 2021 at 16:13
5
+50
\$\begingroup\$

tinylisp, 23 bytes

(q((f g x y)(g(f x)(f y

Try it online!

Ungolfed

(lambda (f g x y)     ; a lambda function taking four arguments
  (g (f x) (f y)))    ; apply f to x, f to y, and g to the results
\$\endgroup\$
4
\$\begingroup\$

Python 2, 25 bytes

\$ a \$ and \$ b \$ are inputted as a tuple (called \$ x \$).

lambda f,g,x:g(*map(f,x))

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ You can save a byte by taking input as a list [a,b] \$\endgroup\$
    – rak1507
    Apr 20, 2021 at 0:45
  • \$\begingroup\$ @rak1507 Yeah, just noticed it. \$\endgroup\$ Apr 20, 2021 at 0:46
4
\$\begingroup\$

Jelly, 4 bytes

Ñ€ç/

Try it online!

Takes f on the first line, g on the second line, and the code is on the third line (this is standard for Jelly). Also, takes the arguments together as a list

 €    For each of the arguments
Ñ     Apply the next link (wraps around to `f`)
   /  Reduce by (for a pair, applies dyad to the first and second element of the list)
  ç   Apply the last link (`g`)

Also works:

Jelly, 4 bytes

ÑçÑ}

Try it online!

Ñ     Apply `f` (to the left argument, since it's called as a monad)
 çÑ}  2-2 chain - given dyads x, y, computes x(a, y(a, b)) if the chain's current value is a and the right argument is b
 ç    Apply `g` to the current value (f(left)) and
  Ñ}  A dyad formed from a monad by ignoring the left argument

Basically, Ñ} is (l, r) -> f(r), so this ends up evaluating as λ x y -> g(f(x), (λ a b -> f(b))(x, y)) which simplifies to λ x y -> g(f(x), f(y)) as required.

(These chaining rules are absolutely beautiful. Thank you Dennis for Jelly :P)

\$\endgroup\$
3
  • 3
    \$\begingroup\$ There is also ÑçÑ} that takes a on the left and b on the right :) \$\endgroup\$ Apr 20, 2021 at 0:53
  • 1
    \$\begingroup\$ @cairdcoinheringaahing lol, I am currently editing that in with a description :P \$\endgroup\$
    – hyper-neutrino
    Apr 20, 2021 at 0:54
  • 1
    \$\begingroup\$ There is also ñçñ, but that requires f to be forced as a monadic link (prefixed with µ) if it has any different behaviour when run monadically/dyadically \$\endgroup\$ Apr 21, 2021 at 13:50
4
\$\begingroup\$

Scala, 16 bytes

_ map _ reduce _

Try it online!

Takes ([a,b],f,g). There’s more ways to do this but I’m on mobile so I’ll add them later

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

Proton, 21 bytes

(f,g,a)=>g(*map(f,a))

Try it online!

Time to bring out this garbage again :D

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

Stax, 7 bytes

n!aa!a!

Run and debug it

A full program which can be executed as a block as well.

accepts the arguments as g x f y.

\$\endgroup\$
7
  • \$\begingroup\$ Cant this be packed? \$\endgroup\$
    – lyxal
    Apr 20, 2021 at 7:23
  • \$\begingroup\$ doesn't make sense to pack something that can be reused. It takes its arguments from the stack, so I think it doesn't make sense to pack here. \$\endgroup\$
    – Razetime
    Apr 20, 2021 at 7:23
  • \$\begingroup\$ "a full program" submission can surely be packed to save a byte. \$\endgroup\$
    – lyxal
    Apr 20, 2021 at 7:24
  • \$\begingroup\$ nah. not doing it. \$\endgroup\$
    – Razetime
    Apr 20, 2021 at 7:24
  • \$\begingroup\$ Okay boomer :p. How about explaining how the link works \$\endgroup\$
    – lyxal
    Apr 20, 2021 at 7:26
4
\$\begingroup\$

C (gcc), 54 \$\cdots\$ 39 37 bytes

Saved 8 bytes thanks to dingledooper!!!
Saved 2 bytes thanks to ceilingcat!!!

o(f,g,a,b)int f(),g();{g(f(a),f(b));}

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ 39 bytes \$\endgroup\$ Apr 20, 2021 at 0:56
  • \$\begingroup\$ @dingledooper Nice - thanks! :D \$\endgroup\$
    – Noodle9
    Apr 20, 2021 at 1:12
  • \$\begingroup\$ @ceilingcat Nice one - thanks! :D \$\endgroup\$
    – Noodle9
    Apr 20, 2021 at 9:50
3
\$\begingroup\$

Vyxal, 8 3 bytes

M$R

Try it Online!

Takes [g, [a, b], f]. If reduction was reversible, then this would be 2 bytes.

Explained

M$R
M   # map f over [a, b]
 $R # reduce that by g
\$\endgroup\$
3
\$\begingroup\$

Excel (Insider Beta), 29 bytes

=LAMBDA(f,g,a,b,g(f(a),f(b)))

LAMBDA is only available through Excel Insider Beta. The functions have to be defined as names to work. In my case, I defined a name q that is equal to the above and then used the formula =q(LAMBDA(x,x^2),LAMBDA(x,y,x+y),1,2) in a cell. This could also be done by defining the names a=LAMBDA(x,x^2) and b=LAMBDA(x,y,x+y) and then use the formula q(a,b,1,5).

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

Red, 24 bytes

func[f g x y][g f x f y]

Try it online!

This version doesn't work in TIO (Red is not up-to date), that's why I provide a screenshot from my Red GUI console:

enter image description here

TIO compatible version, 28 bytes

func[f g x y][do[g f x f y]]

Try it online!

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

Ruby, 23 bytes

->f,g,x,y{g[f[x],f[y]]}

Try it online!

Or:

Ruby, 23 bytes

->f,g,*x{g[*x.map(&f)]}

Try it online!

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

Husk, 5 4 bytes

₂₁⁰₁

Try it online!

Black-box functions are supplied as sequential lines in the code (in the footer in the TIO link), input values are given as program arguments.

₂₁⁰₁     # 2 argument function: second argument is implicit
   ₁     # perform function ₁ using second argument
 ₁⁰      # perform function ₁ using first argument
₂        # perform function ₂ using the last 2 values as arguments
\$\endgroup\$
2
  • \$\begingroup\$ I'm sure you can use F instead of Ẋ to return a value instead of an array. \$\endgroup\$
    – Razetime
    Apr 20, 2021 at 7:25
  • \$\begingroup\$ @Razetime - Yes, you're right, that's much better. Thanks! \$\endgroup\$ Apr 20, 2021 at 9:40
3
\$\begingroup\$

Coconut, 11 bytes

Takes input as Ꙫ(g)(f, [a, b]).

g->g<*..map

Try it online!

<*.. is the multi-arg backward function composition, which makes this function equivalent to

g->*args->g(*map(*args))
\$\endgroup\$
3
\$\begingroup\$

APL (Dyalog Unicode), 5 bytes (SBCS)

Full program version of rak1507's implementation.

⎕/⎕¨⎕

Try it online!

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

Julia, 17 16 bytes

F(!,+,a,b)=!a+!b

Try it online!

Previous answer, 17 bytes

g*f*x=g(f.(x)...)

Try it online!

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

Attache, 10 bytes

${z|x|>&y}

Try it online!

Takes input as F[f, g, [a, b]], where F is the above function.

This is two separate pipes: The vectorizing pipe |, and the regular pipe |>. z|x pipes each element of z into the unary function x, i.e., Map[x, z]. Then, this array is piped to &y, which passes each element of the array as a separate parameter.

Alternatives

${&y!x=>z}, 10 bytes. Same input as above.

{_2@@Map[_]}, 12 bytes. Takes parameters f and g, returns a function which takes a tuple [a, b] as input.

Attache (builtin), 3 bytes

`#:

Try it online!

Simple quote-operator. Called as (`#:)[g, f][a, b].

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

C (gcc), 30 bytes

#define o(f,g,a,b)g(f(a),f(b))

Try it online!

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

Standard ML, 24 bytes

fn(f,g,a,b)=>g(f a)(f b)

Concurr pre-release, 50 bytes

$lambda\f:lambda\g:lambda\a:lambda\b::g(:f a)$:f b

Wow that's horrible.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ fn(f,g)=>g o map f if you use lists, but I haven’t counted to see if it’s actually shorter. Also with a tuple you can do g(f a,f b) which is certainly one shorter. \$\endgroup\$ Apr 21, 2021 at 22:22
2
\$\begingroup\$

Japt, 6 5 bytes

As far as I know, Japt does not support taking functions as inputs, or at least I couldn't find a way that actually works. To sidestep this problem, I've moved the blackbox functions into the code header while excluding them from the byte count. Their definition or form is not important for the implementation itself. Hope this is valid, otherwise I don't think Japt can compete.

The functions are to be stored in V and W respectively.

mV rW 
mV    // Map the array of input numbers through V
   rW // then reduce the result with W.

Shaved off a byte thanks to Shaggy by taking the input as an array instead.

Try it online!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ If they were all built-in Japt methods, they could be taken as input strings. Consensus does allow, though, for black box functions to be assigned to pre-defined variables so we're OK there. Although, you could take advantage of mult-line code to allow for both options, like so. You can also save a byte by taking the integer inputs as a single array and ditching the N. \$\endgroup\$
    – Shaggy
    Apr 20, 2021 at 17:12
  • \$\begingroup\$ @Shaggy Thanks for the tip on the empty leading line in the header, didn't know I could avoid overriding U that way, that's the reason I went with N. \$\endgroup\$
    – Etheryte
    Apr 20, 2021 at 17:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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