Fork me on GitHub
#beginners
<
2019-06-03
>
didibus00:06:26

I do like that spec has made these syntax ambiguities more explicit

ghadi00:06:36

that code does not work in Clojure 1.7

ghadi00:06:20

bash> clojure -Sdeps '{:deps {org.clojure/clojure {:mvn/version "1.7.0"}}}'
Clojure 1.7.0
user=> (eval `(let [a 42]))
CompilerException java.lang.RuntimeException: Can't let qualified name: user/a, compiling:(NO_SOURCE_PATH:2:1)

đź‘Ť 4
didibus00:06:22

You can also do:

(eval `(let [~'a 3] ~'a))
if you really want the symbol to be a

didibus00:06:35

Works for me in 1.7.0-alpha5

didibus00:06:15

Oh no, you're right

didibus00:06:25

Hum... I must have goofed and tried something else

Vikram08:06:57

How to execute system command using clojure? I mean I can call and write into command prompt using clojure. Any ideas

Vikram09:06:51

@michael.e.loughlin Thank you for the reply. I read that clojure doc but I'm not able to figure out how to write using all that in clojure

deep-symmetry15:06:33

As @michael.e.loughlin says, we need more specifics about your question. The sh function that he linked to is exactly what you need to interact with operating system processes. It is a thin layer on top of the underlying Java facility, Runtime.exec(), https://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html#exec(java.lang.String[],%20java.lang.String[],%20java.io.File)

deep-symmetry15:06:32

This is one of those cases where you need to learn things beyond Clojure itself to understand the Java environment in which it operates.

deep-symmetry15:06:43

If you can tell us exactly what you are trying to accomplish, for example the system command you want to run and the arguments, we can perhaps show how that would be formatted when calling sh? But to be able to come up with the answer yourself will require understanding the Java mechanism, and the underlying operating system process mechanism.

Vikram05:06:33

@U0EHA00G1 Thanks for the reply. So I want to read and write on command prompt using clojure for Brl-Cad. Suppose I want to pass this command

(sh "mged" "-c" "test.g" "ls")
The problem is I'm not able to figure out how to pass this syntax in clojure programming.

Vikram05:06:06

I tried this but it's not writing in command prompt

(ns brl-project.core
  (:require [clojure.java.shell :refer [sh]]))

(defn test []
  (:out (sh "mged" "-c" "test.g" "ls")))

deep-symmetry15:06:56

I am confused by what you mean when you say “read and write on command prompt.” That is something that users do, not programs. Java (and your underlying operating sytstem, what are you using?) lets you execute subprocesses and pass them arguments and gather there responses. But there will be no window or “command prompt” associated with that. The value will come back as a response map, which you seem to have noticed in your example. When I invoke (clojure.java.shell/sh "ls" "/usr") in a repl, I get back a map that looks like this:

deep-symmetry15:06:17

{:exit 0,
 :out "X11\nbin\nlib\nlibexec\nlocal\nsbin\nshare\nstandalone\n",
 :err ""}

deep-symmetry15:06:54

So, the result of running that command is available: The process terminated with an exit status of 0, the output that was written to stdout is available as a string under the key :out, and the output that was written to stderr (of which there was none) is available as a string under a key under :err. This allows my Clojure code to run other programs and interact with them, and examine the results. Can you clarify what is missing from your perspective?

deep-symmetry16:06:00

I do notice that in your example you seem to be trying to run two separate commands, mged -c test.g followed by ls. You can’t do that with a single invocation of sh. If for some reason you really don’t want to call sh separately from Clojure for each command you want to run, you can either put the commands into a temporary file as a shell script and run sh with that file as an argument, or you can explicitly invoke the shell executable with a -c argument followed by a string containing all of the commands you want parsed out, something like this:

deep-symmetry16:06:08

(clojure.java.shell/sh "/bin/sh" "-c" "ls /usr ; ls /var")
{:exit 0,
 :out
 "X11\nbin\nlib\nlibexec\nlocal\nsbin\nshare\nstandalone\nagentx\nat\naudit\nbackups\ndb\nempty\nfolders\ninstall\njabberd\nlib\nlog\nma\nmail\nmobile\nmsgs\nnetboot\nnetworkd\nroot\nrpc\nrun\nrwho\nservermgrd\nspool\ntmp\ntmptmpdb5dLEX\ntmptmpdb5dLEX-journal\ntmptmpdblboqU\nvm\nyp\n",
 :err ""}

Vikram09:06:35

Hey @U0EHA00G1, thanks for explaining the above concept.

mloughlin09:06:13

what are you having a problem with?

Casey10:06:10

i'm impementing a client library for an http api. part of the auth workflow is requesting a token, then you have to poll an endpoint while the user performs a second factor verification, once that is complete, the polling endpoint returns the token. What's the proper/clojure way to handle this in a library? I want to avoid blocking the consumer. Perhaps a channel?

christos10:06:27

A returnig channel or passing a channel as an argument, or both

Chase17:06:06

so when you are destructuring a map using something like [{:keys [foo bar]}] then does foo and bar have to coincide directly to the keys :foo and :bar? Because if not how does that work if maps are unordered?

tavistock17:06:58

yes it need to correspond with foo and bar

samedhi18:06:40

Not sure, but maybe you are thinking that this will only work if you have a map of {:foo "footer" :bar "barter"}? You are right @U9J50BY4C in that keys in maps are not "ordered", so the order you specify them as part of the :keys vectors makes no difference.

samedhi18:06:10

Eg. {:foo "footer" :bar "barter"} is equal to {:bar "barter :foo "footer"}

Chase19:06:33

Yep, I think it was just a brain fart where I was trying to think why aren't we just using the actual keyword instead. I just hadn't thought it through again to where it was binding the value of that corresponding keyword like lilactown mentioned.

lilactown17:06:47

yes, {:keys [foo bar]} means "given a map with keys :foo and :bar, bind the value at :foo to the local foo and the value at :bar to the local bar"

Chase19:06:51

is there a function that would turn something like [1 2 3] into just 1 2 3? might have been a macro or something

manutter5119:06:57

You may be thinking of apply

đź‘Ť 4
Chase20:06:02

that's what I was thinking but it wasn't quite getting to where I wanted

manutter5120:06:03

(str [1 2 3])
=> "[1 2 3]"
(apply str [1 2 3])
=> "123" ;; same as (str 1 2 3)

manutter5120:06:24

What’s the bigger issue you’re trying to solve?

Chase20:06:08

I was just exploring the [& args] portion of function parameters and what I could do with them. They get packaged up in a sequence right so you can do anything with them as you would in a sequence?

Chase20:06:10

but what if you didn't want them as a sequence? You want them individually like "normal" parameters but you didn't know how many inputs you would have so you just went with [& args]. I think my problem was this started as a random hypothetical thought exercise to check my understanding but I don't have a concrete thing I'm trying to do here. So I don't know if this would even ever come up

Michael Stokley20:06:41

you could destructure args in the function body

Michael Stokley20:06:47

user=> (defn f [& args]
  #_=>   (let [[a b c] args]
  #_=>     (println a b c)))
#'user/f
user=> (f 1)
1 nil nil
nil
user=> (f 1 2)
1 2 nil
nil
user=> (f 1 2 3)
1 2 3
nil

manutter5120:06:20

Multiple arities is the best way to go if your use case allows for it.

Chase20:06:54

cool. thanks folks!