3 ms·
Sometimes it's worth it, sometimes it's not. Exploratory programming is a thing. Example: Spec 1.0 update position of objects according to velocity for in
by ajuc 12y ago
Sometimes it's worth it, sometimes it's not. Exploratory programming is a thing. Example:
Spec 1.0 update position of objects according to velocity
for in imperative, map in FP
Spec 1.1 what if we made the objects that are far from the center of the group move towards the center?
for followed by for in IP, reduce and map in FP
Spec 1.2 scratch that, just remove the objects that are far from the center
for and for in IP, reduce, map, filter in FP
Spec 1.3 and spawn explosions around them
add 1 call in ip, refactoring required in fp
Spec 1.4 also they should play explosion.mp3
add another call in IP, another refactoring required in FP
Spec 1.5 this should happen for all destroyed objects
move both calls to function that removes object in IP, another refactoring (with passing a lot of state in new ways) in FP
And so on.
After you're OK with the result you can make the code nice in IP too. And you can do this once, instead of doing this every time anything changes.
It's like a text editor that forbids you to have temporarily non compiling code. Only refactorings are available, you can't write if by hand. Pain in the ass.
Yes I know about paredit, people still copy paste, and write parents by hand.
- sparkie 12y agoIt'd be nice if 1.3 and 1.4 could be done with just 1 line of call, but you're missing the fact that pretty much any graphics and audio library will have some "context" singleton through which it is called due to the way these interact with the operating system. The APIs are deliberately designed this way to encapsulate the global state they use. Sure you can make a global variable for the context and avoid passing it around - but the refactoring route is the preferred option in the imperative world anyway. If you're writing in Haskell with any expectation of using IO for some exploratory programming like this, the obvious solution is to make your functions of type (:: MonadIO m => ... -> m ...), then any refactoring you need to do to add additional facets to your state can be specified elsewhere as part of a MonadIO transformer. Your calls to "play explosion.mp3" and "render explosion" just need a liftIO on them.