Counting matrix elements that have "4" or "5" as a neighbor
This is how you could write your code efficiently in base R:

offset &lt;- function(x, v_offset = 0L, h_offset = 0L) {
   stopifnot(h_offset %in% -1:1, v_offset %in% -1:1)
   nr &lt;- nrow(x)
   nc &lt;- ncol(x)
   if (h_offset == +1L) x &lt;- cbind(x[, -1], -99L)
   if (h_offset == -1L) x &lt;- cbind(-99L, x[, -nc])
   if (v_offset == +1L) x &lt;- rbind(x[-1, ], -99L)
   if (v_offset == -1L) x &lt;- rbind(-99L, x[-nr, ])
   x
}

getNeighbours &lt;- function(x, functionof) {
   v_offsets &lt;- c(-1, -1, -1,  0,  0, +1, +1, +1)
   h_offsets &lt;- c(-1,  0, +1, -1, +1, -1,  0, +1)
   neigh_x   &lt;- Map(offset, list(x), v_offsets, h_offsets)
   kc   &lt;- Reduce(`+`, Map(function(x) x == 4L, neigh_x))
   ks   &lt;- Reduce(`+`, Map(function(x) x == 5L, neigh_x))
   kpre &lt;- 0
   functionof(kc, ks, kpre)
}


It builds a list (neigh_x) of eight matrices in memory, one for each neighboring position. Instead of four loops, you are down to a single loop (8 iterations) wherever you see Map or Reduce, everything else uses vectorized operations.

Testing the code:

health &lt;- matrix(1, 5, 5)
health[1, 1] &lt;- 4
test_fun &lt;- function(kc, ks, kpre) 2 * (kc + ks + kpre)

getNeighbours(health, functionof = test_fun)
#      [,1] [,2] [,3] [,4] [,5]
# [1,]    0    2    0    0    0
# [2,]    2    2    0    0    0
# [3,]    0    0    0    0    0
# [4,]    0    0    0    0    0
# [5,]    0    0    0    0    0