#clojure logs

2015-07-04

00:22turbofailfinally taking the plunge back into cljs-land
00:22turbofailit's been a while
00:23vasCommittee on the Jewish Law and Standards? :P
00:24turbofaili think you transposed some letters
00:24turbofailunless it's one of those reordered french initialisms
00:25vasit must be. first result on duckduckgo when i searched "cljs"
00:29vasWould you recommend cljs over clj for a dynamic web application?
00:32turbofaileh? i would normally use both
00:32turbofailcljs for the front-end, clj for the backend
00:33turbofaili suppose you could use node.js on the server end but i'd generally prefer JVM clojure when available
01:43zematisI'm trying to get sum the values of :key in [{:key 57 :other-key 72} {:key 27} ...]. Any suggestions?
01:44tatut,(reduce + (map :key [{:key 1} {:key 10}]))
01:45clojurebot11
01:46TEttinger,(reduce + (map :key [{:key 1} {:key 10} {}]))
01:46clojurebot#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:46TEttinger,(reduce + (remove nil? (map :key [{:key 1} {:key 10} {}])))
01:46clojurebot11
01:46TEttingergood suggestion though, tatut
01:46TEttinger(inc tatut)
01:46lazybot⇒ 1
01:47zematisThanks. Just learning functional programming now :)
01:47TEttingerit's a great fit for a lot of problems
01:47TEttingera lot of people (including me at first) have a hard time adapting to not mutating stuff all the time
01:48zematisI'm having fun. Should probably be learning java more deeply first for my career, but it's not as interesting.
01:48TEttingerit eventually becomes second nature though. learning java at the same time as clojure could be interesting, but they both can use java libs!
01:49tatutthe problem statement said nothing about :key potentially missing! ;)
01:49zematisYep. That's one of the things that led me here instead of haskell.
01:49zematistatut: It shouldn't be in my use case
01:50TEttingerI'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:52TEttingerI'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:53TEttingerlisp-style code doesn't have this problem :)
01:53kungiTEttinger: The last time I switched to lua I immediatly got stumped by its "data structure"
01:53zematisI'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:53TEttingerkungi, yeah the table is interesting
01:54TEttingermetatables are very handy, writing a lib that uses them now
03:51PupenoI'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:48TEttingernice Pupeno
11:12bielllsHi everyone
11:12bielllsDoes anyone know why (class 'true) returns Java.lang.boolean instead of symbol?
11:13biellls,(class 'true)
11:13clojurebotjava.lang.Boolean
11:13biellls,(class 'somename)
11:13clojurebotclojure.lang.Symbol
11:13justin_smith,(class '1)
11:13clojurebotjava.lang.Long
11:13justin_smith,(class ':foo)
11:13clojurebotclojure.lang.Keyword
11:13justin_smith,(class '[])
11:13clojurebotclojure.lang.PersistentVector
11:14justin_smiththere must be a reader specifically for true (and it makes sense that there would be)
11:15bielllsIt's just that I've been trying to port the scheme metacircular evaluator in SICP, and this makes some things not work
11:16bielllsI wondered if there was a good reason why it's implemented like this
11:17justin_smithbiellls: self evaluating things in clojure evaluate to themselves when quoted. There's a consistency to that.
11:17dnolenbiellis: ' doesn't create symbols, it's just quoting
11:17justin_smithoh yeah
11:17dnolenif '(1 2 3) produced symbols that would be pretty useless
11:17justin_smith,((juxt identity type) (symbol "true"))
11:17clojurebot[true clojure.lang.Symbol]
11:18bielllsTrue
11:18bielllsI just thought that quote meant that it wouldn't be evaluated
11:19justin_smithbiellls: that's why I mentioned readers
11:19dnolenbiellls: except some things self-evaluate, pretty sure this is the case for Scheme as well
11:19justin_smithreading and evaluating are separate
11:20Bronsabiellls: it's not evaluated indeed. it's read as a symbol
11:20Bronsa,(class (read-string "true"))
11:20clojurebotjava.lang.Boolean
11:20Bronsaerr, i meant as a boolean
11:21Bronsabiellls: 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:21bielllsIn a scheme repl 'true returns 'true
11:21Bronsasame applies for nil and false
11:22bielllsOK thanks
11:22justin_smithbiellls: what about '#t
11:22justin_smithtrue isn't special in scheme is it?
11:22dnolenbiellls: (eq? '#t #t) => #t
11:22dnolenJust tested this in Petite Chez Scheme
11:22bielllsYou're right, '#t evaluates to #t
11:23dnolensame for (eq? '1 1) => #t
11:24Bronsabiellls: and it's the same in cl, t is equal to 't, nil is equal to 'nil
11:24bielllsI guess that's the difference then, true isn't special in scheme and it is in clojure
11:24Bronsabiellls: but #t is special in scheme and is not in clojure. they just have different representations
11:26bielllsI guess the only way around is to rename true and false to something else in my evaluator
11:27justin_smithwhy not #t and #f - there's a nice symmetry to that
11:27dnolenbiellls: note SICP likely used true and false because they *couldn't* use #t and #f
11:27dnolenbiellls: but you *can*
11:27biellls,'#t
11:27clojurebot#<RuntimeException java.lang.RuntimeException: EOF while reading>
11:28bielllsIt throws an exception In my repl
11:28justin_smithoh, maybe not, :(
11:28bielllshaha
11:28dnolenbiellls: er, sorry # is a reader thing
11:28Bronsabiellls: yeah you can't use the clojure reader for that
11:28dnolenbiellls: in core.logic I ended up using t# and f# I think in the early days.
11:28Bronsadnolen: that's going to be weird with `
11:29dnolenBronsa: 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:29dnolenBronsa: pretty sure it doesn't, they don't use splicing in quoted forms.
11:30bielllsdnolen: Good point about using true and false because they couldn't use #t and #f, I hadn't thought about that
11:31bielllsI should implement a lisp reader sometime to better understand how they work
11:34Bronsabiellls: oh, do so, you can write one in just a hundred-ish lines of code
11:34Bronsaassuming you just want s-exps and not the fancy clojure extensions on top of it
11:37bielllsI will do it when I finish SICP (if it's not part of the book)
11:37bielllsThanks justin_smith dnolen and bronsa
11:47bielllsI'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:47tmtwdin lein repl I'm doing (load-file "bob_test.clj") and it doesn't work
11:48tmtwdfile not found exception
11:49tmtwdnvm
11:49tmtwdfixed it
11:49bielllsUsually clojure is fast enough, but sometimes you need speed that is close to java, and optimized clojure is not pretty
11:51bielllsBut we don't really like working in java
11:52bielllsI 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:53luxbockisn't Java a language that has syntax similar to C and compiles down to JVM byte code?
11:54bielllsYes, but with similar to C I also meant not OO
11:57justin_smithbiellls: but OO isn't a syntax
11:57justin_smithoh, "also", missed that, sorry
12:00bielllsI didn't explain myself well
12:01bielllsBut check a hello world in C and Java to see what I meant
12:03bielllsAlso, it would make it easier to manipulate clojure data structures
12:03bielllsAnd call clojure functions
12:06bielllsMy motivation was partly because I read somewhere that making a mixed clojure and java project was a painful experience
12:07bielllsI haven't tried it yet, so I don't know if that's accurate
12:07justin_smithbiellls: depends which API you use I think, and the using java from clojure part is easier
12:20bielllsok, I will try to do a mixed java and clojure project sometime and see if I run into any difficulties.
12:28tmtwdhow do I check the last character of a string in clojure
12:28tmtwd?
12:29luxbock,(last "foo")
12:29clojurebot\o
12:30ringer1,(last "foo")
12:30clojurebot\o
12:30tmtwdah okay
12:30tmtwdhow come I get this error? http://pastebin.com/8jbJUHw4
12:31ringer1very cool (first visit here and I am easily impressed)
12:31andyfjlast is linear time in length of string. If you want constant time access to last char, try (get s1 (dec (count s1)))
12:32oddcullytmtwd: :else is no function
12:32andyftmtwd: You've got incorrect extra parens in your cond
12:32tmtwdwhere?
12:32justin_smith,(:else {:else "is kind of a function, but not like that"})
12:32clojurebotwhere is log
12:32clojurebot"is kind of a function, but not like that"
12:32andyfClojure's cond is different than Common Lisp's
12:32tmtwdokay
12:32tmtwdill check out the else docs
12:32tmtwdi'm used to scheme and stuff
12:32oddcullytmtwd: well it could, but here you just want to have it as the final clause
12:33Bronsatmtwd: it's not correct even without the else btw
12:33andyf(cond (= "" arg) "Fine" :else "unknown")
12:34biellls:else is just convention though, right?
12:34tmtwdoh I see
12:34bielllsAny keyword is truthy
12:34Bronsabiellls: yes
12:34tmtwdso this is one of the ways clojure ruthlessly dispenses with parens :)
12:34Bronsayou can use whatever truthy value you want
12:34andyftmtwd: When it doesn't replace them with square brackets, yes :)
12:41bensugit 1git
12:41bensusorry, wrong app
12:41tmtwdhttp://pastebin.com/0yT8gtCv is this the right way to check that '?' is the last character of the parameter
12:41tmtwd?
12:42tmtwdI checked in the repl, it seemed to suggest yes, but I'm failing some tests
12:42biellls,(last "Hello")
12:42justin_smithtmtwd: oh, to test the last char, the best bet is .endsWith
12:42clojurebot\o
12:42bielllsReturns a character
12:42justin_smith,(.endsWith "hello" "o")
12:42clojurebottrue
12:43bielllsOr use \?
12:43justin_smithtmtwd: here's your issue ##(= "a" \a)
12:43lazybot⇒ false
12:44justin_smithbiellls: the advantage of endsWith is it doesn't need to turn your whole string into a seq
12:44justin_smithit's a well optimized built in method
12:45bielllsok, thanks
12:45tmtwdah i see
12:52bielllsJust tested it
12:52bielllsStrangely last runs faster in my computer
12:54justin_smithbiellls: criterium says .endsWith is 250x faster
12:55justin_smithbiellls: cite https://www.refheap.com/105306
12:56justin_smithwell, not 250x
12:56justin_smith,(/ 231.5 1.566)
12:56clojurebot147.82886334610473
12:56justin_smith~150x
12:56clojurebotPardon?
12:57justin_smiththat's still an insane difference in execution speed
12:57bielllsCool, I guess I will have to upgrade my benchmarking tools
12:57bielllsI used the time macro
12:57oddcullymaybe measuring unrealized lazy stuff?
12:57justin_smithcriterium is pretty great
12:57justin_smithoddcully: last of a string?
12:58oddcullyjustin_smith: yeah. just guessing.
12:59justin_smithoddcully: a random gc hit could throw time off easily
12:59justin_smithbut anyway, criterium is generally reliable, even though it takes ages to run
12:59oddcullywell just guessing. i have not seen the benchmark of OP
13:00justin_smithbest profiles.clj deps for dev: pallet/alembic, criterium, tools.trace
13:00justin_smithimho
13:04andyf.endsWith can be slow if there is reflection happening (in general, any Java interop call is subject to this slowness)
13:04andyf(set! *warn-on-reflection* true) can help find these
13:04andyftype hints to help eliminate them
13:04justin_smithtrue
13:05justin_smithI wonder if a type hint would speed up the implicit seq call in the version using last
13:08vashappy 4th friends
13:10justin_smithnope, can't even type hint a string literal (d'oh, of course)
13:12csd_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:12csd_From the apache storm source
13:12justin_smithcsd_: it means that if the user pases +, your code gets #'+
13:13justin_smith(for the clojure-bolt macro that is, same for conf-fn-system)
13:13tmtwdhow to check for an empty string? ie "" or " "?
13:13tmtwd.emptyString? arg?
13:13justin_smith,(defmacro pr-var [x] `(pr (var ~x)))
13:13clojurebot#'sandbox/pr-var
13:14justin_smith,(pr-var +)
13:14clojurebot#'clojure.core/+
13:14csd_justin_smith: so the purpose of the macro is to pass a quoted var to the fn?
13:14justin_smithcsd_: right, like most (every?) macro, the only reason you actually need it is syntactic convenience
13:15csd_im surprised that this couldn't be pushed down to the fn* though
13:15justin_smithcsd_: a function can't decide how it's args are interpreted
13:15justin_smith,+
13:15clojurebot#object[clojure.core$_PLUS_ 0x40ecd6ee "clojure.core$_PLUS_@40ecd6ee"]
13:15justin_smithyou can't get #'+ from that
13:16justin_smithI mean you could do a tree search of interned values, but there isn't a *sane* way to get #'+ from that
13:16justin_smiths/tree search/linear search/
13:17csd_justin_smith: why do the args need to be wrapped in (var)?
13:17justin_smithcsd_: probably because they want to embed them in a closure, but ensure that changes to the var are reflected in the running code
13:18justin_smithcsd_: 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:18justin_smith(here's where + is a less illustrative example, of course)
13:19justin_smithcsd_: 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:20csd_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:20justin_smithright, vars are thread-safe
13:22csd_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:23justin_smithcsd_: anything from weavejester
13:23justin_smithcsd_: ztellman's libs can be very enlightening
13:23justin_smithany of the prizmatic stuff
13:23justin_smith*prismatic
13:24csd_yeah those are all libraries though
13:24csd_right?
13:24justin_smithyeah, I missed the applications part, sorry
13:24justin_smithcsd_: circleci
13:27csd_ok
13:28csd_thanks let me know if you think of any others
13:28justin_smithI know of lots of apps (I wrote most of the code even...) but can't share them :)
13:30csd_i wish there was a good resource on writing large clojure apps. Seems to me like there's a need for that
13:30justin_smithyeah
13:30justin_smithit would be a lot of work
13:30csd_yeah
13:31justin_smithbut 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:32csd_i never feel comfortable with how i should handle program state, i.e. whether to have the so called God object or what
13:32justin_smithcomponent sorts that out nicely for me
13:33justin_smiththere's individual components responsible for some data, functionality or stateful resource, then a map describing who needs to use which
13:33csd_I feel most comfortable right now defining everything in `def`, within a large hashmap
13:34justin_smithhave you tried stuartsierra's component lib?
13:34csd_then i can do something like (:path-cache @platform) and be returned the Java cache object i need
13:34justin_smithbecause it's very close to that
13:35csd_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:35justin_smithcsd_: 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:36csd_but is the record initialized within a def, or within a function?
13:36csd_that's what trips me up
13:37csd_it's sort of splitting hairs ultimately
13:37justin_smithcsd_: 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:37justin_smithit's one top level record
13:38justin_smithbut 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:39csd_retry in what sense?
13:40justin_smithcsd_: atoms retry when concurrent modification attempts happen
13:40justin_smithwhile agents simple lock and do one at a time
13:40justin_smith*simply
13:41csd_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:43csd_justin_smith: thanks for letting me throw questions at you, gonna go make some lunch
13:44justin_smithnp, headed out for an errand myself
13:46donbonifaciobeen migrating a 4K LOC of clj to cljc. tests on lein: 220ms, node: 90ms
13:55tmtwdhow do I switch directories for cider?
14:27scottjtmtwd: maybe M-x cd?
14:27scottjtmtwd: be more specific
14:28tmtwdlet me try M-x cd
14:31tmtwdyeah, 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:31tmtwdwhat is the C-c C-l of cider?
14:31tmtwdiow
14:32scottjC-c C-l
14:33scottjcider-load-file
14:34rs0has anyone looked at Clojure<->Neovim integration?
14:35rs0Neovim 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:35rs0in other words, exactly what emacs has apparently been doing since the Carter administration or something
14:35justin_smithrs0: that's what inferior-lisp does
14:35justin_smithrs0: what cider does includes getting doc strings
14:36justin_smithautocomplete
14:36justin_smithshowing args as you use a function
14:36rs0true. i've used emacs and slime a few times when playing with common lisp
14:36lodin_Anyone else feel a need for a good lens implementation in Clojure?
14:37rs0lodin_: why?
14:38rs0lodin_: 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:38lodin_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:39rs0i don't understand your second point, but it sounds interesting
14:39rs0do continue
14:40rs0when i was looking at lenses i was desperate for a clojure-style "what problem are we trying to solve?" treatment
14:40lodin_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:41lodin_s/write/rewrite/
14:41lodin_or at least augment.
14:42lodin_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:43rs0the "key name mismatch" problem strikes me as a bit fishy
14:43rs0i'd need to see it in a practical context
14:44lodin_rs0: Would it be better if you had something with units in it? The typical example would be fahrenheit vs celsius.
14:45lodin_(Then you'd use an iso.)
14:45justin_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:47lodin_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:47rs0i dunno... i'm reminded of rich hickey's rule of thumb that "if your data is making decisions, your design is wrong"
14:47rs0this sounds a bit like a return to Smart Data
14:47justin_smithrs0: it's the lens making the decisions though, and lenses are not data
14:48tmtwdwhats the difference between defn and defn-?
14:48rs0tmtwd: defn- is private
14:48tmtwdrs0, to the ns?
14:48rs0tmtwd: it defines a function that's private to the namespace, yes
14:48tmtwdthanks
14:49rs0hard to google, i suspect
14:49rs0i remember that was a big concern when C# came out
14:51lodin_rs0: Not familiar with Smart Data.
14:52rs0lodin_: it's not a technical term... I'm basically using it to refer to OO-style data that isn't semantically transparent
14:52lodin_rs0: But this is just ad hoc polymorphism, but essentially bundle two functions (get and update) into a convenient interface.
14:58rs0lodin_: but you still think that lenses would be beneficial/coherent in a dynamically typed language like clojure?
14:58rs0lodin_: or at least, no worse than the present state of affairs?
14:59lodin_rs0: brb.
15:09hyPiRionrs0: so something à la define-setf-expander or defsetf in common lisp?
15:10rs0hyPiRion: I don't know enough about CL *or* lenses to say
15:11lodin_rs0: Absolutely.
15:12lodin_rs0: It's just about presenting your data through an interface.
15:12lodin_rs0: but importantly, lenses compose.
15:15lodin_rs0: The only issue with Clojure being dynamic is that it cannot implement pure (with Haskell type a -> f a).
15:17lodin_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:20lodin_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:21rs0lodin_: 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:22lodin_rs0: How do you mean? (Do you have a link to the gist?)
15:27lodin_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:30rs0lodin_: oh, that sounds like a job for transducers! =)
15:31rs0lodin_: 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:32lodin_I'm not sure how that would look. Could you write some example code?
15:34lodin_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:35lodin_So my previous function update-2nd-last would take (first table) as input.
15:36lodin_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:37lodin_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:47lodin_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:49lodin_So about dynamic languages, I think lenses find new uses cases there, the above with default values being one of them.
15:51rs0lodin_: i'm not sure this really fits into the overall Clojure philosophy
15:51lodin_rs0: How's that?
15:52rs0lodin_: well, even though lenses are functions, the intention is to view data through them, right?
15:52lodin_rs0: or update, yes.
15:52rs0right
15:53rs0lodin_: 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:53lodin_rs0: How does lenses change that?
15:55rs0lodin_: 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:56lodin_rs0: That's not what lenses are, but lenses can be used for that.
15:56lodin_But (update [0 reverse' 1] f) is nothing like that.
15:56lodin_It's just abstracting away the (set ... (f (get ...))) pattern.
16:00lodin_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:01rs0lodin_: can't you do that with extend-protocol?
16:02lodin_rs0: You mean have a method that returns the username, like (defprotocol Username (username [_] "Returns the username."))?
16:02rs0lodin_: 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:03lodin_rs0: Lenses are completely separate from how the data is represented, just like protocol methods are not part of the data.
16:04lodin_Lenses are function that the user decides he/she wants to use.
16:04lodin_s/function/functions/
16:04rs0lodin_: right, and defrecord lets you define methods as well
16:04lodin_rs0: Precisely.
16:04rs0actually, let me ask you something
16:04rs0can you compare and contrast lenses with http://rschmitt.github.io/dynamic-object/ ?
16:04lodin_So all that lenses do, is to bundle two methods, get and update.
16:05lodin_This makes it possible to abstract away (set ... (f (get ...))) and similar patterns.
16:06lodin_rs0: After looking at it for a few seconds, I'd say it's quite different.
16:10rs0lodin_: the main similarity is that it provides a set of functions that provide a "view" into data in a Clojure map
16:11rs0lodin_: 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:12lodin_rs0: With DynamicObject, how would you do the equivalent of update-in?
16:13rs0lodin_: unsolved problem
16:13lodin_rs0: So it's completely different. :-)
16:13lodin_A major point of lenses is that they compose.
16:14rs0lodin_: although you remind me, i was wondering about implementing update-in and the like in Collider https://github.com/rschmitt/collider
16:14lodin_So that first you abstract away (set ... (f (get ...)) and then you can abstract (set ... (set ... (f (get ... (get...)))))
16:14lodin_etc etc.
16:15rs0hm
16:15rs0what does that look like with sets?
16:16rs0vectors actually are Associative
16:16rs0but sets, well, you can basically do two things with them: test for membership and iterate over the contents
16:17lodin_rs0: Presumably you would have a mapping function in there. Also abstractable with lenses.
16:17lodin_Not exactly lenses, but traversals.
16:17lodin_Same same, but different. :-)
16:18rs0I dunno, man... maybe I'm biased
16:18rs0at this point I'm fairly predisposed to view concepts coming out of the Haskell space as navel-gazing until proven otherwise
16:19rs0I studied Haskell before Clojure. I was blown away by Clojure's far simpler and more direct solutions to problems I actually have
16:19lodin_You're not convinced that (update table [0 reverse 1] f) is a good abstraction?
16:19lodin_reverse', i mean.
16:19rs0what is reverse'
16:19lodin_it's the iso i mentioned above.
16:20justin_smithunholy union of get-in and -> I see?
16:20lodin_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:22lodin_rs0: Another would be (update 32 [fahrenheit<->celsius] inc), returning 33.8.
16:22lodin_Err, ignore [] since they're not needed.
16:23lodin_Compare with (-> 32 fahrenheit->celsius inc celsius->fahrenheit).
16:25rs0lodin_: since i mentioned this and you wanted to see it: https://gist.github.com/stuarthalloway/b6d1c8766c747fd81018
16:25tmtwdHow can I use repl to call functions directly instead of like this? (#'rna-transcription/transform-rna "C")
16:25justin_smithtmtwd: for starters, you can use require
16:25lodin_rs0: Or (let [x {:temp 32}] (->> x :temp fahrenheit->celsius inc celsius->fahrenheit (assoc x :temp)))
16:25justin_smith,(require '[clojure.string :as s])
16:25clojurebotnil
16:25justin_smith,s/join
16:25clojurebot#object[clojure.string$join 0x26f1ea7d "clojure.string$join@26f1ea7d"]
16:26lodin_rs0: The lens equivalent: (update x [:temp fahrenheit<->celsius] inc).
16:26zematisIs there a way to filter exactly n items out of a vector with a pred?
16:27justin_smithzematis: something like drop?
16:27lodin_zematis: filter is lazy, so you just take n items. Or is that the answer to another question? :-)
16:27rs0i think he means "the first n items matching the pred"
16:27rs0or... something
16:28zematisI want to only drop items where (= pred? true), and end up with a vector that contains m - n items.
16:28zematisCould do it with sort and then drop, but that wouldn't preserve the ordering.
16:29justin_smithzematis: (take n (filter p? c)) ?
16:29lodin_zematis: I see what you mean.
16:29zematisjustin_smith: There may be less than n items after the filter.
16:29justin_smithzematis: take doesn't care
16:30justin_smithit just sets a maximum
16:30zematisHmm. Then that should work!
16:30zematisThanks!
16:30justin_smith,(take 100 [:a :b])
16:30clojurebot(:a :b)
16:30zematisOh, no, that won't work.
16:30lodin_I think you mean filter as in remove, not separate and keep, right?
16:30zematisHere, I'll give an example.
16:31rs0zematis: you want to exclude the first N items in the vector matching pred?
16:31zematisrs0: yep
16:31lodin_zematis: You tricked everyone by saying filter. :-)
16:31zematisAh. Still new at this :)
16:31rs0lodin_: i don't blame him. this is why Collider collections advertise both "filter" and "exclude"
16:32rs0ok. i guess i'd create an empty transient vector and loop/recur
16:32rs0depends on how performance sensitive your use case is
16:32zematisShouldn't be that sensitive.
16:32rs0can't rrb-vectors be appended or something?
16:33lodin_rs0: Back to lenses. Do you see what I'm getting at with the (set ... (f (get ...))) examples?
16:34tmtwdare cursives paredit bindings the same as ciders/emacs, or can they be configured as such?
16:34rs0lodin_: 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:35lodin_rs0: That new protocol is the protocol of lenses! :-)
16:35lodin_rs0: If you would soup-up update-in you would reinvent lenses, I'm quite sure.
16:35lodin_Poorly, probably.
16:36lodin_I did precisely that, but before learning Clojure.
16:36justin_smitha combo of get-in, update-in, and ->
16:36rs0lodin_: I'm not sure why Associative isn't adequate
16:37rs0lodin_: that interface encapsulates the notion of a collection that contains elements "at" some sort of location or address that can be specified
16:37rs0(unlike sets which can merely be traversed)
16:37lodin_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:38rs0I don't know what that means
16:38lodin_rs0: err, i wrote get, i meant update.
16:39rs0so is this, like, shell globbing?
16:39rs0the * represents all paths to different :bar keys?
16:39lodin_If we had a traversal called seq', you could write (update (range 5) seq' inc) ; (1 2 3 4 5).
16:39lodin_But since lenses and traversals and what not (http://i.imgur.com/ALlbPRa.png) compose, then you can also do
16:39rs0,(map inc (range 5))
16:39clojurebot(1 2 3 4 5)
16:40lodin_(update {:foo (range 5)} [:foo seq'] inc) ; {:foo (1 2 3 4 5)}
16:41rs0lodin_: that diagram is worse than the Scala collections library class hierarchy
16:41lodin_rs0: I know, it's horrible.
16:41lodin_Fortunately, this is Clojure, so you don't need to look at it. ;-)
16:41rs0lodin_: well, the types are still there
16:42lodin_rs0: Sure. And for good reason.
16:42rs0lodin_: just because I don't have to look at them doesn't mean they go away
16:42lodin_You don't have to care when using it though, as long as you do things that make sense.
16:43rs0oof. that's not reassuring. that sounds like foreshadowing
16:45lodin_Anyway, the point is that there are different things capable of doing different things, but they all compose.
16:46lodin_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:47rs0something 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:49rs0i seem to see a lot of research out of the Haskell space of the form "look at this insanely complicated abstraction! it COMPOSES!"
16:49rs0say, Arrows or something
16:51rs0actually, arrows are a generalization of monads, so I guess they fall into the abstraction-to-end-all-abstractions category
16:53lodin_Dunno, I'm not that familiar with what's going on in Haskell.
16:53lodin_rs0: Can you give an example of ideas that compose with each other in Clojure?
16:55rs0lodin_: 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:57lodin_rs0: Don't know which talk/article you're refering to, but isn't the same true for Haskell?
16:58rs0lodin_: 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:59lodin_A good strategy, no?
16:59rs0lodin_: but Haskell also has a more academic component with grad students studying hardxxxcore type theory
16:59rs0lodin_: 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:00lodin_rs0: I'm more interested in which ideas you mean compose in Clojure, and how that contrasts with Haskell.
17:03rs0why the hell don't i just have a bookmark folder or something with all the clojure talks
17:04tmtwdanyone use exercism?
17:05rs0lodin_: okay, for example
17:06lodin_rs0: I know Clojure, but I don't know Haskell, so I can't contrast it.
17:06rs0lodin_: in Clojure, you have eager evaluation and no concept of "effects" tracked by the type system
17:07lodin_... beyond lazy vs strict evaluation, and static typing.
17:07rs0lodin_: just a sec
17:07rs0lodin_: 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:08rs0lodin_: 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:08rs0lodin_: if you want to combine the effects of the Writer monad and the State monad, you have to create a monad transformer stack
17:09rs0lodin_: so all of the monads in the stack need to know about each other; it's somewhat monolithic that way
17:09lodin_Right.
17:09rs0lodin_: you also now have all this incidental complexity--for instance, the order of monads in the stack is critical to get right
17:10lodin_Is that really incidental complexity though?
17:10rs0absolutely!
17:10rs0monad transformers have nothing to do with the problem you're trying to solve
17:10lodin_Reversing the order of the stack changes the semantics, no?
17:11rs0the stack itself is incidental complexity
17:11tmtwdanyone know why my functions don't work as expected ? http://pastebin.com/ZYNjzfxT
17:11lodin_rs0: Please elaborate.
17:11rs0i 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:12lodin_tmtwd: You're testing for "C" instead of \C etc. I think that's the problem.
17:12rs0a 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:13rs0a 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:14rs0I 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:14rs0(since monad transformers are also monads)
17:15lodin_rs0: What's the worst/deepest monad stack you've used?
17:16tmtwdlodin_, ah, good tip :)
17:16rs0lodin_: 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:17lodin_tmtwd: You might want to check out (case ...) as well.
17:18lodin_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:20tmtwdlodin_, oh kinda like haskell?
17:20lodin_tmtwd: Dunno. :-)
17:21lodin_Or you mean case in Haskell?
17:21rs0or the haskell 'map' function?
17:21rs0(as opposed to the map data type)
17:21tmtwdso, we can't throw something in the else statement of cond? http://pastebin.com/F7UimAA8
17:22lodin_tmtwd: I think so, but you're missing a dot.
17:22tmtwdlodin_, oh no nvm . I failed at understanding you
17:22lodin_Can you instantiate Throwable btw?
17:23tmtwdlodin_, yeah that was it
17:23tmtwdi dunno thats just what I saw somewhere
17:23tmtwdbut it loads now
17:24lodin_I guess you can then.
17:25lodin_I usually throw Exception. Don't know why.
17:27lodin_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:29lodin_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:30scottjlodin_: have you seen https://github.com/megakorre/glasses ? (idk anything about it, just found it searching clojars for lens)
17:31lodin_scottj: Yes.
17:34tmtwdHow to turn ("G" "A" "B") into "GAB"?
17:34lodin_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:34tmtwdconcat?
17:34lodin_tmtwd: (apply str ...)
17:34clojurebotconcat is considered a cat
17:34Bronsatmtwd: apply str
17:35tmtwd, (apply str ("a" "b"))
17:36clojurebot#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:36tmtwdi don't think that quite works
17:36oddcully,(apply str ["a" "b"])
17:36clojurebot"ab"
17:36lodin_tmtwd: As a general rule, use [] instead of () when writing literal sequences.
17:36oddcully,(apply str '("a" "b"))
17:36clojurebot"ab"
17:36lodin_,(apply str '(x y))
17:36clojurebot"xy"
17:36lodin_Probably not what you wanted.
17:37lodin_I was bitten by that when I was learning Clojure.
17:38tmtwdlodin_, ah gotcha, the return from repl was with parens
17:39lodin_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:41lodin_scottj: Like (update x [:foo mapped-vec] #(add-noise rng %))
17:41lodin_scottj: I'm expecting rs0 to react now, but I think we need a monad for that. :-)
17:42rs0damnit i stopped paying attention
17:42rs0let me read up
17:42scottjlodin_: recall the names of other clojure lens implementations?
17:43lodin_scottj: Not really, I've only used glasses, but I can see if I find any that i recognize.
17:43rs0"purely functional random number generator"
17:43rs0why not just create a java.util.Random with a deterministic seed?
17:44rs0if... this is about testing or something
17:45scottjhttps://speakerdeck.com/markhibberd/lens-from-the-ground-up-in-clojure
17:45lodin_Have you seen gfrederick's talk on rngs?
17:45lodin_scottj: iirc, that one uses [value updater] approach, aka the "functor approach".
17:48lodin_I'm not sure now glasses work, I think it's analoguous but spelled differently. But I'm really not sure.
17:48amalloyrs0: if it's an immutable RNG, you can do things with it you couldn't do with a Random
17:49rs0scottj: i've actually seen both versions of that slide deck
17:49amalloylike 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:49rs0amalloy: ThreadLocalRandom?
17:49rs0actually, you can't control the seed in that case
17:50rs0well, 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:50rs0er
17:50rs0immutable RNG instance
17:50rs0i'm writing up a junit issue and i'm distracted
17:50amalloyhuh? no you wouldn't
17:52rs0oh i see, you're referring to taking the state of the RNG and holding on to it in each thread
17:52rs0so your RNG is basically a pure (next) function over a given seed and some pseudorandom number generation algorithm
17:52amalloyyes, of course. anything else wouldn't be immutable
19:02lodin_My solution now would be to do (let [rng-atom (atom rng)(update x [:foo mapped-vec] #(let [[rngadd-noise @rng %
19:02lodin_err
19:03lodin_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:05lodin_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:10lodin_and update was (fn [x lens f] (update-with nil x lens (fn [_ v] (second (f v))))).
19:10lodin_err,
19:10lodin_and update was (fn [x lens f] (update-with nil x lens (fn [_ v] [nil (f v)])))
21:46TEttingerhuh, I'm not sure if this is a lein thing or a java problem or a cursive/intelliJ problem.
21:46TEttingerjava.lang.Exception: Problem opening jar C:\Users\noto\.m2\repository\org\clojure\clojure\1.7.0\clojure-1.7.0.jar
21:46TEttingercaused by having a dep on [org.clojure/clojure "1.7.0"]
21:47TEttingerthere's one error after that: Caused by: java.util.zip.ZipException: error in opening zip file
21:51TEttingerI just unzipped it manually, it is totally a valid jar/zip
21:54TEttingerhuh, I think it may have been me pressing the run button twice by mistake in Cursive
22:22TEttingercfleming: is there a reason why Cursive doesn't show lein run as an option in the Leiningen Tools window?
22:22TEttingerthere's uberjar, which I think also requires a -main method
22:23TEttingerI 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:24justin_smithTEttinger: or when you require that namespace even
22:25justin_smithTEttinger: just a wild guess - is run hooked up to the standard "run project" UI?
22:43TEttingerjustin_smith, nope
22:43justin_smithTEttinger: looks like Run -> Edit Configurations ? https://cursiveclojure.com/userguide/repl.html
22:43TEttingerrun project doesn't run -main
22:44TEttingeroh?
22:44justin_smithI mean that page is about starting a repl, but it shows things that appear to be related to setting up run configuration...
22:44TEttingerI see VM params and Script params
22:45justin_smithscript params "clojure.main -m your.ns" would work
22:45TEttingerit looks like this: http://i.imgur.com/8IZ6T6K.png
22:45TEttingerdash m?
22:45justin_smithoh, it might be just "-m your.ns"
22:46justin_smithone moment, checking
22:48TEttingerI have an "unused global declaration -main" warning too :|
22:48justin_smithbecause of a (defn -main ...) ?
22:48justin_smithis the ns set up to be your main ns in project.clj?
22:48TEttingeryes
22:48TEttinger:main ^:skip-aot infinite-raid.core
22:49justin_smithinteresting
22:49TEttingerI created a template with `lein new app infinite-raid`
22:49justin_smith(I don't really work on this project from this computer, so testing took a while)
22:50TEttingerchanged to use clojure 1.7.0, added a dep and usage of a java lib, that's about it
22:50justin_smithif you set it to execute "lein run -m your.ns/-main" it should just work
22:50TEttingeras a new run config?
22:50justin_smithtry that from a repl of course, but it works here
22:50justin_smithTEttinger: yeah
22:52justin_smithTEttinger: 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:57TEttingerjustin_smith: it ended up working out by making a new lein run config, with just the arg `run`
23:00justin_smithTEttinger: oh, that's easy!
23:00TEttingerhaha
23:00justin_smiththat was nearly my first guess
23:02TEttingerwell 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:02TEttingerit's always entertaining to see how much shorter the clojure is :)
23:25rhg135Is this supposed to hang, or did I miss something. https://www.refheap.com/105312 networking is a pain
23:29justin_smithrhg135: you can use jstack to see what each of the threads in your vm is doing
23:30rhg135is jstack one of the jvm tools?
23:32justin_smithrhg135: yeah, it comes with the vm
23:32justin_smithit shows a stacktrace for every thread, if you give it your app's pid
23:33rhg135I'm using a debugger, just didn't think to pause the vm
23:41rhg135this is getting weird
23:43rhg135apparently 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:43rhg135but when i type it and use a different port it hangs and the trace reveals netty is waiting