Happily! https://lisp-lang.org/
At risk of stereotyping myself, if you like this kind of thing, check out SICP. It is a really good dive into exactly how far you can go with this kind of tool, and also has applicability across the engineering discipline (not just for lisp folks).
Representing code as data is not very interesting IMO. Code is code, data is data. Granted both are stored in RAM, but they are very different beasts considering how they flow through the machine. Almost any language allows to parameterize over functions (e.g. function pointers), but there is no need to make closures a first class citizen. After all, closures are a brutal abstraction, isolating any context from the caller. When overdone this ends up in a terrible mess where you don't know what's happening anymore (otherwise known as callback hell). Conclusion, use this only as a last resort.
So you can't abstract over data types in C? I often do. Some random thing I often do:
(Anybody objecting they don't like macros and this is not a real abstraction: You are all fools. To a certain point, that is - before you possibly start being right. But don't underestimate how far this can go, and how long this can be a superior solution over alternatives.)You know something that is very hard to abstract over? Programming language FEATURES! Anybody, please show me the ways of doing computation over all the data that was encoded as fancy programming language syntax. This requires even more language features to get this data back from the compiler in some weird form... if possible at all.