If you pass an expression such as K-1 as an argument to a predicate in prolog, prolog does not evaluate the expression as in other languages. It's passed as the term '-'(K,1) with K instantiated as indicated in your predicate.
So, let's suppose you queried:
element_at(X, [1,2], 2).
Then your query would match the second clause of your predicate:
element_at(X,[_|T],K) :- element_at(X,T,K-1).
And recursively query:
element_at(X, [2], 2-1).
This would match the second clause again and query:
element_at(X, [], 2-1-1).
Which will fail since it doesn't match any of your clauses.
Therefore, if you want to pass the value of an expression as an argument, you need to pre-evaluate, as you have done with K1:
K1 is K-1,
element_at(X, T, K1).
Note that you could have a deferred evaluation. For example:
foo(X, Y) :-
Y is X * 2.
| ?- X = 1, foo(X-3, Y).
X = 1
Y = -4
yes
| ?-
In this case, when foo is queried, it queries as, foo(1-3, Y). When foo executes, it executes the line: Y is X * 2 which evaluates, Y is (1-3)*2 yielding Y=-4.