Sounds pretty straightforward. This is a normal way of working in functional languages: you write your business logic in a high-level representation (aka an "embedded DSL") and a succession of interpreters that interpret slightly higher-level representations into slightly lower-level representations, until you get down to one that you can implement directly. It's a nice structure for testing because you can test each interpreter separately on each of its instructions and then the composition behaviour is guaranteed.