Fork me on GitHub
#clojure
<
2016-04-21
>
fasiha01:04:58

When I started using Clojure a few weeks ago, I didn't understand why require needed a quoted vector, i.e., (require '[clojure.string :as string]). Now, I still don't understand because I've never seen or used a quoted vector. So: why does require need the vector to be quoted?

dpsutton01:04:16

my guess is that the name you give it would throw an error if it were unevaluated

dpsutton01:04:52

clojure.string presumably evaluates into a known thing, :as is a keyword, but string would evaluate to something unknown. and then there would be a symbol interred erroneously

dpsutton01:04:26

presumably (and i really don't know for sure here) you are passing all this info to the macro which can do what it wants on its own with the raw info before the code is evaluated. the macro can form this into valid forms

loganmhb01:04:57

@fasiha: what actually need to be quoted are the symbols inside the vector. before it’s been required, ‘clojure.string doesn’t map to anything, and neither does ‘string, as @dpsutton pointed out. quoting the whole vector is easier than quoting each symbol.

loganmhb01:04:10

you do not need to quote the require vectors in the ns macro, also, because the macro receives the unevaluated forms anyway

loganmhb01:04:44

e.g.

(ns foo.core
  (:require [clojure.string :as string]))
works fine.

fasiha01:04:36

Well I'll be a monkey's uncle. (require ['clojure.string :as 'string]) does work as you say @loganmhb. So what I get from this is require isn't a macro, like ns

fasiha01:04:26

Super-duper-awesome. Clojure-grade cerebral reason behind it all. Thanks!

loganmhb01:04:34

glad that helped!

fasiha01:04:45

You know how with some authors, you just have to be erudite to understand the various layers and allusions and subtexts of their writing? I feel that way when working with Clojure. I'm not a very learned person but somehow I feel like I have to think very hard when getting things to work in Clojure.

dpsutton01:04:49

that's the way i've found lisps. I'm only a few weeks into clojure but i've done some elisp and some common lisp

dpsutton01:04:09

the great thing about this is that your boss won't laugh in your face if you suggest putting a lisp into production when its on the jvm

dpsutton01:04:31

but read peter norvig's book on ai. its in common lisp and its absolutely crazy. I'm halfway through

borkdude07:04:54

@dpsutton: I love that book. One of the BEST programming books I have read during my CS studies and it wasn't even on the curriculum.

borkdude07:04:46

and I didn't even read it completely, now that I think of it simple_smile

borkdude07:04:41

@fasiha: you're not the only one having this experience. Some other newcomers find the Clojure docs a bit terse.

bojan.matic07:04:21

(= #(println %1) #(println %1))

bojan.matic07:04:30

can anyone explain why the above returns false?

bojan.matic07:04:43

i was expecting it to be true after all the value of values and PLOP talks simple_smile

grav08:04:50

(= #() #()) also returns false.

borkdude08:04:09

function equivalence is not a solved problem, not even in Haskell

grav08:04:16

I guess the fns are new objects

grav08:04:51

You can def the functions first.

borkdude08:04:47

If you def the functions first, they will still be two different objects

bojan.matic08:04:01

i understand it must be different references underneath, kind of like if you compare two array/list literals in something like ruby/python/js - even if they have the same data the equality is still false

bojan.matic08:04:23

clojure has that one solved

bojan.matic08:04:30

it would’ve been nice if it extended to functions too

bojan.matic08:04:22

my line of thought was that function equivalence should be easier for languages that are homoiconic

bojan.matic08:04:26

is that wrong?

bojan.matic08:04:49

@borkdude: but if i def two lists, they still compare to true

bojan.matic08:04:53

user=> (def a '(1 2 3))
#'user/a
user=> (def b '(1 2 3))
#'user/b
user=> (= a b)
true

borkdude08:04:01

@bojan.matic: function equivalence is an undecidable problem

bojan.matic08:04:44

but in lisp, functions are just lists, and we can already compare lists for equivalence

borkdude08:04:14

at compile time yes, at runtime no.

bojan.matic08:04:45

i think i see what you mean, function equivalence in the broader sense may be undecidable

bojan.matic08:04:51

but two functions with the exact same AST?

bojan.matic08:04:58

shouldn’t that be decidable?

borkdude08:04:18

@bojan.matic: like I tried to say, that should be decided at compile time, but = is a function, so it can't

bojan.matic08:04:09

what about a macro that overrides = and at compile time can figure out if it’s passed all functions? 😄

borkdude08:04:33

you could try

bronsa08:04:32

what about (= {:a (fn [] 1)} {:a (fn [] 1)}) then?

bronsa08:04:25

trying to compare functions is just meaningless, there's no sane/consistent/possible/meaningful way of doing it

plexus08:04:30

@bojan.matic: I couldn't resist

plexus08:04:11

(=== (fn+ [x] (println x)) (fn+ [x] (println x)))

bojan.matic08:04:11

but can we do it without using fn+ in the body, but just plain old fn?

plexus08:04:01

you need some way to hang on to the original form, which clojure doesn't do. Even if it did it wouldn't be terribly useful.

plexus08:04:14

(=== (fn+ [x] (println x)) (fn+ [y] (println y))) ;;=> false

bronsa08:04:35

&form is available from macros

plexus08:04:02

good point, that would clean the above up a bit simple_smile

sgrove08:04:52

Hey all, how can I change the representation of a record in the REPL/println? Is there a protocol like toString that I can implement?

bronsa08:04:09

@sgrove: print-method

bronsa08:04:36

user=> (defrecord X [])
user.X
user=> (defmethod print-method X [_ w] (.write w "FOOO"))
#<MultiFn clojure.lang.MultiFn@7de26db8>
user=> (X.)
FOOO

sgrove08:04:29

Ah, great, thanks @bronsa

sgrove08:04:38

And do I have to be worried about it being round-trip-able?

sgrove08:04:44

I’d rather it not be

bronsa08:04:02

if you want to embed literals for that record in code, yes no, nevermind

telent09:04:25

I feel like this is probably an FAQ, but haven't found a good answer: any way to re-export a symbol from one namespace to another? Let's say I have a library foo with several namespaces foo.ex, foo.run, foo.parsebut my clients would like to write a single [require foo.api :as foo] and get all the symbols they need

telent09:04:17

i could just define vars and set them to the value of the vars in the other namespaces (ns foo.api (:require [foo.parse :as parse])) (def stylesheets parse.stylesheets)

telent09:04:39

but AIUI that blows up if the client expects to rebind the var

telent09:04:18

because binding foo.api.stylesheets won't affect the value of foo.parse.stylesheets

plexus10:04:47

@telent: potemkin has import-vars for that purpose, but I don't think that will help with rebinding https://github.com/ztellman/potemkin

plexus10:04:44

why do you expect your users to rebind vars?

telent10:04:47

in this particular case: I have a list of prefixes used in generating/parsing rdf triples. There is a default list with all the conventional prefixes, but some users may wish to add their own

plexus10:04:10

right, I don't think there's a perfect solution to this. Personally I think it's fine to expose multiple namespaces. It also makes documentation friendlier

plexus10:04:27

you could define all dynamic vars that you expect to be rebound directly at the top level. also not perfect though, as you'd have to watch for circular dependencies

pesterhazy10:04:20

What do people use for full-text search in Clojure? Is Lucene / https://github.com/clojure-cookbook/clojure-cookbook/blob/master/06_databases/6-05_text-search.asciidoc still state of the art?

schmir10:04:58

pesterhazy: I'd go with elasticsearch - if that isn't overkill in your situation. Otherwise I'd say lucene is a good choice.

telent11:04:23

I used https://github.com/weavejester/clucy for lucene last time I was playing with it, worked fine up until the point where I decided that I didn't want full-text search after all

pesterhazy11:04:24

@schmir, it depends a bit on how hard it is to set up, ops-wise

pesterhazy11:04:23

@telent: using lucene directly seems like an elegant solution, though clucy hasn't been updated in a while

pesterhazy11:04:13

also I'm wondering what elasticsearch gives you in addition

dev-hartmann11:04:42

@pesterhazy: i guess you could break it down to :it gives you the benefits of being distributed and having a set of common features implemented on top of lucene, which you normally would have to build yourself

curtis.summers11:04:46

@pesterhazy: Depending on your needs and existing environment, sometimes Postgresql's full text search is good enough: http://www.postgresql.org/docs/current/static/textsearch.html

pesterhazy11:04:23

Thanks, I'll check it out

pesterhazy11:04:46

Maybe there's an elastic search as a service

pesterhazy11:04:25

That might take away the ops issues

joost-diepenmaat11:04:22

AWS has ES as a service

joost-diepenmaat11:04:55

IIRC it’s a relatively old version ES but that might be the best option if you’re running on AWS already

pesterhazy11:04:15

I think I'll just use that then

jumar11:04:40

I’m just wondering if I can’t use sth. `(require '[uncomplicate.fluokitten [core :as f/core] [jvm :as f/jvm]]) `

jumar11:04:26

although the require completes ok, the repl doesn’t seem to recognize “f/core” - I assume the slash cannot be used in this case

joost-diepenmaat11:04:13

f/core means var core in (aliased) namespace f

joost-diepenmaat11:04:29

I don’t think you can have an alias with / in the name

joost-diepenmaat11:04:06

using dots is supported in aliases so you cold use f.core and f.jvm

joost-diepenmaat11:04:26

foo/bar is always either static method or property bar in class foo or var bar in namespace foo.

jasongilman11:04:19

This mentions issues with pmap. https://rasterize.io/blog/clojure-the-good-parts.html It doesn't really say what the problems are though. Does anyone have more information on that?

bsvingen12:04:43

@pesterhazy: You can get hosted Elasticsearch from https://www.elastic.co/cloud. There is also hosted Solr available. Whether you should use a hosted service, run Elasticsearch or Solr yourself, or just use Lucene as a library depends on what exactly it is you want to do.

pesterhazy12:04:54

@bsvingen: ideally I want to get things running in a day (product search), not too advanced but I do need a few features that Datomic fulltext doesn't provide

pesterhazy12:04:48

I just want to get started quickly, I can always move things to self-hosted ES later

bsvingen12:04:45

Yes, that should make it easy to get going.

bsvingen12:04:23

Unless all you need is non-distributed search within a simple application, in which case using Lucene directly should also be fine.

lucj0612:04:14

Hello, any recommended clojars to calculate the sha1_hex of strings ? (I need to create a signature as detailed in https://eu.api.ovh.com/g934.first_step_with_api, signin requests part)

telent12:04:12

I think last time I did that stuff I used the apache commons codec java classes directly

lucj0612:04:24

@telent: thanks. Any link for this ? (I’m not a Java guy since quite a long time :) )

pesterhazy12:04:56

(defn md5 [s]
  (let [algorithm (MessageDigest/getInstance "MD5")
        size (* 2 (.getDigestLength algorithm))
        raw (.digest algorithm (.getBytes s))
        sig (.toString (BigInteger. 1 raw) 16)
        padding (apply str (repeat (- size (count sig)) "0"))]
    (str padding sig)))

pesterhazy12:04:23

this is code I've used to calculate MD5, shouldn't be hard to change to SHA1

pesterhazy12:04:00

looks convoluted though, maybe not the best approach (that's java.security.MessageDigest by the way)

telent12:04:06

oddly, can't find any actual evidence I've ever done this. if it's not on github did it really happen?

lucj0612:04:18

@pesterhazy: thanks I’ll check this. @telent I’m sure it’s hidden somewhere simple_smile

lucj0612:04:34

@pesterhazy: probably a stupid question, but can I also use SHA1_HEX instead of MD5 or is just SHA1 supported ?

pesterhazy12:04:26

SHA1 will returns bytes, so you'll have to encode that in hex yourself (as in my snippet)

lucj0612:04:51

@pesterhazy: thanks for your help.

lucj0612:04:25

@pesterhazy: just replacing MD5 with SHA1 in your function did the trick.

Lambda/Sierra12:04:39

My go-to for hashes is always Apache Commons Codec.

Lambda/Sierra12:04:59

It has all the variants you could want: hex strings, bytes, etc.

lucj0612:04:48

@stuartsierra: thanks, this is good to know

mchampine13:04:14

SHA1 is on its way out and is no longer considered safe for many common cryptographic uses. E.g. browsers are starting to deprecate SHA1 in TLS certs. Someone should ask OVH to update their API.

telent13:04:48

(defn sha256 [body] (Base64/encodeBase64URLSafeString (.digest (doto (java.security.MessageDigest/getInstance "SHA-256") .reset (.update (.getBytes body)))))) (assert (= (sha256 "hello world") "uU0nuZNNPgilLlLX2n2r-sSE7-N6U4DukIj3rOLvzek"))

telent13:04:57

does that look relevant?

telent13:04:48

(:import [java.security SecureRandom] [org.apache.commons.codec.binary Hex Base64] [javax.crypto Mac] [java.security MessageDigest]

mchampine13:04:53

I'd use buddy-core (hash/sha256 "your string here")

xcthulhu13:04:24

@telent: I think you might want (.getBytes body "UTF-8") in there

xcthulhu13:04:31

Not sure if buddy is using UTF-8... I feel like I get nailed by this madness when hashing unicode every time

xcthulhu13:04:44

Okay after much digging it is apparently using UTF-8

nkraft14:04:42

Not sure if this is the right channel for this question, but how does someone get invited to the Clojarians team?

dpsutton14:04:10

I'm running a simple clojure web site with compojure and ring. I build with lein ring uberjar and run with supervisor and nginx in front of it. The first request is always slow due to creating the jvm. Subsequent quick requests are fulfilled quickly. After a while, it seems like the jvm "dies" so that future requests pay this overhead of waiting on the jvm to crank back up. Is there a simple fix to this that doesn't require switching to netty or tomcat for their keepalive features? Perhaps there's a java option that I can pass in saying just stay alive?

loganmhb15:04:44

@afazio: is the test running on a separate thread? bindings are thread-local

afazio15:04:51

@loganmhb: I believe it is all running in the same thread. But that’s where the head scratching comes in.

afazio16:04:03

If it were in the same thread the binding should hold

loganmhb16:04:20

how do you invoke the clojure.test code?

afazio16:04:24

Using (clojure.test/run-tests <namespace>)

afazio16:04:12

I’m wondering if it has something to do with two separate codebases. There is the lein plugin source tree and a separate project that uses that plugin. When it was all in the same source tree it worked great. That’s really the only difference I know of.

hiredman17:04:05

how are you invoking the plugin?

hiredman17:04:05

lein's execution model is two jvms, one for lein, one for your project

hiredman17:04:32

if I recall correctly, plugins reside in the lein jvm

hiredman17:04:22

so you shouldn't be directly running tests inside them

hiredman17:04:41

I am sort of surprised you aren't getting all kinds of other errors

venantius17:04:44

depends on whether the lein plugin injects its codebase into the project as a dependency

razum2um18:04:12

I look clojure.lang.ISeq and see that this interface requires next and more, but ASeq defines more in pseudocode as next || PersistentList.EMPTY and i think it’s common sense. Why when require definition of more in interface? Can it be different from next implementation?

hiredman18:04:16

they have different laziness guarantees, it is the difference between rest and next in clojure

hiredman18:04:31

in the beginning, there was no distinct empty seq value, just nil

razum2um18:04:16

@hiredman: could you bring example with different implementations? I look at LazySeq and they’re almost same (except when reached end of seq - nil vs ‘() )

hiredman18:04:05

that is exactly the difference, one is guaranteed to return nil at the end of the seq, the other is not

hiredman18:04:46

the nil returning semantics are slightly less lazy than the not returning nil

hiredman18:04:52

the nil returning means you have to force at least one "cell" in the lazy seq, to determine if you can return nil or a lazy seq of more elements, the not returning nil means you can always just return the rest without any kind of check

hiredman18:04:50

there was a blog post someone wrote right before that got changed (this may have been pre 1.0) illustrating the laziness in seqs

wren18:04:44

Is there any special serialization I need to do for a ring handler? Or can I just return a clojure data structure and expect serialization to happen?

hiredman18:04:45

depends on what you mean

hiredman18:04:19

the ring spec says the return value of a handler is a map, that contains some special keys, and those keys are specified as being certain types

wren18:04:40

ahh ok I'll check it then. Was just returning a map of data I wanted to get to the client

hiredman18:04:47

if you are specifically talking about the :body field

hiredman18:04:23

the ring spec permits a limited set of types, but there are various middlewares people use to do automic serialization to json or edn or whatever

razum2um18:04:39

@hiredman: I got the thing about the end of seq, but still don’t about why do I need to implement more in ISeq when it’s always next || ()

hiredman18:04:11

it isn't always that

razum2um18:04:00

@hiredman: ok, then could you bring example when they’re implemented differently and the reason why so

hiredman18:04:09

you've always seen one in LazySeq

hiredman18:04:03

and the reason they are implemented differently is because they permit different amounts of laziness

thug.nasty18:04:31

i seem to be doing something wrong using clj-http.client

razum2um19:04:01

@hiredman: yep, but it could be not a part of interface, just implemented as next || () right in LazySeq - nothing will change in behaviour, but we’ll not be forced more be part of interface. or do I mistake?

thug.nasty19:04:22

I'm using

clj (client/get url {:query-params {:access_token "**token**" ...}})

thug.nasty19:04:43

and when it executes, it tells me that the "access_token" is missing

hiredman19:04:09

I am looking at the code for lazyseq right now, and it definitely is not next || ()

thug.nasty19:04:10

I even tried "access_token" too

hiredman19:04:00

thos are different, and they are different for the reason I keep repeating, they provide differing amounts of laziness

hiredman19:04:22

more never calls next there

hiredman19:04:16

you are confused because you looked the the seqs implemented on top of fully realized collections, which have no laziness, so because those methods only differ in laziness, are the same for those collections

razum2um19:04:13

@hiredman: seem I’m missing something and should reread docs, but thanks for answers 👍

hiredman19:04:06

that write up is kind of dated, because it describes a pre-release state of something that in some form has been part of clojure for many many releases now

hiredman19:04:34

(and it referes to some other experimental work "streams" which never made it in to clojure)

hiredman19:04:47

I wish I could find the blog post that was making the rounds before that change was made in clojure, because if I recall it nicely illustrated the limitations of the old model, but my google-fu is weak

arohner19:04:26

IIRC, it had something to do with forcing the first element

arohner19:04:37

pre that change, the first item in a seq was always evaluted

arohner19:04:20

using faraday, I appear to be getting back URL-encoded strings. According to the dynamoDB console UI, the strings are not URL-encoded in the DB. Has anyone seen that?

razum2um19:04:12

@hiredman: @rohitarondekar reread Extension ISeqs on link above, thanks, sorry for such RTFM