1. I think "avoid globals" is a reasonable way into FP, but FP itself involves a lot more than just avoiding coupling via global state. I would say the main components are
- nested definitions;
- lexical scoping;
- first class functions;
- static typing; and
- a whole bunch of programming techniques (e.g. monads) that have grown around them.
2. You certainly can use FP ideas in low-level programming but you'll have difficulty finding a FP language that targets your hardware. There are a few small Scheme implementations that might work. Rust is viable if we're talking 32-bit CPUs, not 8-bit.
(I imagine the Rust developers would not claim Rust is a functional language, but it has absorbed a great many ideas from functional languages. I prefer to talk about modern programming languages instead of functional programming languages. Rust, Haskell, and Scala are all modern and have many features in common. Only Haskell claims to be a pure FP language though.)
I will discuss Haskell, since I am not very familiar with other FP languages. In Haskell static typing is more useful than in other languages. This is because in Haskell the type signature of a function gives an upper bound of what the function does. In an impure language, a function may change any accessible mutable values and/or perform IO. These possible side effects mean that in an impure language the type of a function is a very weak indicator of what the function actually does.
A lot of the action in modern programming languages is in type systems. Static typing is synonymous with the dominant group of programming languages that subscribe to the "functional" label. There are other languages, such as Scheme, that are not statically typed that also subscribe to this label but they don't have the same mindshare at present.
It's important to keep in mind that FP does not name some formally defined concept like the number 3 or the function cos. Rather it's a name given to a group of people and programming languages that share a common ancestry and world view. The definition is fuzzy and can be split many ways.
- nested definitions;
- lexical scoping;
- first class functions;
- static typing; and
- a whole bunch of programming techniques (e.g. monads) that have grown around them.
2. You certainly can use FP ideas in low-level programming but you'll have difficulty finding a FP language that targets your hardware. There are a few small Scheme implementations that might work. Rust is viable if we're talking 32-bit CPUs, not 8-bit.
(I imagine the Rust developers would not claim Rust is a functional language, but it has absorbed a great many ideas from functional languages. I prefer to talk about modern programming languages instead of functional programming languages. Rust, Haskell, and Scala are all modern and have many features in common. Only Haskell claims to be a pure FP language though.)