beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
Joe 2021-02-15T10:18:23.144400Z

I've written a function that takes a lazy sequence and returns a lazy sequence of the partial sums (i.e. the accumulated sum of all terms to that point). I came up with this but it feels like there's a more direct way to do it. Am I missing something?

(defn partial-sums
  ([nums] (partial-sums 0 nums))
  ([acc [fst & rst]]
   (let [new-acc ((fnil + 0) fst acc)]
     (cons new-acc (lazy-seq (partial-sums new-acc rst))))))

2021-02-15T10:24:40.145Z

(reductions + [1 2 3 4])

❤️ 1
1
Joe 2021-02-15T10:43:56.145300Z

Perfect, thanks!

Tim Robinson 2021-02-15T13:12:11.147100Z

Can anyone explain the difference between and and when ? they sound like different concepts but seem to do the the same thing (i.e. evaluate and return the second arg only if the first one is true)

2021-02-15T13:16:29.149800Z

Not quite. and is a “short-circuiting” boolean AND operation that returns “truthy” if all its arguments are truthy, and when more like an if without an else--if the first argument to when is true, it evaluates all the rest of its arguments regardless of whether or not they return a truthy value. (Where “truthy” means any non-nil value).

2021-02-15T13:18:32.152700Z

So if you have (and a b c d e) and a and b are true and c is nil, and will return false without ever evaluating d and e. (when a b c d e) will evaluate all 5 arguments, as long as a returns a truthy value.

2021-02-15T13:36:27.153400Z

A slightly more interesting example:

(and true 1 "ok" nil (throw (Exception. "boom")))
=> nil
(when true 1 "ok" nil (throw (Exception. "boom")))
Execution error at user/eval36922 (form-init10506123581459132295.clj:1).
boom

Tim Robinson 2021-02-15T13:38:24.154Z

yes good point, I was only thinking about the simple case of (when a b)

Tim Robinson 2021-02-15T13:41:32.155800Z

