How to return the result of FileReader. in clojurescript - return-value

I have a function that reads a file using js/FileReader.:
(defn read-file [file]
(let [js-file-reader (js/FileReader.)]
(set! (.-onload js-file-reader)
(fn [evt]
(let [result (-> evt .-target .-result)
array (js/Uint8Array. result)]
{:content array}))) ; <- This is the value that 'read-file' should return
(.readAsArrayBuffer js-file-reader file)))
The problem is that I would like it to return the value of the .-onload method of the FileReader, but I only get (of course) the value of (.readAsArrayBuffer js-file-reader file) which, naturally, is undefined.
Thank you very much!
Edit
After trying with Martin Půda's answer, I think that the problem has to do with an asyncrhonous thing. I tested this code:
(defn read-file [file]
(let [js-file-reader (js/FileReader.)
reading-result (atom)
done? (atom false)]
(set! (.-onload js-file-reader)
(fn [evt]
(let [result (-> evt .-target .-result)
array (js/Uint8Array. result)]
(reset! reading-result {:content array})
(reset! done? true)
(js/console.log "in: " (:content #reading-result)))))
(.readAsArrayBuffer js-file-reader file)
;; (while (not #done?) (js/console.log (.-readyState js-file-reader)))
(js/console.log "out: " #reading-result)
#reading-result))
I get first the log of out: undefined , and then the log of in: (with the desired result).
When I uncomment the line (while...), I get an infinite loop of 1's... So I think that the function never notices that the FileReader was done... I don't know how to solve this...

Try this:
(defn read-file [file]
(let [js-file-reader (js/FileReader.)
reading-result (atom)]
(set! (.-onload js-file-reader)
(fn [evt]
(let [result (-> evt .-target .-result)
array (js/Uint8Array. result)]
(reset! reading-result {:content array}))))
(.readAsArrayBuffer js-file-reader file)
#reading-result))
See docs for atom and reset!.
EDIT: See HTML5 FileReader how to return result?- yes, it's asynchronous. I see two possibilities:
You will write all function calls, which work with returned value, inside event listeners.
You will follow this CLJS guide for Promises and use JS Promises or clojure.core.async.

After much reading, I solved it using a callback function:
(ns lopezsolerluis.fits)
(defn read-file [file callback]
(let [js-file-reader (js/FileReader.)]
(set! (.-onload js-file-reader)
(fn [evt]
(let [result (-> evt .-target .-result)
array (js/Uint8Array. result)]
(callback array))))
(.readAsArrayBuffer js-file-reader file)))
Then read-file is called from this:
(ns lopezsolerluis.annie-web)
(defn procesar-archivo [result]
(js/console.log "Bloques: " result))
(defn input-file []
[:input {:type "file" :id "fits" :name "imagenFits" :accept "image/fits"
:on-change (fn [this]
(if (not (= "" (-> this .-target .-value)))
(let [^js/File file (-> this .-target .-files (aget 0))]
(fits/read-file file procesar-archivo)))
(set! (-> this .-target .-value) ""))}])
I added the namespaces because it surprised me that the callback machinery worked even across namespaces. Well, maybe it shouldn't surprise me; but I am learning and was a new concept for me. :)
I answer my question in case it's useful for others (it costed me a lot! :))

Related

For-each loop over pairs in Racket

I'm trying to print a list of pairs of values (representing key/value pairs) in Racket.
Here's the code I have right now:
#lang racket
(define (write-json keyvalues)
(displayln "{")
(for-each
(lambda (kv) (
(displayln (format "~a: ~a," (car kv) (cdr kv)))))
keyvalues)
(displayln "}"))
(write-json (list (cons "a" 1) (cons "b" 2)))
When I run the example, it prints:
{
a: 1,
Then, it crashes with this error message:
application: not a procedure;
expected a procedure that can be applied to arguments
given: #<void>
arguments...: [none]
context...:
/.../racket/collects/racket/private/map.rkt:58:19: loop
"test.rkt": [running body]
for-loop
run-module-instance!125
perform-require!78
Any idea what's going on?
Thanks!
This is a paren issue. You have an extra set of parentheses around your lambda's body, ie:
( (displayln (format "~a: ~a;" (car kv) (cdr kv))) )
Since displayln is used for side effect, its output is void, hence why your error message states that you're trying to run (#<void>).
In general, whenever you get an error stating "expected a procedure that can be applied to arguments", see if you have parentheses issues in your code block. Editors like Dr. Racket would highlight that region for you.

Clojure Korma: Cannot run an aggregate count

I'm trying to run a simple query using Clojure+Korma to extract the number of records.
This is what I'm trying to do:
(defmacro number-of [ref & filter]
`(let [basetmp# (-> (kc/select* ~ref)
(kc/aggregate (count :*) :cnt))]
(if ~filter
(-> basetmp#
(kc/where ~filter))
basetmp#)))
However if I try to use this macro I get an error message saying:
Wrong number of args (2) passed to: core$count
The query would perfectly work if executed in a function but there's something wrong/missing
in the macro I cannot spot :(
Thanks,
Nico
As noted by ponzao you are picking up the wrong count.
Looking at the macroexpansion
(number-of 'foo) ;; expands to....
(clojure.core/let [basetmp__9167__auto__ (clojure.core/->
(korma.core/select* 'foo)
(korma.core/aggregate
(clojure.core/count :*)
:cnt))]
(if nil
(clojure.core/-> basetmp__9167__auto__ (korma.core/where nil))
basetmp__9167__auto__))
So you need to prevent the count in your macro being expanded as clojure.core/count, you can do this with a unquote/quote thus:
(defmacro number-of [ref & filter]
`(let [basetmp# (-> (kc/select* ~ref)
(kc/aggregate (~'count :*) :cnt))]
(if ~filter
(-> basetmp#
(kc/where ~filter))
basetmp#)))
Which then expands as expected...
(clojure.core/let [basetmp__9137__auto__ (clojure.core/->
(korma.core/select* 'foo)
(korma.core/aggregate
(count :*)
:cnt))]
(if nil
(clojure.core/-> basetmp__9137__auto__ (korma.core/where nil))
basetmp__9137__auto__))
The resultant SQL looks reasonable:
(kc/as-sql (number-of 'foo))
"SELECT COUNT(*) \"cnt\" FROM \"foo\""
UPDATE:
From the comments "What does the count actually represent?" - If you realize that kc/aggregate is also a macro and that the arguments are a 'SQL aggregate' DSL of sorts, then you can expand the kc/aggregate call too. You find there's a function, parse-aggregate in engine.clj where it eventually maps to korma.sql.fn/agg-count:
(clojure.core/let [q__2640__auto__ (kc/select* 'foo)]
(korma.sql.engine/bind-query
q__2640__auto__
(clojure.core/let [res__2641__auto__ (korma.core/fields
q__2640__auto__
[(clojure.core/->
q__2640__auto__
(korma.sql.fns/agg-count
:*))
:cnt])]
(if nil
(korma.core/group res__2641__auto__ nil)
res__2641__auto__))))

How to write a macro resolve the symbol automatically

I'm always fancy that there is a method to resolve symbols automatically. For example, if I am in the "user" namespace and have not "used" symbols in the `clojure.string' namespace, instead of:
(clojure.string/split "a-b-c" #"-")
I want to write as this:
(call split "a-b-c" #"-")
I have simply implemented a `call' macro as this:
(defmacro call [sym & args]
`(let [fn# (first (distinct (remove nil? (map #(ns-resolve % '~sym) (all-ns)))))]
(if-not ((meta fn#) :macro)
(fn# ~#args)
(eval (list fn# ~#(map #(list 'quote %) args))))))
the following tests are always ok:
(call list 'a 'b)
(call apropos "list")
(call doc list)
(call doc clojure.string/split)
the problem happens when I pass a macro as the argument of `doc':
(call doc clojure.repl/doc)
then, there is a exception:
CompilerException java.lang.RuntimeException: Can't take value of a macro: #'clojure.repl/doc, compiling:(NO_SOURCE_PATH:112)
So, that's why? thanks
You can resolve the symbol at compile time in the macro like this:
(defmacro call [sym & args]
(let [f (first (distinct (remove nil? (map #(ns-resolve % sym) (all-ns)))))]
`(~f ~#args)))

How to transform this function into macro?

I have difficulties understanding the new macro system of Scheme. Somewhere along the path I began to write my "macro" as a function first, and then later apply it as a macro.
So my mission is to turn the following structure:
;; highlight-rules: rule id, color and the regexp matches
(define highlight-rules
`((important ,(with-esc "[1;33m") ("foo"
"bob"))
(unimportant ,(with-esc "[1;30m") ("case of unimport"))
(urgent ,(with-esc "[1;31m") ("urgents"))))
Into this kind of cond series with match strings compiled to regexpes:
;; just an example. `line` is an argument bound by the function application
(cond
((string-match (regexp ".*sudo:session.*") line)
(with-color *important* line))
(else line))
I have written a function that seems to do the trick:
;; (cdar highlight-rules) -> (colorstring list-of-rules)
(define (parse-highlight-rules rules)
;; aux function to do one 'class' of patterns
(define (class-of-rules colorstr rulelist)
(map (lambda (rule)
`((string-match ,(regexp rule)) (with-color ,colorstr line)))
rulelist))
(define (do-loop accumulator rules)
(let* ((highlight-group (cdar rules))
(colorstr (car highlight-group))
(grouprules (cadr highlight-group))
(acc* (append (class-of-rules colorstr grouprules) accumulator))
(rest (cdr rules)))
(if (null? rest)
acc*
(do-loop acc* rest))))
; wrap the list in cond.
`(apply cond ,(do-loop '() rules)))
With given highlight-rules the function returns correct-looking list (well apart from applying the apply -- in clojure one would use splicing):
CSI> (parse-highlight-rules highlight-rules)
(apply cond (((string-match #<regexp>) (with-color "\x1b[1;31m" line))
((string-match #<regexp>) (with-color "\x1b[1;30m" line))
((string-match #<regexp>) (with-color #0="\x1b[1;33m" line))
((string-match #<regexp>) (with-color #0# line))))
But how to proceed with this? I've been stuck with this for a while. Chicken Scheme is my dialect.
The easiest way of transforming your function into a macro is by using Chicken's explicit-renaming macro facility, which works similarly to Clojure's defmacro (except that an explicit-renaming macro takes some additional arguments that can be used to preserve hygiene).
Splicing works basically the same way as it does in Clojure. The syntax is ,#. Therefore, the following should work:
(define-for-syntax (parse-highlight-rules rules)
;; ... insert missing code here ...
`(cond ,#(do-loop '() rules)))
(define-syntax highlight
(er-macro-transformer
(lambda (form rename compare)
(parse-highlight-rules (cdr form)))))

Common Lisp: non-nil arguments and their names to alist, how?

I am quite new to Common Lisp and programming, and I'm trying to write a certain function that turns all non-nil args into an alist. The only way I can think of so far is:
(let ((temp nil))
(if arg1
(setf temp (acons 'arg1 arg1 nil)))
(if arg2
(setf temp (acons 'arg2 arg2 temp)))
...
(if arg20-ish
(setf temp (acons 'arg20-ish arg20-ish temp)))
(do-something-with temp))
which does not seem very elegant, it would be messy with many arguments and when these need to be changed. I am looking for a smarter way to do this, both for the sake of writing this particular function and for learning how to think in Lisp and/or functional programming.
The tricky part for me is figuring out how to get the names of the arguments or what symbol to use, without hand coding each case. If &rest provided arg names it would be easy to filter out NILs with loop or mapcar, but since it doesn't, I can't see how to "automate" this.
I'm totally interested in other solutions than the one described, if people think this way is unnatural.
Edit: Below is an example of what I am trying to do:
An object is created, with a non-fixed number of data pairs and some tags, e.g.:
user = "someone"
creation-time = (get-universal-time)
color-of-sky = "blue"
temperature-in-celsius = 32
language = "Common Lisp"
...
tags = '("one" "two" "three")
These properties (i.e. key/arg names) could be different each time. The new object will then be added to a collection; I thought the array might work well since I want constant access time and only need a numeric ID.
The collection will hold more and more such custom objects, indefinitely.
I want to be able to quickly access all objects matching any combination of any of the tags used in these objects.
Since the array is supposed to store more and more data over a long period, I don't want to parse every item in it each time I need to search for a tag. Thus I also store the index of each object with a given tag in a hash-table, under the tag name. I have written this function, what I find difficult is figuring out how to collect the data and turn it into an alist or anything that I can easily parse, index, and store.
This macro will define a function that turns its non-nil arguments into an alist bound during execution of the body:
(defmacro defnamed (fun-name alist-sym (&rest args) &body body)
`(defun ,fun-name (,#args)
(let ((,alist-sym))
,#(mapcar
(lambda (s)
`(when ,s
(push (cons ',s ,s) ,alist-sym)))
(reverse args))
,#body)))
Demonstration:
(defnamed make-my alist (a b c)
alist)
(make-my 1 NIL 3)
=> ((A . 1) (C . 3))
Here's a sort of solution using macros:
(defmacro named-args (fun-name alist-sym (&rest syms) &body body)
`(defun ,fun-name (&key ,#syms)
(declare (special ,#syms))
(let ((,alist-sym
(loop
for s in ',syms
collecting (cons s (symbol-value s)))))
,#body)))
You can then use it with something like
(named-args f u (a b c)
(format t "~A~%" u))
which expands to
(DEFUN F (&KEY A B C)
(DECLARE (SPECIAL A B C))
(LET ((U
(LOOP FOR S IN '(A B C)
COLLECTING (CONS S (SYMBOL-VALUE S)))))
(FORMAT T "~A~%" U)))
Finally, calling will give
(f :a 3) => ((A . 3) (B) (C))
Note that we need the special declaration otherwise symbol-value doesn't work (you need a global binding for symbol-value). I couldn't find a way to get rid of that.
Looking at your question again, it looks like you actually don't want the keyword arguments that didn't get passed. In which case you could parse a &rest argument (although that's a flat list, so you'd need to map along it in twos) or you could modify the macro as follows:
(defmacro named-args (fun-name alist-sym (&rest syms) &body body)
`(defun ,fun-name (&key ,#syms)
(declare (special ,#syms))
(let ((,alist-sym
(loop
for s in ',syms
when (symbol-value s)
collecting (cons s (symbol-value s)))))
,#body)))
and then you get
(f :a 3) => ((A . 3))