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⍥+ 2
We would first calculate 2 of each argument: 12 = 1 and 22 = 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 code-golf, so the shortest code in bytes wins
Test cases
f
g
a, b -> out
f(x) = x2
g(x,y) = x - y
-2, 2 -> 0
f(x) = φ(x) (Euler totient function)
g(x,y) = 2x + y
5, 9 -> 14
f(x) = x3-x2-x-1
g(x,y) = y4-x3-y2-x
-1, -1 -> 22
f(x) = x
g(x,y) = x / y (Integer division)
-25, 5 -> -5
52 Answers 52
Haskell, 12 bytes
f?g=(.f).g.f
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).(.)
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.
-
\$\begingroup\$ I really need to get better at pointfree \$\endgroup\$Unrelated String– Unrelated String2021年04月20日 00:49:17 +00:00Commented Apr 20, 2021 at 0:49
Factor, 16 bytes
[ bi@ rot call ]
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 4rotMove the object third from the top to the top.Stack:
1 4 [ + ]callCall a quotation.Stack:
5
Factor, 10 bytes
map-reduce
Built-in.
-
\$\begingroup\$ Exactly what I had in mind :) \$\endgroup\$Bubbler– Bubbler2021年04月20日 02:10:37 +00:00Commented Apr 20, 2021 at 2:10
J, 12 bytes
2 :'(u v)~v'
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
&
J's built-in conjunctions can be assigned to a variable, unlike in Dyalog APL.
-
\$\begingroup\$ "unlike in Dyalog APL" ― works fine in, say, NARS2000. \$\endgroup\$Adám– Adám2021年04月20日 20:20:08 +00:00Commented Apr 20, 2021 at 20:20
-
5\$\begingroup\$ Ninja'd by ten seconds :/ \$\endgroup\$2021年04月20日 00:26:30 +00:00Commented Apr 20, 2021 at 0:26
-
\$\begingroup\$ No need to Over-complexify, life is Overly simple \$\endgroup\$Kaddath– Kaddath2021年04月20日 08:18:19 +00:00Commented Apr 20, 2021 at 8:18
-
-
\$\begingroup\$ due to rule clarify \$\endgroup\$l4m2– l4m22023年01月09日 21:37:37 +00:00Commented Jan 9, 2023 at 21:37
Rust, 21 bytes
|f,g,x,y|g(f(x),f(y))
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?
Haskell, (削除) 17 (削除ここまで) (削除) 16 (削除ここまで) 15 bytes
(f!k)x=k(f x).f
-1 thanks to Wheat Wizard repatterning the use of infix
-
3\$\begingroup\$ Also worth pointing out this exists in the standard library as 'on' in Data.Function \$\endgroup\$rak1507– rak15072021年04月20日 00:43:05 +00:00Commented 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\$Unrelated String– Unrelated String2021年04月20日 00:44:56 +00:00Commented Apr 20, 2021 at 0:44 -
1\$\begingroup\$ You can shave off a byte with virtually no modification \$\endgroup\$2022年02月06日 17:00:46 +00:00Commented Feb 6, 2022 at 17:00
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 {(⍵⍵ ⍺) ⍺⍺ ⍵⍵ ⍵}
-
-
\$\begingroup\$ @Adám not a fan particularly, you can post that as a separate answer if you want \$\endgroup\$rak1507– rak15072021年04月20日 20:20:33 +00:00Commented Apr 20, 2021 at 20:20
Racket, 26 bytes
(λ(f g x y)(g(f x)(f y)))
λ 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))
-
2\$\begingroup\$ Nice ... argh,
Inneris so close to doing this task \$\endgroup\$Greg Martin– Greg Martin2021年04月23日 01:55:45 +00:00Commented Apr 23, 2021 at 1:55
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.
-
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– Bubbler2021年04月21日 00:44:03 +00:00Commented 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– Bubbler2021年04月21日 01:09:32 +00:00Commented Apr 21, 2021 at 1:09 -
\$\begingroup\$ ...and there's Binary Combinatory Logic. Time to build an online interpreter... \$\endgroup\$Bubbler– Bubbler2021年04月21日 01:15:59 +00:00Commented Apr 21, 2021 at 1:15
-
\$\begingroup\$ @Bubbler Nice, I hadn't realised that
S(KK)Iis justKfor a start, so I'll take another crack at it. \$\endgroup\$Neil– Neil2021年04月21日 14:54:23 +00:00Commented Apr 21, 2021 at 14:54 -
\$\begingroup\$ @Bubbler OK I've tried again and come up with your answer. \$\endgroup\$Neil– Neil2021年04月21日 16:13:21 +00:00Commented Apr 21, 2021 at 16:13
Python 2, 25 bytes
\$ a \$ and \$ b \$ are inputted as a tuple (called \$ x \$).
lambda f,g,x:g(*map(f,x))
-
\$\begingroup\$ You can save a byte by taking input as a list [a,b] \$\endgroup\$rak1507– rak15072021年04月20日 00:45:47 +00:00Commented Apr 20, 2021 at 0:45
-
\$\begingroup\$ @rak1507 Yeah, just noticed it. \$\endgroup\$dingledooper– dingledooper2021年04月20日 00:46:03 +00:00Commented Apr 20, 2021 at 0:46
Jelly, 4 bytes
Ñ€ç/
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
ÑçÑ}
Ñ 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)
-
3\$\begingroup\$ There is also
ÑçÑ}that takesaon the left andbon the right :) \$\endgroup\$2021年04月20日 00:53:16 +00:00Commented Apr 20, 2021 at 0:53 -
1\$\begingroup\$ @cairdcoinheringaahing lol, I am currently editing that in with a description :P \$\endgroup\$2021年04月20日 00:54:21 +00:00Commented Apr 20, 2021 at 0:54
-
1\$\begingroup\$ There is also
ñçñ, but that requiresfto be forced as a monadic link (prefixed withµ) if it has any different behaviour when run monadically/dyadically \$\endgroup\$2021年04月21日 13:50:31 +00:00Commented Apr 21, 2021 at 13:50
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).
Stax, 7 bytes
n!aa!a!
A full program which can be executed as a block as well.
accepts the arguments as g x f y.
-
\$\begingroup\$ Cant this be packed? \$\endgroup\$2021年04月20日 07:23:08 +00:00Commented 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– Razetime2021年04月20日 07:23:31 +00:00Commented Apr 20, 2021 at 7:23
-
\$\begingroup\$ "a full program" submission can surely be packed to save a byte. \$\endgroup\$2021年04月20日 07:24:15 +00:00Commented Apr 20, 2021 at 7:24
-
\$\begingroup\$ nah. not doing it. \$\endgroup\$Razetime– Razetime2021年04月20日 07:24:39 +00:00Commented Apr 20, 2021 at 7:24
-
\$\begingroup\$ Okay boomer :p. How about explaining how the link works \$\endgroup\$2021年04月20日 07:26:49 +00:00Commented Apr 20, 2021 at 7:26
-
\$\begingroup\$ Since you're allowed to take an array of arguments you can omit the first
*in your second solution. \$\endgroup\$Jordan– Jordan2022年10月05日 14:46:30 +00:00Commented Oct 5, 2022 at 14:46
C (clang), (削除) 54 (削除ここまで) \$\cdots\$ (削除) 37 (削除ここまで) 36 bytes
o(f(),g(),a,b){return g(f(a),f(b));}
Saved 8 bytes thanks to dingledooper!!!
Saved 2 bytes thanks to ceilingcat!!!
Saved a byte thanks to jdt!!!
-
\$\begingroup\$ 39 bytes \$\endgroup\$dingledooper– dingledooper2021年04月20日 00:56:52 +00:00Commented Apr 20, 2021 at 0:56
-
\$\begingroup\$ @dingledooper Nice - thanks! :D \$\endgroup\$Noodle9– Noodle92021年04月20日 01:12:24 +00:00Commented Apr 20, 2021 at 1:12
-
\$\begingroup\$ @ceilingcat Nice one - thanks! :D \$\endgroup\$Noodle9– Noodle92021年04月20日 09:50:08 +00:00Commented Apr 20, 2021 at 9:50
-
Vyxal, (削除) 8 (削除ここまで) 3 bytes
M$R
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
Red, 24 bytes
func[f g x y][g f x f y]
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:
TIO compatible version, 28 bytes
func[f g x y][do[g f x f y]]
Husk, (削除) 5 (削除ここまで) 4 bytes
2101
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.
2101 # 2 argument function: second argument is implicit
1 # perform function 1 using second argument
10 # perform function 1 using first argument
2 # perform function 2 using the last 2 values as arguments
-
\$\begingroup\$ I'm sure you can use F instead of Ẋ to return a value instead of an array. \$\endgroup\$Razetime– Razetime2021年04月20日 07:25:09 +00:00Commented Apr 20, 2021 at 7:25
-
\$\begingroup\$ @Razetime - Yes, you're right, that's much better. Thanks! \$\endgroup\$Dominic van Essen– Dominic van Essen2021年04月20日 09:40:46 +00:00Commented Apr 20, 2021 at 9:40
Attache, 10 bytes
${z|x|>&y}
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
`#:
Simple quote-operator. Called as (`#:)[g, f][a, b].
Stacked, 11 bytes
[@:g"!...g]
Simple anonymous function. Takes input on stack as (a b) f g.
Works by storing g as a temporary function variable. Then, applies the " transformation on function f, which makes it apply on each element its called on. ! calls this function f" on the tuple (a b). Then, we simply put these two elements on the stack and call g.
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.
-
1\$\begingroup\$
fn(f,g)=>g o map fif you use lists, but I haven’t counted to see if it’s actually shorter. Also with a tuple you can dog(f a,f b)which is certainly one shorter. \$\endgroup\$D. Ben Knoble– D. Ben Knoble2021年04月21日 22:22:28 +00:00Commented Apr 21, 2021 at 22:22
Explore related questions
See similar questions with these tags.
a&bas an array[a,b]? \$\endgroup\$