Fork me on GitHub
#clojure
<
2022-08-31
>
Daniel Tan05:08:18

is light table maintained?

dpsutton06:08:13

no it is no longer maintained

parrot 1
Daniel Tan09:08:41

any chance theres a semi maintained fork somewhere?

Skiamakhos16:08:42

What was it based on? Atom?

zimablue23:08:15

there was one guy doing a project trying to get it back to life when I checked a year ago and he has done some work but I don't know how far he got, AFAIK most of the clojure community uses emacs, cursive, calva on vscode in that order. I don't think it was based on atom: https://github.com/LightTable/LightTable/blob/develop/project.clj

stephenmhopper12:08:14

I’m working on a side project for running simulations on a fairly complex “living” card game. So far, I’ve managed to create a good foundational model for representing the state of the game in Clojure. I don’t think that modeling the basic actions in the game will be particularly difficult, but each card can potentially have text with special abilities defined. The game engine needs to read these abilities to generate potential events that might be applied to the game state. Typically, I would just write a function for each “action” and have it emit potential events to be applied. However, there’s thousands of cards in this game, so modeling each card by writing a function is tedious and error prone. So I’m planning on just representing all of the abilities as data structures and then writing functions that can interpret those structures. This should allow me to write property based tests up front for the core functions instead of doing it for every single card’s action function. Anyhow, I’m looking for materials / inspiration on what this common data structure should look like. Does anyone have any recommendations on resources (GitHub projects, books, papers, talks, etc) that would be relevant here?

Daniel Tan12:08:32

what I did instead is to break down card actions into individual reusable effects which are sequenced into a game state reducer that also generates the effect sequence into the game state map

stephenmhopper13:08:15

Interesting. What else can you tell me about this project?

stephenmhopper13:08:25

It’s dawned on me that I should use some flavor of Datalog for this project. I’m going to rewrite the underlying state to use a Datalog DB and then revisit the event / action model. So much of this game revolves around querying the state of the game for very specific cards (or a set of very specific cards). So my model of actions will likely involve support for arbitrary datalog queries against the game’s state.

respatialized20:08:50

It sounds like you want a rules engine. Zach Oakes, the creator of the odoyle-rules library, has a demo of creating a Diablo-like hack & slash game using it and modifying the rules on the fly to alter game behavior: https://m.youtube.com/watch?v=XONRaJJAhpA https://github.com/oakes/odoyle-rules

stephenmhopper23:08:15

Oh, I remember watching that when it first came out. I’ll review it again. Thank you!

Daniel Tan00:09:14

mine is a digital TCG with spells and what not.

Daniel Tan00:09:35

I thought of using a database for the game but just opted to use a simple map for the game state first. I also store a random seed with the game state so random events are reproducible, very useful for debugging, but needs native Java Random functions

Nikolas Pafitis13:08:41

Would it be a smart idea in fn and let destructuring to support :let similar to how for comprehension does it? That would help with nested destructuring (especially in fn forms).

p-himik13:08:40

It seems to me that people in general avoid nested destructuring because oftentimes it's more confusing than helpful.

dpsutton13:08:05

It sounds like a bad idea to me. Can you give an example where it would be helpful?

Alex Miller (Clojure team)13:08:36

I think it's better to just use a let

Nikolas Pafitis13:08:57

Admittedly it's been only a couple of times that I thought that something like this might be useful but an example would be

(defn get-handler
  [{:keys [header]
    :let [{:keys [content-type]} header]
    :as request}]
  ; Do something with request or header or content-type
  ...)

Nikolas Pafitis13:08:51

In let it's not really a problem since kind of "already have it" Mostly in function definitions. Would also kind of help in documentation on describing the shape of the input.

Nikolas Pafitis13:08:44

In the above example I know from the function's signature (it might be presented to you as a caller from your text editor/IDE), that the shape of the input would be something like

{:header {:content-type "something goes here"}}

Alex Miller (Clojure team)13:08:54

I think spec is the answer to that and may become more integrated with defn in the future

Nikolas Pafitis13:08:50

@U064X3EF3 I think I agree. On a side note, I haven't been following any recent Cognitect developments. There were rumours of spec2 going around? Today I prefer using something like malli because of it's edn/data nature, but I'd like to have something more ubiquitous. What's in the pipeline for spec?

Joshua Suskalo14:08:34

for this specific case you can already do this @U0105D1EL4B

(fn [{{:keys [content-type] :as header} :header
      :as request}]
  ...)

👆 3
quoll19:08:18

The only impediment is that you can’t “nest” structures if you try to pull part of the path out with :keys. All parts of the path must be explicitly pulled out. So if you have a structure of {:a 1 :b 2 :c {:d 3}} then you can get to :a, :b and :c with :keys but if you want to get to :d then you have to pull :c out separately and explicitly:

(let [{:keys [a b c] {:keys [d]} :c} {:a 1 :b 2 :c {:d 3}}]
  [a b c d])

[1 2 {:d 3} 3]

🙌 2
quoll19:08:01

The above pulls out and binds c before it pulls it out to destructure for d. @U5NCUG8NR’s approach should only pull it out a single time, and then destructure the value bound the c

🙌 2
quoll19:08:31

(more explicitly, Joshua’s method calls get on the map once, and mine calls it twice)

🙌 2
erwinrooijakkers20:08:17

what is the purpose of the zero-arity of a transducer? e.g., for map:

(fn [rf]
 (fn
  ([] (rf))
  ([result] (rf result))
  ([result input]
   (rf result (f input)))
  ([result input & inputs]
   (rf result (apply f input inputs)))))
it there an example where it is called?

Joshua Suskalo20:08:40

It's called in contexts where the transducer context doesn't provide an init value to the reducing function, but one is required.

Joshua Suskalo20:08:46

e.g. if you manually apply a transducer to a reducing function before passing to clojure.core.reducers/reduce, you expect to see the 0-arity be called.

zimablue23:08:50

there are some great blogs on this, if you google "these aren't the transducers you're looking for". There's also some nice footguns/inconsistencies between (reduce) and (transduce) I think

Joshua Suskalo23:08:06

can you link the article you're referring to? I can find none by that name.

zimablue23:08:44

just realized that I'd kind of reinvented tap> add-tapin my cljs codebase, I don't have a question I just had to tell someone. I'd never gotten around to understanding taps till now, I thought they were fundamentally related to channels but they're not, it's misleading because async/tap is channels but tap>, add-tap are unrelated to channels AFAIK

zimablue23:08:40

it's simpler and arguably less useful in cljs because I think a big advantage of the clj one is performance, with a dedicated thread and java queue