Fork me on GitHub

@misha The obvious solution is a "seen" map


and only put the fields you want to compare into the elements of that map


generally though, are you just doing a search?


not exactly. There is a complication of time, where state is "the same", but time (since game start) is not. Which is kind a problem for your line 92. The goal is not to do search from start state for every query. the goal is to generate all possible states for a certain time period from the initial state, and then search through those. then, since there is a bunch of those states (millions per second after some point in time) – i'd like to parallelize it too. And it is a problem for your "doseq" on line 93 part. Then, the "searching" is typically like this: - what is the earliest state/time I can have this unit/upgrade/building, and - what are steps that led to it. (tracing it back to the initial state)


if so, this might be useful


there are def. libraries and whatnot that are better examples and actually tested


you can start from a "starting game state" and go forwards from there

Alan Thompson04:10:45

Good article on how one can "discover" lisp:

Александр Стоянов06:10:15

Hello! I have some bug: (go (def row (:body (<! (http/get ""))))) (def clean (subs row 1 (s/index-of row (last row)))) (hash-map clean) It returns {} in clean some data like :id 1, :name "Ab Bc Cd", :sex "M", :birth "01.01.1999", :address "Street 1", :oms "0001" and when i put this data in hash-map: (hash-map :id 1, :name "Ab Bc Cd", :sex "M", :birth "01.01.1999", :address "Street 1", :oms "0001") It works. But why and how can i fix it?


Not sure what's going on in your code. First of all, (hash-map clean) would immediately fail in Clojure, no matter what the value of clean is because hash-map expects either no arguments or an even number of arguments. So you must be using ClojureScript. Second of all, you're assigning the result of subs to clean. subs returns a string. You cannot magically turn a string into data without explicitly converting it. If you want to read EDN strings, just use clojure.edn/read-string.

Александр Стоянов22:10:48

It's in cljs but i did think there's no difference so i wrote in this channel


Either way, you have to read that EDN string first.


hello. I'm looking for something which behaves like an Atom, but which records a stat like 'number of tries per successful update' - anyone know of such an impl?


@borkdude cheers yeah I've been thinking of doing that ... just being lazy!


I have issues with I am getting "Unexpected character: C". How do I find out what's causing this? The input file is a tsv file and I've told data.csv to use \tab as separator.

Alex Miller (Clojure team)14:10:24

read-csv will give you a lazy sequence - if you read that line by line (with loop/recur), you should be able to count lines and print or try/catch around the body to determine where the bad data is

Hayden Sartoris15:10:22

Anyone experienced issues involving, threading, and try? The following causes Can't set!: *current-length* from non-binding thread :

(defmethod d/create! :impl/ad
  [ad-inst complex-user ad-user]
  (log/trace ad-user) ; fine
    (log/trace ad-user) ; not fine
    ; etc

Hayden Sartoris15:10:16

Method is being called from pmap

Hayden Sartoris15:10:02

Exception is thrown from within clojure.pprint


@hsartoris Could it be a laziness issue?


my guess would be this is an async issue.

Hayden Sartoris15:10:17

Actually I have to amend, the try likely has nothing to do with it; can only consistently repro with log/spy


pmap does return a lazy sequence, and there are dynamic vars that affect clojure.pprint's behavior. I haven't checked, but wouldn't be completely surprised if clojure.pprint's implementation attempts to set! one or more dynamic vars in its implementation.


Just checked, and there definitely are a couple of set! calls within pprint's implementation.


@hsartoris You could try (doall (pmap ..)) to see if it's laziness causing this

Hayden Sartoris15:10:51

Thanks! I guess the dice have just fallen in favor of not breaking for the previous iterations... weird

Ben Sless17:10:02

@hsartoris in general, be wary of mixing side effects with laziness. You'll get surprises


But it is fairly common when someone is debugging issues with laziness and side effects, debug print/log statements are a common way to do that. In this case, it is an extra bit of surprise that the function that was attempted to be used for printing, pprint, has inside of itself some implementation details that don't mix with laziness, more so than if one tried to use println instead.


Agreed on the general recommendation you gave.

Ben Sless17:10:09

Would it be correct to say dynamic bindings are a form of side effects? You're reading from an impure environment instead of writing to it (the classic example)


dynamic vars are global mutable variables that don't combine well with the mathematical concepts of FP like laziness and purity


I worked on an application once that had a dynamic var for the Datomic db value (as of a certain date, defaulting to today). This caused tremendous confusion in combation with laziness. I refactored the entire codebase to take a db argument instead.

💪 3

This was before component was a thing. Currently I work on an app where lots of functions take the system as an argument. Nice to see how things evolved during the years ;)


