In lines 149-188, I implement the eight brainfuck operations as state-transforming operations.
The question is: Is it okay to make one type for which I implement ALL the functionality, or am I better off splitting it into two types and duplicating the code for the shared instructions (most are shared)? Is there a idiomatic way to have types "inherit" from other types? For example, the operation "increment byte at pointer" is only needed for the data tape, while "seek next matching bracket" is only needed for the instruction tape (Lines 1-100). The functionality of the two tapes overlap, but not completely. I use this type for both the data tape and the brainfuck program itself, the instruction tape. I made a type Tape with a pointer which can be shifted and read from / written to. In particular, I am unsure about the following points:
The goal is to afterwards use StateT instead of State and combine that with IO, so that I properly learn to use monad transformers. This implementation is lacking any IO, because I wanted to create a simple, baseline implementation of stateful computation. But I am sure there are many more eyes on which I am blind, so please point out where I go wrong or miss more elegant solutions. It was eye-opening in some regards, because I finally used and designed monadic operations by myself. This project is a brainfuck interpreter, for which I used nothing but the wiki article on brainfuck (i.e., no foreign design or code, apart from whileM). In my previous project, I made a JSON parser, but relied heavily on guidance from a university course.