Functional programming techniques have been used to describe synchronous digital circuits since the early 1980s. Here we survey the systems and formal underpinnings that constitute this tradition. We situate these techniques with respect to other formal methods for hardware design and discuss the work yet to be done.Hardware designs traverse a series of abstraction layers: what might begin as a highlevel behavioural model that addresses architectural issues will, when mature, typically be manually translated into a Register-Transfer Level (RTL) description that captures how the high-level computations are performed by the finite-state means of logic gates and memories. This is typically validated against the original model using simulation and testing, or more formally with model-checking techniques or a proof assistant. The resulting netlists (circuit schematics represented as graphs) are semiautomatically mapped to an implementation technology and laid out for realisation in silicon.The original motivation for developing Domain-Specific Languages (DSLs) [Mernik et al. 2005] for the upper reaches of this process was to harness the huge increases in transistor densities on silicon chips forecast by Moore's law [Mead and Conway 1980]. It was hoped that productivity would rise with the abstraction level, yielding designs that were more reusable, scalable, and correct. Traditional imperative programming languages were a poor fit, as their implicit sequentiality conflicts with the intrinsic parallelism of hardware, and a global store is in tension with the ideal of placing computations physically near the relevant state [Nikhil 2011]. For these reasons, I thank