Fork me on GitHub
#clojure
<
2016-09-12
>
amacdougall00:09:12

Hm, threading question... I've got a grid. You can create it with create-grid, look up individual cells with find-cell, and then use link to return a grid where some cells are linked. This is pretty easy in a let:

(let [grid (grid/create-grid 2 2)
      grid (link (find-cell grid 0 0) ::e)
      grid (link (find-cell grid 0 0) ::s)]
  ; now the cell at 0, 0 has exits :e and :s. The cell at 1, 0 has an exit :w,
  ; and so on.
  )
But I'm wondering how to establish multiple links on a grid in a ->. It seems like after one link, this thread would be working with a stale grid, not the intermediate linked grid:
(-> (create-grid 2 2) (link (find-cell grid 0 0) ::e) (link (find-cell grid 0 0) :s)))

amacdougall00:09:34

Is there a way to handle this, or am I pushing -> beyond what it is expected to handle?

amacdougall00:09:22

I guess I could handle it with a (defn link-cell [grid x y direction] ...) function. ¯\(ツ)

amacdougall00:09:06

But it's convenient and self-documenting to have [grid cell direction].

amacdougall00:09:13

Or link could have two signatures: [grid cell direction] and [grid x y direction]. But I'm always wary of using argument counts to mean different argument types instead of just additional optional args.

mfikes00:09:14

@amacdougall as-> might help:

(macroexpand 
  '(as-> (create-grid 2 2) grid 
     (link (find-cell grid 0 0) ::e) 
     (link (find-cell grid 0 0) ::s)))

amacdougall00:09:24

Just what the doctor ordered! I was only vaguely aware of that macro. Thanks for the tip!

mfikes00:09:00

Your original let is fine in my view, but just trying to address your use of -> 🙂

amacdougall00:09:19

as-> doesn't automatically interpose the intermediate result, so the forms had to be (link grid cell direction), but it was still handy.

amacdougall00:09:49

And yeah, looking at it, I don't think it's more economical or readable than the let version, actually. But still good to know.

grounded_sage03:09:13

Is anyone doing Artificial Neural Network stuff with Clojure. Been reading up about it a bit lately and I find it very interesting.

yonatanel07:09:02

@alexmiller re data formats (ion, transit etc), do you know which has a better node.js support? It's hard to tell a js programmer to construct EDN using keyword function instead of just sending JSON.

kurt-yagram12:09:59

using datomic, fetching fields from the database look something like:

