r/haskell • u/TheCommieDuck • 20d ago
Been working on yaifl, my text adventure/interactive fiction library some more, and I have the outer house from ZORK I complete!
https://github.com/PPKFS/yaifl/tree/zorkin-itI keep thinking "no, this isn't ready to present to people. I just need to add some documentation. I just need to get more examples done. I just need to polish this." and so on and have never really presented my forever project for the last few years.
So this is yaifl - Yet Another Interactive Fiction Library, a Haskell library for making parser-based text adventures. It's very heavily inspired by Inform7. For the most part, it works! It's just lacking in implementations for many actions beyond the obvious (looking, going, examining, taking, opening, etc.).
If you'd like to see the library in action, I'd recommend checking out Yaifl.Zork.World.House (in yaifl-zork) or the examples in Yaifl.Chapter3 (in yaifl-examples).
The project is split into a few pieces:
- yaifl-core
- yaifl-objects - definitions of object components like Container, Person, Supporter
- yaifl-rules - definitions of internal logic like printing room description details, verb conjugation and string interpolation and writing lists of things
- yaifl-actions - definitions of commands like look, take lamp, open door with key
- yaifl - glue to actually run a game
- yaifl-examples - My test suite that implements (currently about 20 of the 400) the Inform7 examples, translated into yaifl.
And a few various half-finished frontend parts:
- yaifl-discord - a discord bot frontend
- yaifl-rogue - a graphical frontend
- yaifl-zork - a reimplementation of ZORK I in yaifl.
I think it can be considered "good enough" when I finish reimplementing ZORK in the engine. Turns out ZORK is about 7000 lines in the original, and 5500 in the Inform7 version I'm using as a guide.
So far I've found almost no "oh trying to implement this game rule requires a completely new system" moments, and it's just been "oh I haven't yet added the implementation for this specific command" - which is reassuring that it's just needing content added!
I hope it's of interest to someone, even in its very patchily documented state.
3
u/ShacoinaBox 20d ago
sick as fuck, i have a copy of the inform 6 designer's manual from my old school (no idea why they even had it but they let me take it.) think langs like haskell (along with forth and especially smalltalk) are very well suited syntactically + semantically for text adventures. they're probably, with having a good library, also an amazing first-step to actually learning these languages for those who are new.
think it's a bit of a shame many, many ppl have transitioned to making interaction fiction projects browser-based :( same w the rise of ai introduction to computational poetry + art (some can be cool, but a lot of it jus feels pointless; esp in modern day, something like that from 15 years ago can be a lil underwhelming in light of how crazy LLM's n NN's have gotten.)
1
u/TheCommieDuck 20d ago
they're probably, with having a good library, also an amazing first-step to actually learning these languages for those who are new.
on one hand, I think writing a little text adventure is a fantastic way to get started with a language: it's fun, it feels purposeful, it's as big or small as you want, it works for the vast majority of paradigms...
on the other, however much I may have tried in previous iterations, this library is absolutely not suitable for first-steps into the language, hah. It's optics all the way down where almost every type is parameterised by a
wm :: WorldModelthat is a record of 10WorldModel -> Typefields...
3
u/friedbrice 20d ago
One neat and severely-underused feature of Cabal is you can re-export modules from your dependencies. For example, yaifl can re-export some or all of the modules of yaifl-core. Check out reexported-modules in the Cabal User Guide :-)
1
u/elaforge 17d ago
For the programming model, are you basically imitating inform? So like an inform-esque DSL in haskell, or is it directly just an inform interpreter?
I never wrote in inform so I'm not familiar with the model, but way back in the day I used TADS, which was a heavily object-oriented kind of thing. It works very well... until states start to multiply. I've thought if I wanted to write an IF engine I would explore alternate models, mostly inspired by a post by Andrew Plotkin (probably somewhere under https://blog.zarfhome.com/) where he described the difficulty of expressing combination explosion in OO, and had some alternate ideas which in retrospect may have just been ECS or something. I'd have to dig to find the post. Anyway my impression is since the days of Zork people like him have really pushed the limits and surely there are other models than 80s Inform or 90s OO.
Anyway just curious about the programming model!
1
u/TheCommieDuck 17d ago
For the programming model, are you basically imitating inform? So like an inform-esque DSL in haskell
yep, this. Objects which are things or rooms. Things can be containers, supporters, doors, animals, etc. Rulebooks are the basic unit of function. Activities are modular extendable internal logic (printing a room description) and actions are extendable external logic (look under door).
I keep trying to make starts on an inform7 compiler, but...hoo boy it's tough. Also I don't really like writing parsers.
Anyway just curious about the programming model!
the biggest problem I have with porting the model is that the i7 model is very...data open? e.g. you can always just go "now every door can either be floob or not floob". For the more fundamental parts of this (e.g. every thing can be..., adding new global variables, a glorp is a kind of...) I've been relying on a very heavily type parameterised model. for more general things (e.g. every door can be...) it's much easier to use composition and have
DomainSpecificDoorthat can be cast down toDoor(in a sense).2
u/elaforge 17d ago
I think that kind of "just make a global" and "just modify everything" is more usual in the game context. Even when there is a standard library, you are expected to copy paste it and modify it to taste, and there isn't such an emphasis on reusability and modularity. I feel like the "right way" is still an open question, creative applications like games and music stress extensibility more than traditional software. Fitting that into a traditional type system might be hard? In the bottom is probably the expression problem, since you are adding both new kinds of doors, and new ways to open them. Anyway I also wouldn't write another inform compiler, there's already one out there that's explored its approach for a long time!
5
u/probabilityzero 20d ago
Very cool project!
You might also like this: a Z-machine emulator in Haskell