If you are only going to use this for learning then you do not really need any inputs/outputs or analogues to learn basics of coding only for real world applications like actually controlling actual peripherals.
Most programmers simulate the programs so do not actually use the real I/O. for example the pdf I posted, if you disabled the read analogue input and just used the variable that it would normally move the data to i.e. 0-4000 in the case of the FX2N, then you can write temporary code to simulate the analogue input going up & down using a timer to increment the variable.
So in effect white the logic & simulate the I/O with internal bits. I agree that being able to have things move in the real world is better but to learn the basics of programming the real I/O is not required.
Most programming IDE's for OLC's now have simulators built in, although some have some simple programming to simulate real I/O I still prefer to create my own I/O simulation even within the simulator. Certain function do not work i.e. simulation of special cards like analogues, motion or communications.
What I tend to do is create an input/output program which maps the inputs into internal bits and maps internal bits to the outputs, also include any analogue processing but not call this block(s), then use the mapped bits/words in the program, this way you also create a simulation program block, this simulates the I/O and analogues, when tested, remove the simulation blocks & re-instate the mapping to the real I/O.