Distributing a list of heads over a list of arguments

Given two lists, one for the heads another for their arguments

heads = {f, g, h, k};
arguments = {w, x, y, z};

is there less clumsy way to do this?

In[1]:= Diagonal[Through /@ Distribute[heads[arguments], List]]
Out[1]= {f[w], g[x], h[y], k[z]}

Perhaps

MapThread[Compose, {heads, arguments}]

Compose is currently superseded by composition, but that works slightly different, so another solution is:

MapThread[#1@#2 &, {heads,arguments}]
In[1]:= Inner[#1[#2] &, heads, arguments, List]
Out[1]= {f[w], g[x], h[y], k[z]}

Sander Huisman, - this would be my solution as well.

Some more just for fun

(*   Clearly that? is a transpose symbol *)
{heads, arguments}?/. {f_, a_} :> f@a

(* Listability is *always* good *)
Attributes[headThread] = {Listable};
headThread[f_, a_] := f@a;
headThread[heads, arguments]

(* .. especially in pure functions *)
Function[, #1@#2, {Listable}][heads, arguments]

No worries, but for the inconvenience you have to suffer reading this code, in the category:
Way clumsier

result = {};
For[
  i = 1,
  i <= Max[Length /@ {heads, arguments}],
  i += Length[IntegerPartitions[i]]/PartitionsP[i],
  AppendTo[result, heads[[i]][arguments[[i]]]]
  ];
result

@Simon Schmidt - Wow this is a real fun one :wink: +1 !

Dot[heads, arguments] /. Times -> (Operate[##, 0] &)

Nice, but the Operate is slightly heavy handed. I think the following is both shorter and easier to understand:

In[7]:= Dot[heads, arguments] /. Times -> (#1[#2] &)

Out[7]= f[w] + g[x] + h[y] + k[z]

Of course, this will break if one of the arguments has head Times.

arguments = {w, x, y, z b};

In[18]:= Dot[heads, arguments] /. Times -> (Operate[##, 0] &)

During evaluation of In[18]:= Operate::argt: Operate called with 4 arguments; 2 or 3 arguments are expected. >>

Out[18]= f[w] + g[x] + h[y] + Operate[b, k, z, 0]

In[19]:= Dot[heads, arguments] /. Times -> (#1[#2] &)

Out[19]= b[k] + f[w] + g[x] + h[y]

In[7]:= Dot[heads, arguments] /. Times → (#1[#2] &)

Out[7]= f + g + h + k

Of course, this will break if one of the arguments has head Times.

And while it’s frequently safer to use Replace at a specific level is rather than ReplaceAll (/.) in code, even that won’t help you in this case. That’s probably why Dan’s answer used Inner instead of Dot.

Compose@@@Thread@{heads, arguments}
 #[[1]][#[[2]]] & /@ Transpose[{heads, arguments}]