(d/q query (d/db conn) arg)
defining a query seems to be a bit awkward, but more probably, I must be missing a better/nicer solution. query is a (quoted) vector, so to avoid evaluation of the symbols (I guess). For now, I define query like this:
(let [ ...
   query `[~':find [(~'pull ~'?e ~fields) ...]
           ~':in ~'$ ~'?f
          ~':where ~'[?e :some/field ?f]]
I need all the ~' so all the symbols are not namespaced. Only fields must be evaluated. I'm just wondering, well... there probably is a better way to define query (generate a quoted list in which a few symbols/expressions are evaluated)?

hans12:09:49

kurt-yagram: why would the symbols be namespaced?

hans12:09:13

ah, the symbols, yes, but not the keywords.

hans12:09:35

kurt-yagram: i did not know that difference between backquote and quote, but in any case: does datomic care about the namespace of the symbols?

kurt-yagram12:09:38

yeah, the keywords, true, I shouldn't unquote them

kurt-yagram12:09:06

🙂 that's a good question as well. Didn't try, actually, with the namespaced symbols 😛

hans12:09:29

maybe that is something to try first. could be purely a cosmetical issue.

kurt-yagram12:09:02

will do, first fix code

hans12:09:19

i still wonder why (not= `[foo] '[foo])

hans12:09:30

seems counter intuitive to me.

gfredericks12:09:43

because

(not= `foo 'foo)

gfredericks12:09:10

which is because

` 
changes the symbol based on the current namespace

hans12:09:12

gfredericks: ah, that's just my question simplified.

hans12:09:02

hm, so backquote has some specialized behavior to support macro writing, is that fair to say?

gfredericks12:09:38

three special behaviors: symbol qualification, gensyms, and unquoting

kurt-yagram12:09:08

so... @hans : I need the unquoting ~' on the symbols...

hans12:09:57

okay, this goes against my common lisp intuition then. it should prevent me from using backquote for anything other than writing macros. 🙂

Alex Miller (Clojure team)12:09:32

@yonatanel certainly transit-js should work, not sure of details though

gfredericks12:09:53

@hans it's useful to use it in functions that are helpers for complex macros

Madara Uchiha13:09:09

I need a slight push in the right direction.

Madara Uchiha13:09:49

Clojure for the brave and true, chapter 7's exercises has this:

Madara Uchiha13:09:04

Create an infix function that takes a list like (1 + 3 * 4 - 5) and transforms it into the lists that Clojure needs in order to correctly evaluate the expression using operator precedence rules.

Madara Uchiha13:09:13

How would you approach something like that?

mpenet13:09:58

About serialisation in my experience it's best to choose something language agnostic and well established. Years down the road when your system needs to integrate with some new language/platform you ll be happy you made that decision. There are exceptions of course (always).

manutter5113:09:08

@madarauchiha One approach I’ve used is to make a function that takes the current ast (abstract syntax tree) and the current list to parse, returns ast and remaining. If the parser function succeeds, ast is the updated AST, and remaining is the rest of the string to parse (if any). If it fails, ast is nil, and remaining is the original string that was passed in

Madara Uchiha13:09:14

Aren't the current ast and the current list to parse the same?

manutter5113:09:17

That’s the basic pattern, and you use that to build a parser for each individual operator you want to parse for, so like parse+, parse*, etc.

manutter5113:09:13

Not quite — the AST is an abstract syntax tree, where you have like [operator [operator [argument argument]] argument — nested arguments not just a straight list

Madara Uchiha13:09:41

Where do I get that from? Or is that what I build?

manutter5113:09:16

Right, you build that using the functions you write that know how to parse expressions

manutter5113:09:28

That’s actually writing a simple “compiler”, so if you’ve never done anything like that, there’s a lot involved

manutter5113:09:46

by the way, there’s a #braveandtrue channel, you might want to move the conversation there

manutter5113:09:04

Personally, I would use Instaparse, but in the context of Brave And True that might defeat the purpose of the exercise.

Madara Uchiha13:09:18

I'm not dealing with strings here though

Madara Uchiha13:09:31

But with a form

Madara Uchiha13:09:45

(Not sure how much that matters, I would think that using forms instead of strings should make things easier)

manutter5113:09:56

Sorry, I’m used to thinking of this problem in terms of strings, but the same general approach works with lists

manutter5113:09:29

Working with lists does help by doing one of the initial parsing steps for you.

manutter5113:09:52

One thing I might also play with is writing a classifier function to start with, so for example (1 + 3 * 4 - 5) would become a list of pairs like this: ([:num 1] [:op :add] [:num 3] [:op :mult] [:num 4] [:op :sub] [:num 5])

manutter5113:09:47

So the first member of the pair is just a description of the type of thing you’re dealing with, and the second member tells you the actual value. That way it’s easier to pick out patterns like “number followed by operator followed by number"

Madara Uchiha13:09:51

But that doesn't help me with the order of execution problem

Madara Uchiha13:09:02

I'm looking more towards expression op expression

manutter5113:09:20

Hrm, the more I get into this, the less sure I am that I’m helping or just confusing things 😕

Madara Uchiha13:09:41

It's OK, I'm a self taught programmer with no formal education

manutter5113:09:44

I’m so used to reaching for Instaparse for stuff like this, I forget how to do things manually

Madara Uchiha13:09:02

So things like compilers and syntax trees I am bound to have gaps about.

manutter5113:09:14

Yeah me too.

manutter5113:09:26

Ok, I’m trying to remember, I think the canonical approach is to say “a term is a number by itself, or a term plus a term, or a term minus a term” and then “an expression is a term by itself, or an expression times and expression, or an expression minus an expression”.

manutter5113:09:30

Then you write functions that try and build a valid tree of nested terms and expressions without leaving any unparsed numbers or symbols in the list

Madara Uchiha14:09:21

That honestly sounds far too complicated for a beginner XD

manutter5114:09:33

Frankly it does, which makes me a little surprised it’s an exercise in B&T

manutter5114:09:08

I mean, it’s the “Hello, World” of compiler design class, but still.

manutter5114:09:22

I haven’t read B&T yet, what’s in chapter 7?

Madara Uchiha14:09:31

Basic of Clojure parsing/evaluating model

Madara Uchiha14:09:43

And initial touching of macros

elise_huard15:09:34

Hi, is there a known approach in clojure to store RSA private keys in clojure? I remember using keystores in my java days, but haven't found anything more than a slightly abandoned-looking project https://github.com/weavejester/crypto-keystore

weavejester15:09:10

IMO, Java keystores are an evil to avoid if possible 🙂

weavejester15:09:04

The most straightforward option is just to store keys plaintext and load them in directly.

weavejester15:09:03

Obviously ensuring that the file permissions restrict read-access.

elise_huard15:09:27

@weavejester yes I remember them not being a huge bundle of fun 🙂

elise_huard15:09:43

OK, makes sense, I'll investigate how to lock it all down in the simplest way possible

husain.mohssen20:09:34

I have a very noob Q: what’s the difference between (int? 3) and (integer? 3) in the latest version of clojure ?

Lambda/Sierra20:09:18

@husain.mohssen int? is only true for fixed-precision integers: java.lang.Byte, .Short, .Integer, and .Long. integer? is true for all of those and also arbitrary-precision integers, java.lang.BigInteger, clojure.lang.BigInt.

amacdougall21:09:20

Last night I found myself with a curious situation: I want to maintain a set of lines which have been drawn in this SVG graph. A line, in SVG, has a start and end point: <line x1="0" y1="0" x2="10" y2="10" />. I figured I could maintain the Hiccup equivalents in a Clojure set. However, I quickly ran aground when I realized that I want to consider a line and its reverse to be equal. For instance, (conj #{{:x1 0, :y1 0, :x2 10, :y2 10}} {:x1 10, :y1 10, :x2 0, :y2 0}) should not add to the set.

amacdougall21:09:28

I ended up avoiding the entire thing by doing a different line drawing algorithm. But it seems like I could get this behavior by "subclassing" the set collection type to implement a special equality function. LineSet or something.

amacdougall21:09:54

I'm just not sure exactly what Clojure language features I would use to achieve this. I'm still hazy on the usage and advantages of protocols vs multimethods and such.

amacdougall21:09:59

To put it much more simply, how do I get something that acts like a Clojure set in every way, but uses a custom function for its equality checks?

akiva21:09:28

I just chuckled.

Alex Miller (Clojure team)21:09:56

equality by value is an important part of the assumptions Clojure uses and works in tandem with immutable collections

Alex Miller (Clojure team)21:09:33

sets (that is, things that implement IPersistentSet) are expected by set functions to implement equality by set contents and that’s implemented in the language itself (in the functions that implement =)

Alex Miller (Clojure team)21:09:52

breaking that assumption is likely to break other parts of Clojure in possibly surprising ways

Alex Miller (Clojure team)21:09:43

if you want to maintain an additional constraint like this, you could make a function that enforced it for you when adding a line to the set

Alex Miller (Clojure team)21:09:30

or you could use a different data structure (an index) that structured lines as pairs of points with some rule for the ordering of points in the line

Alex Miller (Clojure team)21:09:35

or you could implement an entirely new function (`isomorphic`, not =) that answered this question for you

Alex Miller (Clojure team)21:09:39

as a general rule, if you start mucking with equality in Clojure, you’re probably fighting the language, and eventually you will lose ;)

Alex Miller (Clojure team)21:09:26

all that said, one way to do this though is to define your own collection with deftype and extend the proper interfaces to act as an IPersistentSet. You would not need to mess with equality - you could merely wrap conj to canonicalize your line defs by sorting the points and thus avoid ever creating a set with lines with swapped points.

nwjsmith21:09:00

@amacdougall what about modeling it as a set of points (tuples) rather than a map? i.e. #{[x1 y1] [x2 y2]}

nwjsmith21:09:18

or maps, #{{:x 0 :y 0} {:x 10 :y 10}}

dpsutton22:09:13

When loading a time from a database, on my local i'm getting an hour difference from the server. both agree that it is 5:07 central time though

dpsutton22:09:56

dealing with the a ms sql server, and getting org joda time objects in clojure

shaun-mahood22:09:29

@dpsutton: Are you using clj-time?

dpsutton22:09:57

with jdbc, coerce and core

shaun-mahood22:09:22

Are you using clj-time.local?

shaun-mahood22:09:56

See if https://github.com/clj-time/clj-time#clj-timelocal helps you out at all - I found it really difficult to get things working properly when I first started to work with it.

dpsutton22:09:11

oddly enough its been working for a while

dpsutton22:09:26

but is now not working

shaun-mahood22:09:26

Oh that's annoying. Any changes that can help pinpoint why?

dpsutton22:09:18

updated ubuntu 14.04 -> 16.04 and java 7 -> java 8. But had issues with sql server driver and jdbc and microsoft's 3.0 driver so downgraded to java 7

dpsutton22:09:30

so net was 14.04 -> 16.04

shaun-mahood22:09:14

Here are a couple of utility functions for dealing with times that helped me a lot - might give you a quick way to check if there is a problem

(:require [clj-time.local :as l])

(def month-name-formatter (f/with-zone (f/formatter "MMM dd, yyyy")
                                       (t/time-zone-for-offset -7)))

(def hour-minute-formatter (f/with-zone (f/formatter "MMM dd, yyyy hh:mm aa")
                                        (t/time-zone-for-offset -7)))

(defn now-string []
  (f/unparse hour-minute-formatter (l/local-now)))

(defn today-string []
  (f/unparse month-name-formatter (l/local-now)))

shaun-mahood22:09:01

Try running those and see if you get what you expect (probably need to change time-zone-for-offset value though)

dpsutton22:09:13

i will. thanks shaun

dpsutton22:09:21

i've got to head out now but i'll tackle this in teh morning

shaun-mahood22:09:19

Also worth replacing the MS driver with net.sourceforge.jtds/jtds, it works really well and I've not had any issues with it.

idiomancy22:09:49

@alexmiller you recommended that I listen to the cognitech podcast with rich hickey about spec. it was suuuper awesome, thank you. it completely cleared up everything for me.

idiomancy22:09:28

I was struggling with the concept of namespaced keywords. it's now extremely clear what the point is, and im developing my projects in that direction now.

idiomancy22:09:43

defining components instead of aggregates is brilliant.

idiomancy22:09:20

@everybody-else does anyone know how to stop the repl printing expanded namespaces?

idiomancy22:09:23

id prefer ::my-key to be printed in the repl, rather than :my.ns/my-key

idiomancy22:09:52

im sure theres some dynamic binding

idiomancy22:09:08

like

*print-namespaces*
or something, but I havent found it yet

idiomancy22:09:52

@bfabry your help was awesome in that regard as well

bfabry22:09:55

I'm pretty sure there is @idiomancy and I think I saw it listed in a changelog. is ther changelog in an easily digestible format anywhere ala CHANGES.MD?

bfabry23:09:33

actually that's symbols, not keywords

dadair23:09:55

Hi there, I am trying to get a raw (unmodified) duct-framework template working in a Docker container using docker-compose. I can get the .jar to run, and it says that it is running the server at <container>:3000, and I've forwarded that port to 80 in the docker-compose file, but I can't seem to connect to the server from a browser on my host (at https://[machine-ip]). I've uploaded the docker files to a gist (https://gist.github.com/adairdavid/4a6788002de7f96f5c075c84570015b0), would anyone be able to point out any mistakes I've made? Or try to recreate this using your own clojure application? Sorry if this is more oriented to the docker side of the equation, but maybe I've done something wrong on the clojure side?

tanzoniteblack23:09:40

@dadair 1.) are you on a mac/windows and using docker via a virtual machine that has a different ip address than the actual machine’s or 2.) are you on a machine where 80 is a privileged port that you sometimes can’t access without jumping through hoops (like…the afore mentioned mac bit)

dadair23:09:17

I'm on a mac, and I'm running docker by following the getting started guide (docker-machine with virtualbox driver). I'm able to run other docker examples (e.g., their nginx example) and I can connect to it from http://[machine-ip], I wiped that machine and re-created for a fresh machine for this clojure app, but can't connect to it through host browser

tanzoniteblack23:09:43

run the command docker-machine ip and see if you can connect to that machine

dadair23:09:08

that's the http://[machine-ip] I'm using

dadair23:09:31

with the nginx example, works great

tanzoniteblack23:09:33

also, if your code is opening the server on port 3000, and you want to connect to it on port 80 when talking to the docker instance, you don’t need the expose 3000 command in the dockerfile; the ports 80:3000 should be good enough

dadair23:09:18

awesome, thanks. I think that expose is an artefact of hacking away at this trying to make it work -_-

dadair23:09:57

and happy to put up example files after this is working for other people trying the same thing

dadair23:09:04

thanks for your help so far!

tanzoniteblack23:09:09

otherwise, I don’t see anything weird?

tanzoniteblack23:09:53

you might try doing a docker exec -it <name-of-container> bash and seeing if you can curl your server on localhost:3000 to verify that the server is working correctly and it’s definitely a connection issue from the outside

dadair23:09:34

was just trying that, it returns the expected duct index.html

dadair23:09:42

so it's something from host->container

tanzoniteblack23:09:23

oh…not sure what it is then. Sorry I couldn’t actually help

dadair23:09:48

no problem, thanks for looking into it!

tanzoniteblack23:09:54

one more thing you could try, is just opening port 3000 to the container (i.e. ”3000:3000”) and make sure it’s not related to os x being screwy with port 80; I’ve run into that before

dadair23:09:31

no luck, and docker ps shows 0.0.0.0:3000->3000/tcp for the container ports