I have an interest in this area of Clojure software design. I could find very few write ups on the topic, and nothing in depth. According to you, should the system map contain A) as much as possible or B) as little as required ? In my app, getting passed the system map carries the implication that you are going to do something side effectful with it, like getting a record from a database. In, R. Dittwald advocates for deferring side effects to as late as possible and using as many pure functions as can. Isn't passing the system to lots of functions some kind of design smell in that context ? I'm having trouble reconciling "system map given liberally everywhere" and "use as much pure functions as possible".


They don’t seem like side effects to me. They for sure break referential transparency though

Ben Sless17:10:55

> Despite this, the fact is that we are using functional values to simulate state. There is in principle nothing to stop functional programs from passing a single extra parameter into and out of every single function in the entire system. If this extra parameter were a collection (compound value) of some kind then it could be used to simulate an arbitrarily large set of mutable variables. In effect this approach recreates a single pool of global variables — hence, even though referential transparency is maintained, ease of reasoning is lost (we still know that each function is dependent only upon its arguments, but one of them has become so large and contains irrelevant values that the benefit of this knowledge as an aid to understanding is almost nothing). This is however an extreme example and does not detract from the general power of the functional approach. Out Of The Tar Pit, 5.2.3 Kinds of State


I don't think that is the same thing though. He is talking about pure functions (no side effects) that accepts some large mutable collection.


he's not talking about a mutable collection


at least that's not how I remember the paper


yes, the mutable part doesn't matter actually.


using dynamic scope in combination with laziness doesn't exactly introduce mutation in the normal sense, but it does introduce changes in bindings that are equally spooky and unpredictable, so as @dpsutton says they break referential transparency


to me (and for many of us I think), avoiding mutation isn't the end goal, it's a means to having referential transparency

Ben Sless18:10:31

Eventually you have to mutate something, otherwise your code isn't doing anything besides heat CPU

Ben Sless18:10:12

(unless you're writing a theorem prover or something)


right, the question is whether the calculation is reified into the explicit flow of data, or spooky

🎃 3

there's a massive amount of mutability in theorem provers :)

👀 3

mutating the set of proven theorems and lemmas? largely like clojure namespaces?


nah I meant the implementation of theorem provers usually makes use of a lot of mutability internally


in order to be efficient

👍 3

I think the point of that quote from Out of the Tar Pit a few comments back is that even if you write pure functions, if one of the parameters is some big collection, e.g. a Clojure map with many key/value pairs, but any given function only examines a small fraction of them, then the fact that it is a pure function doesn't help a human much in reasoning about which part of that big collection is relevant for any given pure function. That is a kind of incidental complexity for a person who wants to reason about the code's behavior.

☝️ 6

(def zorn's-lemma ...) etc?


@andy.fingerhut that's how I understand it as well. Even more so if you pass that large collection around from function to function it complicates things even more.


It is better than reading global variables, because you know that whatever the pure function accesses is somewhere in that big collection, rather than outside of it, but it isn't localizing things very much if that collection is large.


and why I said it is different is that if a function refers to an ear-muffed variable it isn't pure at all


so it is a different case altogether


If you read a dynamic variable's value, one that is in the environment and not a parameter, then yes, to that extent you are reading global variables.


Note that pretty much every Clojure function you write depends upon the current definitions of other Clojure functions that you name inside of its body, and those are mutable variables (via def). It is just very very uncommon practice to mutate those vars, except during interactive development.


and also in this particular case we're talking about printing functions so I don't think it is claimed they are side-effect free