Also (and false x) returns false whereas (when false x) returns nil (though that often wouldn't matter)

2021-02-15T14:11:02.156100Z

Interestingly,

(and false true)
=> false
(and nil true)
=> nil

2021-02-15T14:11:42.156700Z

So technically if and finds a falsy value, it immediately returns the falsy value and does not evaluate any further args.

grazfather 2021-02-15T14:41:57.156900Z

I got a strange error: I was running something in a loop for about a day with a Thread/sleep in it. It was working great, but then it randomly crashed

{:clojure.main/message
 "Syntax error reading source at (tempplot/core.clj:21:1).\nEOF while reading, starting at line 16\n",
 :clojure.main/triage
But the file never changed, how in the world is this possible?
(defn create-db
  [db]
  (try (db-do-commands
          db (create-table-ddl :temps
                               [[:timestamp :datetime :default :current_timestamp ]
                                [:location :text]
                                [:temp :real]]
                               :conditional?))
       (catch Exception e
         (println (.getMessage e)))))
line 16 is the create-table-ddl line

grazfather 2021-02-15T14:44:18.157500Z

create-db was already run literally > 24 hours earlier

2021-02-15T14:58:24.157600Z

Is there a stack trace after those 3 lines of error you showed? One thing it makes me immediately wonder is "if Clojure loaded that source file earlier, why was it trying to read the source file again later?" Do you have some explicit load or load-file call in your Clojure code that would cause that? Or a (require ...) with :reload-all as an arg?

2021-02-15T14:59:30.157800Z

Clojure is definitely a dynamic enough language that you can load source files long after the program begins running, but it is not the most common practice in Clojure programs to do so.

grazfather 2021-02-15T15:27:58.158Z

Here is the trace

grazfather 2021-02-15T15:28:01.158200Z

{:clojure.main/message
 "Syntax error reading source at (tempplot/core.clj:21:1).\nEOF while reading, starting at line 16\n",                                                                              :clojure.main/triage
 {:clojure.error/phase :read-source,
  :clojure.error/line 21,
  :clojure.error/column 1,
  :clojure.error/source "core.clj",
  :clojure.error/path "tempplot/core.clj",
  :clojure.error/cause "EOF while reading, starting at line 16"},
 :clojure.main/trace
 {:via
  [{:type clojure.lang.Compiler$CompilerException,
    :message
    "Syntax error reading source at (tempplot/core.clj:21:1).",
    :data
    {:clojure.error/phase :read-source,
     :clojure.error/line 21,
     :clojure.error/column 1,
     :clojure.error/source "tempplot/core.clj"},
    :at [clojure.lang.Compiler load "Compiler.java" 7643]}
   {:type java.lang.RuntimeException,
    :message "EOF while reading, starting at line 16",
    :at [clojure.lang.Util runtimeException "Util.java" 221]}],
  :trace                                                                                                                                                                             [[clojure.lang.Util runtimeException "Util.java" 221]
   [clojure.lang.LispReader readDelimitedList "LispReader.java" 1405]
   [clojure.lang.LispReader$ListReader invoke "LispReader.java" 1243]
   [clojure.lang.LispReader read "LispReader.java" 285]
   [clojure.lang.LispReader readDelimitedList "LispReader.java" 1398]
   [clojure.lang.LispReader$ListReader invoke "LispReader.java" 1243]
   [clojure.lang.LispReader read "LispReader.java" 285]
   [clojure.lang.LispReader read "LispReader.java" 216]
   [clojure.lang.Compiler load "Compiler.java" 7631]
   [clojure.lang.RT loadResourceScript "RT.java" 381]
   [clojure.lang.RT loadResourceScript "RT.java" 372]
   [clojure.lang.RT load "RT.java" 459]
   [clojure.lang.RT load "RT.java" 424]
   [clojure.core$load$fn__6839 invoke "core.clj" 6126]
   [clojure.core$load invokeStatic "core.clj" 6125]
   [clojure.core$load doInvoke "core.clj" 6109]
   [clojure.lang.RestFn invoke "RestFn.java" 408]
   [clojure.core$load_one invokeStatic "core.clj" 5908]
   [clojure.core$load_one invoke "core.clj" 5903]
   [clojure.core$load_lib$fn__6780 invoke "core.clj" 5948]
   [clojure.core$load_lib invokeStatic "core.clj" 5947]
   [clojure.core$load_lib doInvoke "core.clj" 5928]
   [clojure.lang.RestFn applyTo "RestFn.java" 142]
   [clojure.core$apply invokeStatic "core.clj" 667]
   [clojure.core$load_libs invokeStatic "core.clj" 5985]
   [clojure.core$load_libs doInvoke "core.clj" 5969]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.core$apply invokeStatic "core.clj" 667]
   [clojure.core$require invokeStatic "core.clj" 6007]
   [clojure.core$require doInvoke "core.clj" 6007]
   [clojure.lang.RestFn invoke "RestFn.java" 408]
   [user$eval140$fn__144 invoke "form-init798709166106965070.clj" 1]
   [user$eval140 invokeStatic "form-init798709166106965070.clj" 1]
   [user$eval140 invoke "form-init798709166106965070.clj" 1]
   [clojure.lang.Compiler eval "Compiler.java" 7177]
   [clojure.lang.Compiler eval "Compiler.java" 7167]
   [clojure.lang.Compiler load "Compiler.java" 7636]
   [clojure.lang.Compiler loadFile "Compiler.java" 7574]
   [clojure.main$load_script invokeStatic "main.clj" 475]
   [clojure.main$init_opt invokeStatic "main.clj" 477]
   [clojure.main$init_opt invoke "main.clj" 477]
   [clojure.main$initialize invokeStatic "main.clj" 508]
   [clojure.main$null_opt invokeStatic "main.clj" 542]
   [clojure.main$null_opt invoke "main.clj" 539]
   [clojure.main$main invokeStatic "main.clj" 664]
   [clojure.main$main doInvoke "main.clj" 616]
   [clojure.lang.RestFn applyTo "RestFn.java" 137]
   [clojure.lang.Var applyTo "Var.java" 705]
   [clojure.main main "main.java" 40]],
  :cause "EOF while reading, starting at line 16",
  :phase :read-source}}

grazfather 2021-02-15T15:29:24.158400Z

(ns tempplot.core
  (:require [dvlopt.linux.i2c :as i2c]
            [dvlopt.linux.i2c.smbus :as smbus]
            [clojure.data.json :as json]
            ;[oz.core :as oz]
            [clojure.java.jdbc :refer :all]))

(def db
  {:classname "org.sqlite.JDBC"
   :subprotocol "sqlite"
   :subname "db/database.db"})

(defn create-db
  [db]
  (try (db-do-commands
          db (create-table-ddl :temps
                               [[:timestamp :datetime :default :current_timestamp ]
                                [:location :text]
                                [:temp :real]]
                               :conditional?))
       (catch Exception e
         (println (.getMessage e)))))


(defn minimum-legal-temp
  [datetime outside-temp]
  ; TODO: Add date awareness: Heat season is between Oct 1 and ??
  (if (and (>= (.getHour datetime) 6) (< (.getHour datetime) 22))
    (if (< outside-temp 12.78) ; Day time, if under 55°F, then keep 68°F
      20
      outside-temp)            ; Otherwise there's no miniimum
    16.67))                    ; At night the minimum is always 62°F during heat season

(comment
  (minimum-legal-temp (java.time.LocalDateTime/of 2021 2 13 5 45) 10)
  (minimum-legal-temp (java.time.LocalDateTime/of 2021 2 13 15 45) 10)
  )

(def reg-temp 0)
(def reg-config 1)
(def resolution 0.0078125)

(defn bytes->val
  [b]
  (reduce (fn [acc v] (+ v (* acc 256))) b))

(bytes->val [8 201])

(def reading->C (partial * resolution))

(defn read-reg
  [bus reg]
  (i2c/transaction bus
        [{::i2c/slave-address 0x48
          ::i2c/write [reg]}
         {::i2c/slave-address 0x48
          ::i2c/read 2}]))

(defn line-plot
  [db]
  {:data {:values (doall (query db ["select * from temps order by timestamp"]))}
   :encoding {:x {:field "timestamp" :type "nominal"}
              :y {:field "temp" :type "quantitative"}
              :color {:field "location" :type "nominal"}}
   :mark "line"})


(def api-host "<http://api.openweathermap.org/data/2.5/forecast?id=524901&amp;appid=>")
(def api-key "xxx")
(def api-current-weather "<https://api.openweathermap.org/data/2.5/weather?id=%d&amp;appid=%s&amp;mode=json&amp;units=metric>")
(def manhattan-city-id 5125771)

(defn get-current-temperature
  [city-id]
  (-&gt; (format api-current-weather manhattan-city-id api-key)
      slurp
      json/read-str
      (get-in ["main" "temp"])))

(defn get-manhattan-temp [] (get-current-temperature manhattan-city-id))

(defn -main
  [&amp; args]
  (println "Creating db")
  (create-db db)
  (println "Reading temps")
  (with-open [bus (i2c/bus "/dev/i2c-1")]
    (while true
    ;(dotimes [i (* 12 18)] ; for now
      (let [inside-temp (-&gt; (read-reg bus reg-temp)
                  (get 1)
                  bytes-&gt;val
                  reading-&gt;C)
            outside-temp (get-manhattan-temp)
            now (java.time.LocalDateTime/now)
            min-temp (minimum-legal-temp now outside-temp)]
         (insert! db :temps {:location "inside" :temp inside-temp :timestamp now})
         (insert! db :temps {:location "outside" :temp outside-temp :timestamp now})
         (insert! db :temps {:location "minimum" :temp min-temp :timestamp now})
         (println (format "%s inside %.2fC outside %.2fC illegal? %s" now inside-temp outside-temp (&lt; inside-temp min-temp))))
      (Thread/sleep (* 5 60 1000)) ; 5 minutes
    )
  )
  (spit "plot.edn" (line-plot db))
)

; {1 [8 201]}
; {1 [0 240]}

2021-02-15T15:30:27.158700Z

Do you know of any way that your program would try to load new Clojure source code long after it started?

2021-02-15T15:30:58.158900Z

Or was this exception perhaps caused because you had a live REPL session open with the running program, and you did something in the REPL that tried to load Clojure source code?

2021-02-15T15:41:01.159100Z

I'm only eyeballing it, but I see nothing about that source file that ends at line 21 🙂

2021-02-15T15:41:48.159300Z

Is there any chance that you were editing the source file after your program was already running?

grazfather 2021-02-15T15:45:45.159500Z

no repl, no editing the file

grazfather 2021-02-15T15:45:53.159700Z

it was on a raspberry pi I hadn’t touched

grazfather 2021-02-15T15:45:56.159900Z

I just checked it this morning

grazfather 2021-02-15T15:46:14.160100Z

and in fact the time stamp on the file was 13 hours before the error

2021-02-15T16:02:16.160300Z

Maybe the Pi itself reset for some reason? Would your program relaunch if the device rebooted?

2021-02-15T16:11:29.160500Z

how did you run clojure? via java directly, with clj, lein?

2021-02-15T16:57:37.160700Z

The file(form whatever.clj) name in a the stack trace means lein

2021-02-15T17:00:18.161400Z

so likely "lein run", I wonder if there's a hidden reloading plugin somewhere

2021-02-15T17:01:46.162600Z

Hi, newbie question here, I'm using SQL server express, and some test database "AdventureWorks", but got an error java.sql.SQLException: No suitable driver found for jdbc:<sqlserver://127.0.0.1:1433>;DATABASENAME=AdventureWorks I've installed my jdbc via com.microsoft.sqlserver.jdbc.SQLServerDriver class path environment C:\Program Files\Java\jdk-15.0.2\mssql-jdbc-9.2.0.jre15.jar my code is

(ns clojuresql.core
  (:require [next.jdbc :as jdbc]
            [hugsql.core :as hugsql]
            [hugsql.adapter.next-jdbc :as adapter]
            [next.jdbc :as jdbc]
            [honeysql.core :as sql]
            [honeysql.helpers :refer :all :as helpers]))

(def db-sqlserver {:dbtype "sqlserver" :dbname "AdventureWorks"
                   :user "sa" :password "123456789"})

(def ds (jdbc/get-datasource db-sqlserver))


(jdbc/execute! ds
               ["show tables"])
where did i do wrong?

2021-02-15T17:04:41.163900Z

@adrianimanuel you don't "install" a jdbc driver, you add it as a maven dep to a project

2021-02-15T17:05:06.164400Z

(using any mainstream clojure option like lein or deps.edn at least)

2021-02-15T17:08:42.166Z

you can check the output of (System/getProperty "java.class.path") to see if mssql-jdbc is mentioned anywhere

2021-02-15T17:09:10.166900Z

@noisesmith oh, okay it's like this right com.h2database/h2 {:mvn/version "1.4.199"} , but for the SQLserver, from here https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc/9.2.0.jre15 [com.microsoft.sqlserver/mssql-jdbc "9.2.0.jre15"] am i right?

2021-02-15T17:09:57.167800Z

right - that's the normal way to do it - the general concept is that there's no global state of installed libs, but rather a config of which libs and versions you want, and a resolver that provides them to your process

👏 1
2021-02-15T17:10:17.168200Z

ahh okay, noted... thanks so much!

2021-02-15T17:11:22.169300Z

this is weird at first! but now I find every other programming environment primitive. what do you mean I need to create a whole virtual OS / user environment just to use different lib versions in two projects?

2021-02-15T17:11:52.169800Z

a small upfront complexity to remove the avalanche of complexities that global installs create...

✅ 1
2021-02-15T17:13:47.170800Z

@adrianimanuel one more note - you have two sample lib specs there, the h2 example is in deps.edn format, the mssql one is in lein format - the two are easy to convert in your head but definitely make sure you have the right one

2021-02-15T17:17:35.172700Z

yes, i read h2 in deps.edn format from https://github.com/seancorfield/next-jdbc/blob/develop/doc/getting-started.md But, noted, I'm using lein format to do that. I've got another error here, it's already connected but what should i do?

Execution error (SQLServerException) at com.microsoft.sqlserver.jdbc.SQLServerException/makeFromDriverError (SQLServerException.java:234).
The TCP/IP connection to the host 127.0.0.1, port 1433 has failed. Error: "Connect timed out. Verify the connection properties. Make sure that an instance of SQL Server is running on the host and accepting TCP/IP connections at the port. Make sure that TCP connections to the port are not blocked by a firewall.".

2021-02-15T17:27:29.173Z

you should look in the database to see what information was recorded in there, since it includes timestamps, my guess is you'll find less information than you expect, indicating that the error happened much earlier then you think

2021-02-15T17:28:30.174100Z

followed this https://stackoverflow.com/questions/18841744/jdbc-connection-failed-error-tcp-ip-connection-to-host-failed and changed my ipall port to : 1433, but still got an error

2021-02-15T17:39:40.174500Z

i've also create inbound exception in the firewall for 1433 port

dpsutton 2021-02-15T17:51:56.174700Z

are you running things in WSL?

2021-02-15T18:23:21.175100Z

@dpsutton windows 10

2021-02-15T18:25:17.175200Z

It does seem a lot more plausible that (a) the exception you showed actually occurred shortly after starting you program, perhaps because the file was not fully copied to the Raspberry pi where it was running somehow, but you did not notice it until much later, versus (b) the file was fully there when you started your program, got loaded once successfully then, your program for some reason tried loading it again 13 hours later (same running JVM process), and the file was somehow changed in a way that the modify time stamp did not get updated.

Audrius 2021-02-15T18:46:39.176700Z

How to kill the current command in the REPL? I have something like (javadoc Object) and I want to kill it is there a way? (it is "lein repl")

2021-02-16T11:35:48.214900Z

It seems that a workaround for that issue is to start the default browser first.

2021-02-16T14:08:30.219600Z

this should be a simple fix, as surely nobody uses javadoc in a critical path, it's easy to manage the stdio of a child with ProcessBuilder

2021-02-16T16:49:28.234200Z

There is a patch on the ticket I linked that led to improved behavior in my interactive testing. Alex Miller's last comment on it that I recall was that he'd like to think about it more and see if there is a better way. I do not know what the criteria for better is here.

2021-02-15T18:47:16.176800Z

ctrl + c twice maybe?

Audrius 2021-02-15T18:47:53.177Z

did not work

2021-02-15T18:51:27.177300Z

thats shortcut to kill in emacs

2021-02-15T19:24:27.177500Z

wait, why would javadoc hang? it just shells out and returns immediately in my experience

2021-02-15T19:25:00.177700Z

nrepl, which lein uses, has a signal handler that kills the current top level execution on control-c

2021-02-15T19:26:02.177900Z

if javadoc hangs (maybe because your browser is set up weird?) that sounds like a bug in javadoc

em 2021-02-15T20:26:10.182800Z

What's the rule on evaluation for vars that refer to vars? Might be a weird question, but I'm curious about why this works:

(def a inc)
(def b #'a)
(def c #'b)

@#'a
;; #object[clojure.core$inc 0x2b39a1 "clojure.core$inc@2b39a1"]
@#'b
;; #exercises.core/a
@#'c
;; #exercises.core/b

;; However, c still works as a function
(c 4)
;; 5
I kinda expected a function call to c would evaluate to the var b, and not the function object inc all the way down the chain. Does evaluation explicitly continuously unwrap vars until something that implements IFn , or instead is it that vars can function as functions that pass arguments down to whatever they're pointing at, thus c in the above example is just a bunch of nested function calls?

2021-02-15T20:31:57.183300Z

@eagonmeng when you call a var, it derefs and calls the thing it contains

2021-02-15T20:32:04.183500Z

refs do this too

2021-02-15T20:33:06.184100Z

it's not the evaluators job per se - var implements the IFn interface

user=&gt; (supers clojure.lang.Var)
#{clojure.lang.Settable java.lang.Runnable clojure.lang.IFn java.util.concurrent.Callable java.io.Serializable clojure.lang.IDeref clojure.lang.IMeta clojure.lang.IRef clojure.lang.AReference java.lang.Object clojure.lang.ARef clojure.lang.IReference}

2021-02-15T20:34:07.185200Z

the evaluator takes the list (x) and since in most contexts () means call, it looks for the way to call the thing

2021-02-15T20:34:35.185800Z

so if x is a var, it finds that the var is an IFn (a first class thing clojure knows how to call), and invokes it

2021-02-15T20:34:43.186100Z

the object decides what "calling" means

2021-02-15T20:35:11.186800Z

in the var case, calling means calling the thing it contains, but really it's up to the object, it's not in clojure's compiler's control

2021-02-15T20:36:28.187400Z

using some OO primitives really helps here I think:

(cmd)user=&gt; (def f (reify clojure.lang.IFn (invoke [this] "hi")))
#'user/f
(ins)user=&gt; (f)
"hi"

2021-02-15T20:37:06.188Z

reify creates a thing that implements some interface, here it creates a thing clojure knows it can call - anything could go in that method

em 2021-02-15T20:46:54.189700Z

@noisesmith Thanks for the clarification! Makes sense, so it was the latter option I was thinking about. A lot more clean than baking in some weird unwrapping mechanism in evaluation, which was what I was confused about. Essentially vars ARE functions since they implement IFn , and they simply call the thing the thing they point at when treated as such, and thus sequentially referenced vars form a call chain until they hit an actual function or error out when they resolve to something that doesn't.

2021-02-15T22:13:10.190300Z

If the person asking is using a Linux system with xdg-open installed, it might be related to this issue: https://clojure.atlassian.net/browse/CLJ-2493

2021-02-15T22:51:20.190500Z

oh wow - I never had xdg-open hang on me, I guess because I already had a browser running so it just opens a tab in that browser an returns immediately without the need to start a process

2021-02-15T22:51:36.190700Z

but yeah, good find, definitely a bug in javadoc