2015-07-04
| 00:22 | turbofail | finally taking the plunge back into cljs-land |
| 00:22 | turbofail | it's been a while |
| 00:23 | vas | Committee on the Jewish Law and Standards? :P |
| 00:24 | turbofail | i think you transposed some letters |
| 00:24 | turbofail | unless it's one of those reordered french initialisms |
| 00:25 | vas | it must be. first result on duckduckgo when i searched "cljs" |
| 00:29 | vas | Would you recommend cljs over clj for a dynamic web application? |
| 00:32 | turbofail | eh? i would normally use both |
| 00:32 | turbofail | cljs for the front-end, clj for the backend |
| 00:33 | turbofail | i suppose you could use node.js on the server end but i'd generally prefer JVM clojure when available |
| 01:43 | zematis | I'm trying to get sum the values of :key in [{:key 57 :other-key 72} {:key 27} ...]. Any suggestions? |
| 01:44 | tatut | ,(reduce + (map :key [{:key 1} {:key 10}])) |
| 01:45 | clojurebot | 11 |
| 01:46 | TEttinger | ,(reduce + (map :key [{:key 1} {:key 10} {}])) |
| 01:46 | clojurebot | #error {\n :cause nil\n :via\n [{:type java.lang.NullPointerException\n :message nil\n :at [clojure.lang.Numbers ops "Numbers.java" 1013]}]\n :trace\n [[clojure.lang.Numbers ops "Numbers.java" 1013]\n [clojure.lang.Numbers add "Numbers.java" 128]\n [clojure.core$_PLUS_ invoke "core.clj" 955]\n [clojure.lang.ArrayChunk reduce "ArrayChunk.java" 63]\n [clojure.core.protocols$fn__6514 invoke "... |
| 01:46 | TEttinger | ,(reduce + (remove nil? (map :key [{:key 1} {:key 10} {}]))) |
| 01:46 | clojurebot | 11 |
| 01:46 | TEttinger | good suggestion though, tatut |
| 01:46 | TEttinger | (inc tatut) |
| 01:46 | lazybot | ⇒ 1 |
| 01:47 | zematis | Thanks. Just learning functional programming now :) |
| 01:47 | TEttinger | it's a great fit for a lot of problems |
| 01:47 | TEttinger | a lot of people (including me at first) have a hard time adapting to not mutating stuff all the time |
| 01:48 | zematis | I'm having fun. Should probably be learning java more deeply first for my career, but it's not as interesting. |
| 01:48 | TEttinger | it eventually becomes second nature though. learning java at the same time as clojure could be interesting, but they both can use java libs! |
| 01:49 | tatut | the problem statement said nothing about :key potentially missing! ;) |
| 01:49 | zematis | Yep. That's one of the things that led me here instead of haskell. |
| 01:49 | zematis | tatut: It shouldn't be in my use case |
| 01:50 | TEttinger | I've definitely gotten used to switching languages a lot. contributing to a java lib, writing abhorrent C# for asset processing for a game, writing clojure snippets to solve what would be ugly tasks in those languages (in a fraction of the code, usually), lua a lot lately |
| 01:52 | TEttinger | I've noticed that the only thing that really trips me up is whether I need semicolons at the end of a line or not when I switch from lua or perl to java or C# |
| 01:53 | TEttinger | lisp-style code doesn't have this problem :) |
| 01:53 | kungi | TEttinger: The last time I switched to lua I immediatly got stumped by its "data structure" |
| 01:53 | zematis | I've noticed that problem too. Whenever I move from C/Java to python my lines end up with semicolons at the end for the first few minutes. |
| 01:53 | TEttinger | kungi, yeah the table is interesting |
| 01:54 | TEttinger | metatables are very handy, writing a lib that uses them now |
| 03:51 | Pupeno | I'm proud of my tic-tac-toe solution. It's the first time I feel I was *thinking in Clojure*: https://www.refheap.com/105203 |
| 04:48 | TEttinger | nice Pupeno |
| 11:12 | biellls | Hi everyone |
| 11:12 | biellls | Does anyone know why (class 'true) returns Java.lang.boolean instead of symbol? |
| 11:13 | biellls | ,(class 'true) |
| 11:13 | clojurebot | java.lang.Boolean |
| 11:13 | biellls | ,(class 'somename) |
| 11:13 | clojurebot | clojure.lang.Symbol |
| 11:13 | justin_smith | ,(class '1) |
| 11:13 | clojurebot | java.lang.Long |
| 11:13 | justin_smith | ,(class ':foo) |
| 11:13 | clojurebot | clojure.lang.Keyword |
| 11:13 | justin_smith | ,(class '[]) |
| 11:13 | clojurebot | clojure.lang.PersistentVector |
| 11:14 | justin_smith | there must be a reader specifically for true (and it makes sense that there would be) |
| 11:15 | biellls | It's just that I've been trying to port the scheme metacircular evaluator in SICP, and this makes some things not work |
| 11:16 | biellls | I wondered if there was a good reason why it's implemented like this |
| 11:17 | justin_smith | biellls: self evaluating things in clojure evaluate to themselves when quoted. There's a consistency to that. |
| 11:17 | dnolen | biellis: ' doesn't create symbols, it's just quoting |
| 11:17 | justin_smith | oh yeah |
| 11:17 | dnolen | if '(1 2 3) produced symbols that would be pretty useless |
| 11:17 | justin_smith | ,((juxt identity type) (symbol "true")) |
| 11:17 | clojurebot | [true clojure.lang.Symbol] |
| 11:18 | biellls | True |
| 11:18 | biellls | I just thought that quote meant that it wouldn't be evaluated |
| 11:19 | justin_smith | biellls: that's why I mentioned readers |
| 11:19 | dnolen | biellls: except some things self-evaluate, pretty sure this is the case for Scheme as well |
| 11:19 | justin_smith | reading and evaluating are separate |
| 11:20 | Bronsa | biellls: it's not evaluated indeed. it's read as a symbol |
| 11:20 | Bronsa | ,(class (read-string "true")) |
| 11:20 | clojurebot | java.lang.Boolean |
| 11:20 | Bronsa | err, i meant as a boolean |
| 11:21 | Bronsa | biellls: as you can see, in the expression `(quote true)`, `true` is already a bool at read-time. just as 1 is a number and :foo a keyword |
| 11:21 | biellls | In a scheme repl 'true returns 'true |
| 11:21 | Bronsa | same applies for nil and false |
| 11:22 | biellls | OK thanks |
| 11:22 | justin_smith | biellls: what about '#t |
| 11:22 | justin_smith | true isn't special in scheme is it? |
| 11:22 | dnolen | biellls: (eq? '#t #t) => #t |
| 11:22 | dnolen | Just tested this in Petite Chez Scheme |
| 11:22 | biellls | You're right, '#t evaluates to #t |
| 11:23 | dnolen | same for (eq? '1 1) => #t |
| 11:24 | Bronsa | biellls: and it's the same in cl, t is equal to 't, nil is equal to 'nil |
| 11:24 | biellls | I guess that's the difference then, true isn't special in scheme and it is in clojure |
| 11:24 | Bronsa | biellls: but #t is special in scheme and is not in clojure. they just have different representations |
| 11:26 | biellls | I guess the only way around is to rename true and false to something else in my evaluator |
| 11:27 | justin_smith | why not #t and #f - there's a nice symmetry to that |
| 11:27 | dnolen | biellls: note SICP likely used true and false because they *couldn't* use #t and #f |
| 11:27 | dnolen | biellls: but you *can* |
| 11:27 | biellls | ,'#t |
| 11:27 | clojurebot | #<RuntimeException java.lang.RuntimeException: EOF while reading> |
| 11:28 | biellls | It throws an exception In my repl |
| 11:28 | justin_smith | oh, maybe not, :( |
| 11:28 | biellls | haha |
| 11:28 | dnolen | biellls: er, sorry # is a reader thing |
| 11:28 | Bronsa | biellls: yeah you can't use the clojure reader for that |
| 11:28 | dnolen | biellls: in core.logic I ended up using t# and f# I think in the early days. |
| 11:28 | Bronsa | dnolen: that's going to be weird with ` |
| 11:29 | dnolen | Bronsa: yeah in my case it didn't matter much. I don't remember enough about the metacircular evaluator chapter in SICP whether it matters much |
| 11:29 | dnolen | Bronsa: pretty sure it doesn't, they don't use splicing in quoted forms. |
| 11:30 | biellls | dnolen: Good point about using true and false because they couldn't use #t and #f, I hadn't thought about that |
| 11:31 | biellls | I should implement a lisp reader sometime to better understand how they work |
| 11:34 | Bronsa | biellls: oh, do so, you can write one in just a hundred-ish lines of code |
| 11:34 | Bronsa | assuming you just want s-exps and not the fancy clojure extensions on top of it |
| 11:37 | biellls | I will do it when I finish SICP (if it's not part of the book) |
| 11:37 | biellls | Thanks justin_smith dnolen and bronsa |
| 11:47 | biellls | I'd like to ask an unrelated question about something I've been thinking about doing, but I don't know if it's a good idea |
| 11:47 | tmtwd | in lein repl I'm doing (load-file "bob_test.clj") and it doesn't work |
| 11:48 | tmtwd | file not found exception |
| 11:49 | tmtwd | nvm |
| 11:49 | tmtwd | fixed it |
| 11:49 | biellls | Usually clojure is fast enough, but sometimes you need speed that is close to java, and optimized clojure is not pretty |
| 11:51 | biellls | But we don't really like working in java |
| 11:52 | biellls | I was thinking of making a language that is similar to C in syntax and compiles to Java or JVM byte code and has syntactic sugar to make working with clojure data structures and calling clojure functions easier |
| 11:53 | luxbock | isn't Java a language that has syntax similar to C and compiles down to JVM byte code? |
| 11:54 | biellls | Yes, but with similar to C I also meant not OO |
| 11:57 | justin_smith | biellls: but OO isn't a syntax |
| 11:57 | justin_smith | oh, "also", missed that, sorry |
| 12:00 | biellls | I didn't explain myself well |
| 12:01 | biellls | But check a hello world in C and Java to see what I meant |
| 12:03 | biellls | Also, it would make it easier to manipulate clojure data structures |
| 12:03 | biellls | And call clojure functions |
| 12:06 | biellls | My motivation was partly because I read somewhere that making a mixed clojure and java project was a painful experience |
| 12:07 | biellls | I haven't tried it yet, so I don't know if that's accurate |
| 12:07 | justin_smith | biellls: depends which API you use I think, and the using java from clojure part is easier |
| 12:20 | biellls | ok, I will try to do a mixed java and clojure project sometime and see if I run into any difficulties. |
| 12:28 | tmtwd | how do I check the last character of a string in clojure |
| 12:28 | tmtwd | ? |
| 12:29 | luxbock | ,(last "foo") |
| 12:29 | clojurebot | \o |
| 12:30 | ringer1 | ,(last "foo") |
| 12:30 | clojurebot | \o |
| 12:30 | tmtwd | ah okay |
| 12:30 | tmtwd | how come I get this error? http://pastebin.com/8jbJUHw4 |
| 12:31 | ringer1 | very cool (first visit here and I am easily impressed) |
| 12:31 | andyf | jlast is linear time in length of string. If you want constant time access to last char, try (get s1 (dec (count s1))) |
| 12:32 | oddcully | tmtwd: :else is no function |
| 12:32 | andyf | tmtwd: You've got incorrect extra parens in your cond |
| 12:32 | tmtwd | where? |
| 12:32 | justin_smith | ,(:else {:else "is kind of a function, but not like that"}) |
| 12:32 | clojurebot | where is log |
| 12:32 | clojurebot | "is kind of a function, but not like that" |
| 12:32 | andyf | Clojure's cond is different than Common Lisp's |
| 12:32 | tmtwd | okay |
| 12:32 | tmtwd | ill check out the else docs |
| 12:32 | tmtwd | i'm used to scheme and stuff |
| 12:32 | oddcully | tmtwd: well it could, but here you just want to have it as the final clause |
| 12:33 | Bronsa | tmtwd: it's not correct even without the else btw |
| 12:33 | andyf | (cond (= "" arg) "Fine" :else "unknown") |
| 12:34 | biellls | :else is just convention though, right? |
| 12:34 | tmtwd | oh I see |
| 12:34 | biellls | Any keyword is truthy |
| 12:34 | Bronsa | biellls: yes |
| 12:34 | tmtwd | so this is one of the ways clojure ruthlessly dispenses with parens :) |
| 12:34 | Bronsa | you can use whatever truthy value you want |
| 12:34 | andyf | tmtwd: When it doesn't replace them with square brackets, yes :) |
| 12:41 | bensu | git 1git |
| 12:41 | bensu | sorry, wrong app |
| 12:41 | tmtwd | http://pastebin.com/0yT8gtCv is this the right way to check that '?' is the last character of the parameter |
| 12:41 | tmtwd | ? |
| 12:42 | tmtwd | I checked in the repl, it seemed to suggest yes, but I'm failing some tests |
| 12:42 | biellls | ,(last "Hello") |
| 12:42 | justin_smith | tmtwd: oh, to test the last char, the best bet is .endsWith |
| 12:42 | clojurebot | \o |
| 12:42 | biellls | Returns a character |
| 12:42 | justin_smith | ,(.endsWith "hello" "o") |
| 12:42 | clojurebot | true |
| 12:43 | biellls | Or use \? |
| 12:43 | justin_smith | tmtwd: here's your issue ##(= "a" \a) |
| 12:43 | lazybot | ⇒ false |
| 12:44 | justin_smith | biellls: the advantage of endsWith is it doesn't need to turn your whole string into a seq |
| 12:44 | justin_smith | it's a well optimized built in method |
| 12:45 | biellls | ok, thanks |
| 12:45 | tmtwd | ah i see |
| 12:52 | biellls | Just tested it |
| 12:52 | biellls | Strangely last runs faster in my computer |
| 12:54 | justin_smith | biellls: criterium says .endsWith is 250x faster |
| 12:55 | justin_smith | biellls: cite https://www.refheap.com/105306 |
| 12:56 | justin_smith | well, not 250x |
| 12:56 | justin_smith | ,(/ 231.5 1.566) |
| 12:56 | clojurebot | 147.82886334610473 |
| 12:56 | justin_smith | ~150x |
| 12:56 | clojurebot | Pardon? |
| 12:57 | justin_smith | that's still an insane difference in execution speed |
| 12:57 | biellls | Cool, I guess I will have to upgrade my benchmarking tools |
| 12:57 | biellls | I used the time macro |
| 12:57 | oddcully | maybe measuring unrealized lazy stuff? |
| 12:57 | justin_smith | criterium is pretty great |
| 12:57 | justin_smith | oddcully: last of a string? |
| 12:58 | oddcully | justin_smith: yeah. just guessing. |
| 12:59 | justin_smith | oddcully: a random gc hit could throw time off easily |
| 12:59 | justin_smith | but anyway, criterium is generally reliable, even though it takes ages to run |
| 12:59 | oddcully | well just guessing. i have not seen the benchmark of OP |
| 13:00 | justin_smith | best profiles.clj deps for dev: pallet/alembic, criterium, tools.trace |
| 13:00 | justin_smith | imho |
| 13:04 | andyf | .endsWith can be slow if there is reflection happening (in general, any Java interop call is subject to this slowness) |
| 13:04 | andyf | (set! *warn-on-reflection* true) can help find these |
| 13:04 | andyf | type hints to help eliminate them |
| 13:04 | justin_smith | true |
| 13:05 | justin_smith | I wonder if a type hint would speed up the implicit seq call in the version using last |
| 13:08 | vas | happy 4th friends |
| 13:10 | justin_smith | nope, can't even type hint a string literal (d'oh, of course) |
| 13:12 | csd_ | Hi, i'm trying to understand the purpose of the macros in the attached. What purpose do they serve here? http://pastebin.com/hqxXPH5z |
| 13:12 | csd_ | From the apache storm source |
| 13:12 | justin_smith | csd_: it means that if the user pases +, your code gets #'+ |
| 13:13 | justin_smith | (for the clojure-bolt macro that is, same for conf-fn-system) |
| 13:13 | tmtwd | how to check for an empty string? ie "" or " "? |
| 13:13 | tmtwd | .emptyString? arg? |
| 13:13 | justin_smith | ,(defmacro pr-var [x] `(pr (var ~x))) |
| 13:13 | clojurebot | #'sandbox/pr-var |
| 13:14 | justin_smith | ,(pr-var +) |
| 13:14 | clojurebot | #'clojure.core/+ |
| 13:14 | csd_ | justin_smith: so the purpose of the macro is to pass a quoted var to the fn? |
| 13:14 | justin_smith | csd_: right, like most (every?) macro, the only reason you actually need it is syntactic convenience |
| 13:15 | csd_ | im surprised that this couldn't be pushed down to the fn* though |
| 13:15 | justin_smith | csd_: a function can't decide how it's args are interpreted |
| 13:15 | justin_smith | ,+ |
| 13:15 | clojurebot | #object[clojure.core$_PLUS_ 0x40ecd6ee "clojure.core$_PLUS_@40ecd6ee"] |
| 13:15 | justin_smith | you can't get #'+ from that |
| 13:16 | justin_smith | I mean you could do a tree search of interned values, but there isn't a *sane* way to get #'+ from that |
| 13:16 | justin_smith | s/tree search/linear search/ |
| 13:17 | csd_ | justin_smith: why do the args need to be wrapped in (var)? |
| 13:17 | justin_smith | csd_: probably because they want to embed them in a closure, but ensure that changes to the var are reflected in the running code |
| 13:18 | justin_smith | csd_: if you just passed in + as an arg to a higher order function, the resulting code would not see any redefinition of + during dev |
| 13:18 | justin_smith | (here's where + is a less illustrative example, of course) |
| 13:19 | justin_smith | csd_: when you call a var as a function, the value is looked up each time, ensuring that you see redefinitions without having to recreate your closure (and probably do some stateful stop/start thing) |
| 13:20 | csd_ | so i could for example bind the (var foo) to something within a let binding, run that concurrently, and change the value across the different threads and have it be safe? |
| 13:20 | justin_smith | right, vars are thread-safe |
| 13:22 | csd_ | unrelated, i'm looking for examples of well written clojure applications. storm and cascalog seem like good potential ones. can you think of any others? |
| 13:23 | justin_smith | csd_: anything from weavejester |
| 13:23 | justin_smith | csd_: ztellman's libs can be very enlightening |
| 13:23 | justin_smith | any of the prizmatic stuff |
| 13:23 | justin_smith | *prismatic |
| 13:24 | csd_ | yeah those are all libraries though |
| 13:24 | csd_ | right? |
| 13:24 | justin_smith | yeah, I missed the applications part, sorry |
| 13:24 | justin_smith | csd_: circleci |
| 13:27 | csd_ | ok |
| 13:28 | csd_ | thanks let me know if you think of any others |
| 13:28 | justin_smith | I know of lots of apps (I wrote most of the code even...) but can't share them :) |
| 13:30 | csd_ | i wish there was a good resource on writing large clojure apps. Seems to me like there's a need for that |
| 13:30 | justin_smith | yeah |
| 13:30 | justin_smith | it would be a lot of work |
| 13:30 | csd_ | yeah |
| 13:31 | justin_smith | but between component and prismatic/schema, I can see how a lot of the big picture structure and smaller scale specification would work, so that's a head start I guess |
| 13:32 | csd_ | i never feel comfortable with how i should handle program state, i.e. whether to have the so called God object or what |
| 13:32 | justin_smith | component sorts that out nicely for me |
| 13:33 | justin_smith | there's individual components responsible for some data, functionality or stateful resource, then a map describing who needs to use which |
| 13:33 | csd_ | I feel most comfortable right now defining everything in `def`, within a large hashmap |
| 13:34 | justin_smith | have you tried stuartsierra's component lib? |
| 13:34 | csd_ | then i can do something like (:path-cache @platform) and be returned the Java cache object i need |
| 13:34 | justin_smith | because it's very close to that |
| 13:35 | csd_ | i've looked at it but haven't tried it. even that though, when looking at the docs, i'm confused about where to define the objects initially |
| 13:35 | justin_smith | csd_: you define a record, that has a start method, that creates and initializes all stateful objects, and can if you wish also capture other stateless things to provide alongside |
| 13:36 | csd_ | but is the record initialized within a def, or within a function? |
| 13:36 | csd_ | that's what trips me up |
| 13:37 | csd_ | it's sort of splitting hairs ultimately |
| 13:37 | justin_smith | csd_: the normal thing is to use def to create the record, then use alter-var-root to run the start method that actually creates the stateful stuff |
| 13:37 | justin_smith | it's one top level record |
| 13:38 | justin_smith | but I have one case where I put the component inside an agent, because I want to be able to create it fresh inside a launcher, without using a def-inside-def, and unlike an atom an agent won't retry (which would be silly for stateful resources) |
| 13:39 | csd_ | retry in what sense? |
| 13:40 | justin_smith | csd_: atoms retry when concurrent modification attempts happen |
| 13:40 | justin_smith | while agents simple lock and do one at a time |
| 13:40 | justin_smith | *simply |
| 13:41 | csd_ | i need to sit down sometime and just go through clojure.core. there's so much stuff in there that i don't know much about |
| 13:43 | csd_ | justin_smith: thanks for letting me throw questions at you, gonna go make some lunch |
| 13:44 | justin_smith | np, headed out for an errand myself |
| 13:46 | donbonifacio | been migrating a 4K LOC of clj to cljc. tests on lein: 220ms, node: 90ms |
| 13:55 | tmtwd | how do I switch directories for cider? |
| 14:27 | scottj | tmtwd: maybe M-x cd? |
| 14:27 | scottj | tmtwd: be more specific |
| 14:28 | tmtwd | let me try M-x cd |
| 14:31 | tmtwd | yeah, my M-x cd directory is in the right directory, but when I try to (load "myfile.clj") it does not work, filenotfound exception |
| 14:31 | tmtwd | what is the C-c C-l of cider? |
| 14:31 | tmtwd | iow |
| 14:32 | scottj | C-c C-l |
| 14:33 | scottj | cider-load-file |
| 14:34 | rs0 | has anyone looked at Clojure<->Neovim integration? |
| 14:35 | rs0 | Neovim now has an experimental built-in terminal emulator. it seems like lein integration could consist of "start a terminal running lein within vim, send it text from some other buffer" |
| 14:35 | rs0 | in other words, exactly what emacs has apparently been doing since the Carter administration or something |
| 14:35 | justin_smith | rs0: that's what inferior-lisp does |
| 14:35 | justin_smith | rs0: what cider does includes getting doc strings |
| 14:36 | justin_smith | autocomplete |
| 14:36 | justin_smith | showing args as you use a function |
| 14:36 | rs0 | true. i've used emacs and slime a few times when playing with common lisp |
| 14:36 | lodin_ | Anyone else feel a need for a good lens implementation in Clojure? |
| 14:37 | rs0 | lodin_: why? |
| 14:38 | rs0 | lodin_: lens kind of strikes me as a defrecord analogue for haskell, but with more type theory, and more feature pragmas (e.g. template haskell) |
| 14:38 | lodin_ | rs0: Several reasons. One is that update-in only takes so you far. It does not update over every element in a vector, for instance. Another is that polymorphic lenses make for good interfaces since you can "add keys ad hoc" and don't need to rewrite data structures to fit a certain format. |
| 14:39 | rs0 | i don't understand your second point, but it sounds interesting |
| 14:39 | rs0 | do continue |
| 14:40 | rs0 | when i was looking at lenses i was desperate for a clojure-style "what problem are we trying to solve?" treatment |
| 14:40 | lodin_ | rs0: If you have a record that has all the keys that you need, but with the wrong names, e.g. :user instead of :username, then you need to write the record. |
| 14:41 | lodin_ | s/write/rewrite/ |
| 14:41 | lodin_ | or at least augment. |
| 14:42 | lodin_ | If you instead of doing (get info :username) you do (view info username), then any record (if you dispatch on types) can implement username and "redirect" to :user. |
| 14:43 | rs0 | the "key name mismatch" problem strikes me as a bit fishy |
| 14:43 | rs0 | i'd need to see it in a practical context |
| 14:44 | lodin_ | rs0: Would it be better if you had something with units in it? The typical example would be fahrenheit vs celsius. |
| 14:45 | lodin_ | (Then you'd use an iso.) |
| 14:45 | justin_smith | lodin_ so you'd have one record, and some code could update it in farenheight and other code could update in celcius to control the same value? |
| 14:47 | lodin_ | justin_smith: Yes, or you have two records, one using fahrenheit and one using celsius and a function that does (view stuff temperature) and expects fahrenheit. |
| 14:47 | rs0 | i dunno... i'm reminded of rich hickey's rule of thumb that "if your data is making decisions, your design is wrong" |
| 14:47 | rs0 | this sounds a bit like a return to Smart Data |
| 14:47 | justin_smith | rs0: it's the lens making the decisions though, and lenses are not data |
| 14:48 | tmtwd | whats the difference between defn and defn-? |
| 14:48 | rs0 | tmtwd: defn- is private |
| 14:48 | tmtwd | rs0, to the ns? |
| 14:48 | rs0 | tmtwd: it defines a function that's private to the namespace, yes |
| 14:48 | tmtwd | thanks |
| 14:49 | rs0 | hard to google, i suspect |
| 14:49 | rs0 | i remember that was a big concern when C# came out |
| 14:51 | lodin_ | rs0: Not familiar with Smart Data. |
| 14:52 | rs0 | lodin_: it's not a technical term... I'm basically using it to refer to OO-style data that isn't semantically transparent |
| 14:52 | lodin_ | rs0: But this is just ad hoc polymorphism, but essentially bundle two functions (get and update) into a convenient interface. |
| 14:58 | rs0 | lodin_: but you still think that lenses would be beneficial/coherent in a dynamically typed language like clojure? |
| 14:58 | rs0 | lodin_: or at least, no worse than the present state of affairs? |
| 14:59 | lodin_ | rs0: brb. |
| 15:09 | hyPiRion | rs0: so something à la define-setf-expander or defsetf in common lisp? |
| 15:10 | rs0 | hyPiRion: I don't know enough about CL *or* lenses to say |
| 15:11 | lodin_ | rs0: Absolutely. |
| 15:12 | lodin_ | rs0: It's just about presenting your data through an interface. |
| 15:12 | lodin_ | rs0: but importantly, lenses compose. |
| 15:15 | lodin_ | rs0: The only issue with Clojure being dynamic is that it cannot implement pure (with Haskell type a -> f a). |
| 15:17 | lodin_ | And as far as I understand, the Haskell lens library uses applicative functors for good reasons (although I don't know the details for the implementation). |
| 15:20 | lodin_ | rs0: The core use case is handled in Clojure by the *-in functions, but lenses generalize those functions so that you can look inside any object, not just associatives. |
| 15:21 | rs0 | lodin_: i'm not sure that that's more appealing than just having a defprotocol that you can use to implement navigation. i saw stuart halloway do exactly that in a gist showing how to find nils in arbitrarily nested clojure collections |
| 15:22 | lodin_ | rs0: How do you mean? (Do you have a link to the gist?) |
| 15:27 | lodin_ | rs0: An example: how would a function look that takes a sequence and a function and updates the second last item with the provided function? Like (defn update-2nd-last [xs f] ...). |
| 15:30 | rs0 | lodin_: oh, that sounds like a job for transducers! =) |
| 15:31 | rs0 | lodin_: i'm not sure why you can't maintain a small internal buffer (which is all you'd end up doing with transducers anyway) |
| 15:32 | lodin_ | I'm not sure how that would look. Could you write some example code? |
| 15:34 | lodin_ | Actually, let's say that you have a table represented as a sequence of sequences, and you want to update the second last element in the first row. So the first dimension is rows, the second is columns. |
| 15:35 | lodin_ | So my previous function update-2nd-last would take (first table) as input. |
| 15:36 | lodin_ | The point that I'm failing to get to, is that with lenses you can write (update xs [0 reverse' 1] f) where reverse' is an iso. |
| 15:37 | lodin_ | You can also define default values as part of the lens, i.e. not as part of the data structure. So you don't need a magic object that overloads calls to get. |
| 15:47 | lodin_ | For instance, instead of (update-in {} [:foo] (fnil inc 0)) you can write (update {} (key' :foo 0) inc). (Sometimes this is what you want, sometimes not.) |
| 15:49 | lodin_ | So about dynamic languages, I think lenses find new uses cases there, the above with default values being one of them. |
| 15:51 | rs0 | lodin_: i'm not sure this really fits into the overall Clojure philosophy |
| 15:51 | lodin_ | rs0: How's that? |
| 15:52 | rs0 | lodin_: well, even though lenses are functions, the intention is to view data through them, right? |
| 15:52 | lodin_ | rs0: or update, yes. |
| 15:52 | rs0 | right |
| 15:53 | rs0 | lodin_: I think one of Clojure's biggest contributions to software engineering is the emphasis on reducing everything to generic reusable data, and directly using/passing around values everywhere you can |
| 15:53 | lodin_ | rs0: How does lenses change that? |
| 15:55 | rs0 | lodin_: with lenses, you're introducing this sort of object-y translation layer between your data and the code that is looking at it. it's more than just a common abstraction (e.g. the seq protocol), because it seems like you're implementing specific semantics/special cases for different types of data that, fundamentally, have the same shape underneath (e.g. two different defrecord types) |
| 15:56 | lodin_ | rs0: That's not what lenses are, but lenses can be used for that. |
| 15:56 | lodin_ | But (update [0 reverse' 1] f) is nothing like that. |
| 15:56 | lodin_ | It's just abstracting away the (set ... (f (get ...))) pattern. |
| 16:00 | lodin_ | The cool thing about having polymorphic lenses is that you can implement "username" on Associative so that it just accesses :username. If you then have a record you can implement username so that it accesses :user. |
| 16:01 | rs0 | lodin_: can't you do that with extend-protocol? |
| 16:02 | lodin_ | rs0: You mean have a method that returns the username, like (defprotocol Username (username [_] "Returns the username."))? |
| 16:02 | rs0 | lodin_: additionally, years of Java development has led me to appreciate the transparent way that Clojure serializes data. you pretty much know exactly how something will get written out |
| 16:03 | lodin_ | rs0: Lenses are completely separate from how the data is represented, just like protocol methods are not part of the data. |
| 16:04 | lodin_ | Lenses are function that the user decides he/she wants to use. |
| 16:04 | lodin_ | s/function/functions/ |
| 16:04 | rs0 | lodin_: right, and defrecord lets you define methods as well |
| 16:04 | lodin_ | rs0: Precisely. |
| 16:04 | rs0 | actually, let me ask you something |
| 16:04 | rs0 | can you compare and contrast lenses with http://rschmitt.github.io/dynamic-object/ ? |
| 16:04 | lodin_ | So all that lenses do, is to bundle two methods, get and update. |
| 16:05 | lodin_ | This makes it possible to abstract away (set ... (f (get ...))) and similar patterns. |
| 16:06 | lodin_ | rs0: After looking at it for a few seconds, I'd say it's quite different. |
| 16:10 | rs0 | lodin_: the main similarity is that it provides a set of functions that provide a "view" into data in a Clojure map |
| 16:11 | rs0 | lodin_: however, they can do more than just return values. for instance, they can perform implicit type conversions. T -> Optional<T>, Date -> Instant, and so on |
| 16:12 | lodin_ | rs0: With DynamicObject, how would you do the equivalent of update-in? |
| 16:13 | rs0 | lodin_: unsolved problem |
| 16:13 | lodin_ | rs0: So it's completely different. :-) |
| 16:13 | lodin_ | A major point of lenses is that they compose. |
| 16:14 | rs0 | lodin_: although you remind me, i was wondering about implementing update-in and the like in Collider https://github.com/rschmitt/collider |
| 16:14 | lodin_ | So that first you abstract away (set ... (f (get ...)) and then you can abstract (set ... (set ... (f (get ... (get...))))) |
| 16:14 | lodin_ | etc etc. |
| 16:15 | rs0 | hm |
| 16:15 | rs0 | what does that look like with sets? |
| 16:16 | rs0 | vectors actually are Associative |
| 16:16 | rs0 | but sets, well, you can basically do two things with them: test for membership and iterate over the contents |
| 16:17 | lodin_ | rs0: Presumably you would have a mapping function in there. Also abstractable with lenses. |
| 16:17 | lodin_ | Not exactly lenses, but traversals. |
| 16:17 | lodin_ | Same same, but different. :-) |
| 16:18 | rs0 | I dunno, man... maybe I'm biased |
| 16:18 | rs0 | at this point I'm fairly predisposed to view concepts coming out of the Haskell space as navel-gazing until proven otherwise |
| 16:19 | rs0 | I studied Haskell before Clojure. I was blown away by Clojure's far simpler and more direct solutions to problems I actually have |
| 16:19 | lodin_ | You're not convinced that (update table [0 reverse 1] f) is a good abstraction? |
| 16:19 | lodin_ | reverse', i mean. |
| 16:19 | rs0 | what is reverse' |
| 16:19 | lodin_ | it's the iso i mentioned above. |
| 16:20 | justin_smith | unholy union of get-in and -> I see? |
| 16:20 | lodin_ | rs0: iso being a lens that doesn't actually look deeper, but just makes things look different. So reverse' would make the sequence look reversed to the following steps. |
| 16:22 | lodin_ | rs0: Another would be (update 32 [fahrenheit<->celsius] inc), returning 33.8. |
| 16:22 | lodin_ | Err, ignore [] since they're not needed. |
| 16:23 | lodin_ | Compare with (-> 32 fahrenheit->celsius inc celsius->fahrenheit). |
| 16:25 | rs0 | lodin_: since i mentioned this and you wanted to see it: https://gist.github.com/stuarthalloway/b6d1c8766c747fd81018 |
| 16:25 | tmtwd | How can I use repl to call functions directly instead of like this? (#'rna-transcription/transform-rna "C") |
| 16:25 | justin_smith | tmtwd: for starters, you can use require |
| 16:25 | lodin_ | rs0: Or (let [x {:temp 32}] (->> x :temp fahrenheit->celsius inc celsius->fahrenheit (assoc x :temp))) |
| 16:25 | justin_smith | ,(require '[clojure.string :as s]) |
| 16:25 | clojurebot | nil |
| 16:25 | justin_smith | ,s/join |
| 16:25 | clojurebot | #object[clojure.string$join 0x26f1ea7d "clojure.string$join@26f1ea7d"] |
| 16:26 | lodin_ | rs0: The lens equivalent: (update x [:temp fahrenheit<->celsius] inc). |
| 16:26 | zematis | Is there a way to filter exactly n items out of a vector with a pred? |
| 16:27 | justin_smith | zematis: something like drop? |
| 16:27 | lodin_ | zematis: filter is lazy, so you just take n items. Or is that the answer to another question? :-) |
| 16:27 | rs0 | i think he means "the first n items matching the pred" |
| 16:27 | rs0 | or... something |
| 16:28 | zematis | I want to only drop items where (= pred? true), and end up with a vector that contains m - n items. |
| 16:28 | zematis | Could do it with sort and then drop, but that wouldn't preserve the ordering. |
| 16:29 | justin_smith | zematis: (take n (filter p? c)) ? |
| 16:29 | lodin_ | zematis: I see what you mean. |
| 16:29 | zematis | justin_smith: There may be less than n items after the filter. |
| 16:29 | justin_smith | zematis: take doesn't care |
| 16:30 | justin_smith | it just sets a maximum |
| 16:30 | zematis | Hmm. Then that should work! |
| 16:30 | zematis | Thanks! |
| 16:30 | justin_smith | ,(take 100 [:a :b]) |
| 16:30 | clojurebot | (:a :b) |
| 16:30 | zematis | Oh, no, that won't work. |
| 16:30 | lodin_ | I think you mean filter as in remove, not separate and keep, right? |
| 16:30 | zematis | Here, I'll give an example. |
| 16:31 | rs0 | zematis: you want to exclude the first N items in the vector matching pred? |
| 16:31 | zematis | rs0: yep |
| 16:31 | lodin_ | zematis: You tricked everyone by saying filter. :-) |
| 16:31 | zematis | Ah. Still new at this :) |
| 16:31 | rs0 | lodin_: i don't blame him. this is why Collider collections advertise both "filter" and "exclude" |
| 16:32 | rs0 | ok. i guess i'd create an empty transient vector and loop/recur |
| 16:32 | rs0 | depends on how performance sensitive your use case is |
| 16:32 | zematis | Shouldn't be that sensitive. |
| 16:32 | rs0 | can't rrb-vectors be appended or something? |
| 16:33 | lodin_ | rs0: Back to lenses. Do you see what I'm getting at with the (set ... (f (get ...))) examples? |
| 16:34 | tmtwd | are cursives paredit bindings the same as ciders/emacs, or can they be configured as such? |
| 16:34 | rs0 | lodin_: i'm not completely sure how this is more general than update-in, or possibly a souped-up update-in that you could build using some new protocol |
| 16:35 | lodin_ | rs0: That new protocol is the protocol of lenses! :-) |
| 16:35 | lodin_ | rs0: If you would soup-up update-in you would reinvent lenses, I'm quite sure. |
| 16:35 | lodin_ | Poorly, probably. |
| 16:36 | lodin_ | I did precisely that, but before learning Clojure. |
| 16:36 | justin_smith | a combo of get-in, update-in, and -> |
| 16:36 | rs0 | lodin_: I'm not sure why Associative isn't adequate |
| 16:37 | rs0 | lodin_: that interface encapsulates the notion of a collection that contains elements "at" some sort of location or address that can be specified |
| 16:37 | rs0 | (unlike sets which can merely be traversed) |
| 16:37 | lodin_ | rs0: There was a library that I saw ones that introduces wildcards for get-in, so you could write (get x [:foo * :bar]) to update all the bar keys in the sequence contained in (:foo x). |
| 16:38 | rs0 | I don't know what that means |
| 16:38 | lodin_ | rs0: err, i wrote get, i meant update. |
| 16:39 | rs0 | so is this, like, shell globbing? |
| 16:39 | rs0 | the * represents all paths to different :bar keys? |
| 16:39 | lodin_ | If we had a traversal called seq', you could write (update (range 5) seq' inc) ; (1 2 3 4 5). |
| 16:39 | lodin_ | But since lenses and traversals and what not (http://i.imgur.com/ALlbPRa.png) compose, then you can also do |
| 16:39 | rs0 | ,(map inc (range 5)) |
| 16:39 | clojurebot | (1 2 3 4 5) |
| 16:40 | lodin_ | (update {:foo (range 5)} [:foo seq'] inc) ; {:foo (1 2 3 4 5)} |
| 16:41 | rs0 | lodin_: that diagram is worse than the Scala collections library class hierarchy |
| 16:41 | lodin_ | rs0: I know, it's horrible. |
| 16:41 | lodin_ | Fortunately, this is Clojure, so you don't need to look at it. ;-) |
| 16:41 | rs0 | lodin_: well, the types are still there |
| 16:42 | lodin_ | rs0: Sure. And for good reason. |
| 16:42 | rs0 | lodin_: just because I don't have to look at them doesn't mean they go away |
| 16:42 | lodin_ | You don't have to care when using it though, as long as you do things that make sense. |
| 16:43 | rs0 | oof. that's not reassuring. that sounds like foreshadowing |
| 16:45 | lodin_ | Anyway, the point is that there are different things capable of doing different things, but they all compose. |
| 16:46 | lodin_ | It's like you can only do (comp g f) if g has arity one in Clojure, because it doesn't make sense otherwise. |
| 16:47 | rs0 | something just occurred to me. I have a sense that Haskell people are concerned with whether an idea composes with itself (e.g. applicative functors do, monads don't), and Clojure people are concerned with whether ideas compose with *other ideas* |
| 16:49 | rs0 | i seem to see a lot of research out of the Haskell space of the form "look at this insanely complicated abstraction! it COMPOSES!" |
| 16:49 | rs0 | say, Arrows or something |
| 16:51 | rs0 | actually, arrows are a generalization of monads, so I guess they fall into the abstraction-to-end-all-abstractions category |
| 16:53 | lodin_ | Dunno, I'm not that familiar with what's going on in Haskell. |
| 16:53 | lodin_ | rs0: Can you give an example of ideas that compose with each other in Clojure? |
| 16:55 | rs0 | lodin_: well the basic idea behind most of clojure's features is orthogonality and simplicity. they do one thing and can be composed in different ways to combine their effects. have you ever seen stuart halloway's breakdown of the features of classes and their Clojure analogues? |
| 16:57 | lodin_ | rs0: Don't know which talk/article you're refering to, but isn't the same true for Haskell? |
| 16:58 | rs0 | lodin_: I think that a lot of the Haskell code out there that actually does useful stuff tends to look like that. the main problem solving strategy is usually "call a function" |
| 16:59 | lodin_ | A good strategy, no? |
| 16:59 | rs0 | lodin_: but Haskell also has a more academic component with grad students studying hardxxxcore type theory |
| 16:59 | rs0 | lodin_: well, I also think that pervasive non-strict evaluation is a bad design choice for a general purpose programming language. it leads to a ton of incidental complexity |
| 17:00 | lodin_ | rs0: I'm more interested in which ideas you mean compose in Clojure, and how that contrasts with Haskell. |
| 17:03 | rs0 | why the hell don't i just have a bookmark folder or something with all the clojure talks |
| 17:04 | tmtwd | anyone use exercism? |
| 17:05 | rs0 | lodin_: okay, for example |
| 17:06 | lodin_ | rs0: I know Clojure, but I don't know Haskell, so I can't contrast it. |
| 17:06 | rs0 | lodin_: in Clojure, you have eager evaluation and no concept of "effects" tracked by the type system |
| 17:07 | lodin_ | ... beyond lazy vs strict evaluation, and static typing. |
| 17:07 | rs0 | lodin_: just a sec |
| 17:07 | rs0 | lodin_: in Haskell, you have pervasive non-strict evaluation, and the IO monad is used to sequence effects (and in effect to mark impure functions as contaminated) |
| 17:08 | rs0 | lodin_: monads are probably the most famous abstraction associated with Haskell, and they don't actually compose with each other. and this results in an interesting situation, even above and beyond the IO monad itself |
| 17:08 | rs0 | lodin_: if you want to combine the effects of the Writer monad and the State monad, you have to create a monad transformer stack |
| 17:09 | rs0 | lodin_: so all of the monads in the stack need to know about each other; it's somewhat monolithic that way |
| 17:09 | lodin_ | Right. |
| 17:09 | rs0 | lodin_: you also now have all this incidental complexity--for instance, the order of monads in the stack is critical to get right |
| 17:10 | lodin_ | Is that really incidental complexity though? |
| 17:10 | rs0 | absolutely! |
| 17:10 | rs0 | monad transformers have nothing to do with the problem you're trying to solve |
| 17:10 | lodin_ | Reversing the order of the stack changes the semantics, no? |
| 17:11 | rs0 | the stack itself is incidental complexity |
| 17:11 | tmtwd | anyone know why my functions don't work as expected ? http://pastebin.com/ZYNjzfxT |
| 17:11 | lodin_ | rs0: Please elaborate. |
| 17:11 | rs0 | i don't need monad transformers to reason about my code, any more than I need C++ multiple virtual destructor inheritance to reason about my program's resource management |
| 17:12 | lodin_ | tmtwd: You're testing for "C" instead of \C etc. I think that's the problem. |
| 17:12 | rs0 | a haskell program, at the highest level, lives in a monad transformer stack, and all of the wrapping and unwrapping and lifting and effect sequencing is something that's on your head every day when you go to work |
| 17:13 | rs0 | a Clojure program, or an OCaml program (for a statically typed example), doesn't force your architecture into the procrustean bed of one all-purpose abstraction |
| 17:14 | rs0 | I think monad transformers are an example of taking things too far. it's basically saying "if monads aren't getting the job done, you're not using enough of them" |
| 17:14 | rs0 | (since monad transformers are also monads) |
| 17:15 | lodin_ | rs0: What's the worst/deepest monad stack you've used? |
| 17:16 | tmtwd | lodin_, ah, good tip :) |
| 17:16 | rs0 | lodin_: I haven't done enough practical Haskell for things to get to that point. I think most people in practice use RWS and RWST, plus something for IO |
| 17:17 | lodin_ | tmtwd: You might want to check out (case ...) as well. |
| 17:18 | lodin_ | tmtwd: Or actually, just use a map if that's what you need. (def handle-char {\C \G, \A \U, \T \A, \G \C}), yes, the map can be used as a function. |
| 17:20 | tmtwd | lodin_, oh kinda like haskell? |
| 17:20 | lodin_ | tmtwd: Dunno. :-) |
| 17:21 | lodin_ | Or you mean case in Haskell? |
| 17:21 | rs0 | or the haskell 'map' function? |
| 17:21 | rs0 | (as opposed to the map data type) |
| 17:21 | tmtwd | so, we can't throw something in the else statement of cond? http://pastebin.com/F7UimAA8 |
| 17:22 | lodin_ | tmtwd: I think so, but you're missing a dot. |
| 17:22 | tmtwd | lodin_, oh no nvm . I failed at understanding you |
| 17:22 | lodin_ | Can you instantiate Throwable btw? |
| 17:23 | tmtwd | lodin_, yeah that was it |
| 17:23 | tmtwd | i dunno thats just what I saw somewhere |
| 17:23 | tmtwd | but it loads now |
| 17:24 | lodin_ | I guess you can then. |
| 17:25 | lodin_ | I usually throw Exception. Don't know why. |
| 17:27 | lodin_ | rs0: If it's any comfort though, I wanted lenses before I knew lens existed. I know about lens because I was trying to reinvent them. |
| 17:29 | lodin_ | I'm quite sure I wouldn't have done as good a job though, so I'm glad someone else has done pretty much all the hard work. |
| 17:30 | scottj | lodin_: have you seen https://github.com/megakorre/glasses ? (idk anything about it, just found it searching clojars for lens) |
| 17:31 | lodin_ | scottj: Yes. |
| 17:34 | tmtwd | How to turn ("G" "A" "B") into "GAB"? |
| 17:34 | lodin_ | There's a few other implementations as well, but iirc the other ones use the [getter setter] approach, rather than the [value updater] approach. |
| 17:34 | tmtwd | concat? |
| 17:34 | lodin_ | tmtwd: (apply str ...) |
| 17:34 | clojurebot | concat is considered a cat |
| 17:34 | Bronsa | tmtwd: apply str |
| 17:35 | tmtwd | , (apply str ("a" "b")) |
| 17:36 | clojurebot | #error {\n :cause "java.lang.String cannot be cast to clojure.lang.IFn"\n :via\n [{:type java.lang.ClassCastException\n :message "java.lang.String cannot be cast to clojure.lang.IFn"\n :at [sandbox$eval25 invoke "NO_SOURCE_FILE" 0]}]\n :trace\n [[sandbox$eval25 invoke "NO_SOURCE_FILE" 0]\n [clojure.lang.Compiler eval "Compiler.java" 6792]\n [clojure.lang.Compiler eval "Compiler.java" 6755]\n... |
| 17:36 | tmtwd | i don't think that quite works |
| 17:36 | oddcully | ,(apply str ["a" "b"]) |
| 17:36 | clojurebot | "ab" |
| 17:36 | lodin_ | tmtwd: As a general rule, use [] instead of () when writing literal sequences. |
| 17:36 | oddcully | ,(apply str '("a" "b")) |
| 17:36 | clojurebot | "ab" |
| 17:36 | lodin_ | ,(apply str '(x y)) |
| 17:36 | clojurebot | "xy" |
| 17:36 | lodin_ | Probably not what you wanted. |
| 17:37 | lodin_ | I was bitten by that when I was learning Clojure. |
| 17:38 | tmtwd | lodin_, ah gotcha, the return from repl was with parens |
| 17:39 | lodin_ | scottj: The problem with glasses is that there's no way to handle e.g. using a purely functional random number generator in the updater function. |
| 17:41 | lodin_ | scottj: Like (update x [:foo mapped-vec] #(add-noise rng %)) |
| 17:41 | lodin_ | scottj: I'm expecting rs0 to react now, but I think we need a monad for that. :-) |
| 17:42 | rs0 | damnit i stopped paying attention |
| 17:42 | rs0 | let me read up |
| 17:42 | scottj | lodin_: recall the names of other clojure lens implementations? |
| 17:43 | lodin_ | scottj: Not really, I've only used glasses, but I can see if I find any that i recognize. |
| 17:43 | rs0 | "purely functional random number generator" |
| 17:43 | rs0 | why not just create a java.util.Random with a deterministic seed? |
| 17:44 | rs0 | if... this is about testing or something |
| 17:45 | scottj | https://speakerdeck.com/markhibberd/lens-from-the-ground-up-in-clojure |
| 17:45 | lodin_ | Have you seen gfrederick's talk on rngs? |
| 17:45 | lodin_ | scottj: iirc, that one uses [value updater] approach, aka the "functor approach". |
| 17:48 | lodin_ | I'm not sure now glasses work, I think it's analoguous but spelled differently. But I'm really not sure. |
| 17:48 | amalloy | rs0: if it's an immutable RNG, you can do things with it you couldn't do with a Random |
| 17:49 | rs0 | scottj: i've actually seen both versions of that slide deck |
| 17:49 | amalloy | like you can spin up three threads pursuing different strategies, and give them each the same seeded RNG instance, to get reliable random numbers from all of them |
| 17:49 | rs0 | amalloy: ThreadLocalRandom? |
| 17:49 | rs0 | actually, you can't control the seed in that case |
| 17:50 | rs0 | well, that's still nothing a thread-local variable can't fix. if you shared an immutable test runner between those threads you'd still get non-deterministic behavior |
| 17:50 | rs0 | er |
| 17:50 | rs0 | immutable RNG instance |
| 17:50 | rs0 | i'm writing up a junit issue and i'm distracted |
| 17:50 | amalloy | huh? no you wouldn't |
| 17:52 | rs0 | oh i see, you're referring to taking the state of the RNG and holding on to it in each thread |
| 17:52 | rs0 | so your RNG is basically a pure (next) function over a given seed and some pseudorandom number generation algorithm |
| 17:52 | amalloy | yes, of course. anything else wouldn't be immutable |
| 19:02 | lodin_ | My solution now would be to do (let [rng-atom (atom rng)(update x [:foo mapped-vec] #(let [[rngadd-noise @rng % |
| 19:02 | lodin_ | err |
| 19:03 | lodin_ | My solution now would be to do (let [rng-atom (atom rng) new-x (update x [:foo mapped-vec] #(let [[rng v] (add-noise @rng %)] (reset! rng-atom rng) v))] [@rng-atom new-x]). |
| 19:05 | lodin_ | It would be cleaner to have something like (update-with rng x [:foo mapped-vec] add-noise), where add-noise takes two arguments and returns a tuple. |
| 19:10 | lodin_ | and update was (fn [x lens f] (update-with nil x lens (fn [_ v] (second (f v))))). |
| 19:10 | lodin_ | err, |
| 19:10 | lodin_ | and update was (fn [x lens f] (update-with nil x lens (fn [_ v] [nil (f v)]))) |
| 21:46 | TEttinger | huh, I'm not sure if this is a lein thing or a java problem or a cursive/intelliJ problem. |
| 21:46 | TEttinger | java.lang.Exception: Problem opening jar C:\Users\noto\.m2\repository\org\clojure\clojure\1.7.0\clojure-1.7.0.jar |
| 21:46 | TEttinger | caused by having a dep on [org.clojure/clojure "1.7.0"] |
| 21:47 | TEttinger | there's one error after that: Caused by: java.util.zip.ZipException: error in opening zip file |
| 21:51 | TEttinger | I just unzipped it manually, it is totally a valid jar/zip |
| 21:54 | TEttinger | huh, I think it may have been me pressing the run button twice by mistake in Cursive |
| 22:22 | TEttinger | cfleming: is there a reason why Cursive doesn't show lein run as an option in the Leiningen Tools window? |
| 22:22 | TEttinger | there's uberjar, which I think also requires a -main method |
| 22:23 | TEttinger | I can sorta work around it by calling (-main) at the end of the file, but then it gets called when AOT compiling as well |
| 22:24 | justin_smith | TEttinger: or when you require that namespace even |
| 22:25 | justin_smith | TEttinger: just a wild guess - is run hooked up to the standard "run project" UI? |
| 22:43 | TEttinger | justin_smith, nope |
| 22:43 | justin_smith | TEttinger: looks like Run -> Edit Configurations ? https://cursiveclojure.com/userguide/repl.html |
| 22:43 | TEttinger | run project doesn't run -main |
| 22:44 | TEttinger | oh? |
| 22:44 | justin_smith | I mean that page is about starting a repl, but it shows things that appear to be related to setting up run configuration... |
| 22:44 | TEttinger | I see VM params and Script params |
| 22:45 | justin_smith | script params "clojure.main -m your.ns" would work |
| 22:45 | TEttinger | it looks like this: http://i.imgur.com/8IZ6T6K.png |
| 22:45 | TEttinger | dash m? |
| 22:45 | justin_smith | oh, it might be just "-m your.ns" |
| 22:46 | justin_smith | one moment, checking |
| 22:48 | TEttinger | I have an "unused global declaration -main" warning too :| |
| 22:48 | justin_smith | because of a (defn -main ...) ? |
| 22:48 | justin_smith | is the ns set up to be your main ns in project.clj? |
| 22:48 | TEttinger | yes |
| 22:48 | TEttinger | :main ^:skip-aot infinite-raid.core |
| 22:49 | justin_smith | interesting |
| 22:49 | TEttinger | I created a template with `lein new app infinite-raid` |
| 22:49 | justin_smith | (I don't really work on this project from this computer, so testing took a while) |
| 22:50 | TEttinger | changed to use clojure 1.7.0, added a dep and usage of a java lib, that's about it |
| 22:50 | justin_smith | if you set it to execute "lein run -m your.ns/-main" it should just work |
| 22:50 | TEttinger | as a new run config? |
| 22:50 | justin_smith | try that from a repl of course, but it works here |
| 22:50 | justin_smith | TEttinger: yeah |
| 22:52 | justin_smith | TEttinger: I use things like that in order to run the same project from a jsvc wrapper or just through regular clojure.main, both possible from the same uberjar (without lein it's slightly different in invocation, but same concept of course) |
| 22:57 | TEttinger | justin_smith: it ended up working out by making a new lein run config, with just the arg `run` |
| 23:00 | justin_smith | TEttinger: oh, that's easy! |
| 23:00 | TEttinger | haha |
| 23:00 | justin_smith | that was nearly my first guess |
| 23:02 | TEttinger | well it looks like I'll be writing some java and some clojure now to try to make a game. even though I have a decent amount of art I made, it still isn't enough for some sorts of games, so this is going to be full-color text-based type of thing. |
| 23:02 | TEttinger | it's always entertaining to see how much shorter the clojure is :) |
| 23:25 | rhg135 | Is this supposed to hang, or did I miss something. https://www.refheap.com/105312 networking is a pain |
| 23:29 | justin_smith | rhg135: you can use jstack to see what each of the threads in your vm is doing |
| 23:30 | rhg135 | is jstack one of the jvm tools? |
| 23:32 | justin_smith | rhg135: yeah, it comes with the vm |
| 23:32 | justin_smith | it shows a stacktrace for every thread, if you give it your app's pid |
| 23:33 | rhg135 | I'm using a debugger, just didn't think to pause the vm |
| 23:41 | rhg135 | this is getting weird |
| 23:43 | rhg135 | apparently when I load-file it, it doesn't even connect, and when I type it on that port, 8088, it doesn't connect either |
| 23:43 | rhg135 | but when i type it and use a different port it hangs and the trace reveals netty is waiting |