clojure.core.async - using >! and <! within a function call - asynchronous

I would like to be able to park when calling a function from a go-block. Using >! and <! does not work as expected.
This would park appropriately.
(go (<! (chan)))
However, if we have a function call,
(defn f [c] (<! c))
(go (f (chan)))
The <! is not resovled by the go block, as it is in a function. Is there any alternatives around this? The closest one I can think of is to write a macro for f rather than a function - is there an alternative function, instead of <! and >! that I can use for this purpose?

It's a known limitation of core.async. go macro only rewrites passed s-expression, it cannot really "look" inside bodies of functions.
I'd suggest to rewrite your example as follows (in case you want to use parking puts and gets):
(defn f [c] (go (<! c)))
(go (<! (f (chan))))
Also there's always a possibility to use blocking puts and takes (<!!, >!!).
> (time (dotimes [n 100000] (<!! (go (<! (let [ch (chan)] (put! ch 1) ch))))))
"Elapsed time: 1432.751927 msecs"
nil
> (time (dotimes [n 100000] (<!! (go (<! (go (<! (let [ch (chan)] (put! ch 1) ch))))))))
"Elapsed time: 1828.132637 msecs"
nil
According to benchmarks the initial method (if it had been supported by core.async) should be rougly 30% faster than the suggested workaround.

Related

What is the "truly-the" function?

In SBCL 2.0.1, (macroexpand '(dolist (x '(1 2 3)) (princ x))) returns:
(BLOCK NIL
(LET ((#:N-LIST385 '(1 2 3)))
(TAGBODY
#:START386
(UNLESS (ENDP #:N-LIST385)
(LET ((X (TRULY-THE (MEMBER 3 2 1) (CAR #:N-LIST385))))
(SETQ #:N-LIST385 (CDR #:N-LIST385))
(TAGBODY (PRINC X)))
(GO #:START386))))
NIL)
T
What is TRULY-THE? It appears to be non-standard because I could not find it in the Common Lisp HyperSpec.
What is the difference between TRULY-THE and THE?
From the SBCL manual:
Special Operator: truly-the [sb-ext] value-type form
Specifies that the values returned by form conform to the value-type, and causes the compiler to trust this information unconditionally.
Consequences are undefined if any result is not of the declared type -- typical symptoms including memory corruptions. Use with great care.
In other words, the the operator in certain cases (for instance with a high level of debugging) compiles to a test to check the correctness of the type specified, while truly-the instructs the compiler to NEVER perform this check.

Is there a way to find out how the primitive functions (built-in) where exactly defined inside SBCL?

I am learning Common Lisp using Emacs, SBCL and Slime.
I would like to know exactly what is the code definition of the built-in functions.
I know how to use (documentation ...) and (describe ...). However, they provide only high level information. I would like to see the code details.
For instance, take the nth built-in function.
Documentation gives us:
CL-USER> (documentation 'nth 'function)
"Return the nth object in a list where the car is the zero-th element."
Describe gives me:
CL-USER> (describe 'nth)
COMMON-LISP:NTH
[symbol]
NTH names a compiled function:
Lambda-list: (SB-IMPL::N LIST)
Declared type: (FUNCTION (UNSIGNED-BYTE LIST) (VALUES T &OPTIONAL))
Derived type: (FUNCTION (T T) (VALUES T &OPTIONAL))
Documentation:
Return the nth object in a list where the car is the zero-th element.
Inline proclamation: MAYBE-INLINE (inline expansion available)
Known attributes: foldable, flushable, unsafely-flushable
Source file: SYS:SRC;CODE;LIST.LISP
(SETF NTH) names a compiled function:
Lambda-list: (SB-KERNEL::NEWVAL SB-IMPL::N LIST)
Derived type: (FUNCTION (T UNSIGNED-BYTE LIST) (VALUES T &OPTIONAL))
Inline proclamation: INLINE (inline expansion available)
Source file: SYS:SRC;CODE;SETF-FUNS.LISP
(SETF NTH) has a complex setf-expansion:
Lambda-list: (SB-IMPL::N LIST)
(undocumented)
Source file: SYS:SRC;CODE;DEFSETFS.LISP
; No value
I would like to see something like:
(unknown-command 'nth)
Which would return something like:
(defun nth (x xs)
(if (equal x 0)
(car xs)
(my-nth (- x 1) (cdr xs))))
Lisp languages are fantastic and have a huge ecossystem built by awesome programmers. I hope there is some tool or command for that.
Thanks
First, some general clarifications
In your own code, hitting Meta-. should take you to the source of the code
This will also "just work" for libraries installed via Quicklisp.
Now for SBCL code itself:
If the code is in the "expected place", hitting Meta-. on built-in functions (like nth in your example above) will also take you to its source. I believe the default is /usr/share/sbcl-source/src/code/ but there's possibly a way to configure it.
However, there's another practical way to view this: if you look at the output of (describe ...) above, the line was:
Source file: SYS:SRC;CODE;LIST.LISP
Note: not the last line, that is for (setf nth), something slightly different
This tells you which file in the SBCL source code you can expect to find the function definition.
So, within [the repo](https:/ /github.com/sbcl/sbcl/tree/master/src), if you locate src/code/list.lisp, you should find the definition you're looking for; reproducing here:
(defun nth (n list)
"Return the nth object in a list where the car is the zero-th element."
(declare (explicit-check)
(optimize speed))
(typecase n
((and fixnum unsigned-byte)
(block nil
(let ((i n)
(result list))
(tagbody
loop
(the list result)
(if (plusp i)
(psetq i (1- i)
result (cdr result))
(return (car result)))
(go loop)))))
(t
(car (nthcdr n list)))))
When such information is available, it should be accessible via function-lambda-expression :
* (FUNCTION-LAMBDA-EXPRESSION #'nth)
(LAMBDA (SB-IMPL::N LIST)
(DECLARE (SB-INT:EXPLICIT-CHECK)
(OPTIMIZE SPEED))
(BLOCK NTH
(TYPECASE SB-IMPL::N
((AND FIXNUM UNSIGNED-BYTE)
(BLOCK NIL
(LET ((SB-IMPL::I SB-IMPL::N) (SB-IMPL::RESULT LIST))
(TAGBODY
LOOP
(THE LIST SB-IMPL::RESULT)
(IF (PLUSP SB-IMPL::I)
(PSETQ SB-IMPL::I (1- SB-IMPL::I)
SB-IMPL::RESULT (CDR SB-IMPL::RESULT))
(RETURN (CAR SB-IMPL::RESULT)))
(GO LOOP)))))
(T (CAR (NTHCDR SB-IMPL::N LIST))))))
NIL
NTH
However, it is not always available, in which case you would have to go to the SBCL source code repository.

How do I map over a list of async channels in the order they exist in a list?

I'm having trouble returning the values from core.async channels in the browser in the order they were created (as opposed to the order at which they return a value). The channels themselves are returned from mapping cljs-http.client/get over a list of URLs.
If I bind the results manually in a let block then I can return the results in the order of the channels "by hand", but this obviously a problem when I don't know how many channels exist.
(let [response-channels (map #(http/get "http://date.jsontest.com" {:with-credentials? false}) (range 3))]
; Response is now three channels generated by http/get:
;(#object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel])
; If I want the results back in the guaranteed order that I made them, I can do this:
(go (let [response1 (<! (nth response-channels 0))
response2 (<! (nth response-channels 1))
response3 (<! (nth response-channels 2))]
(println "This works as expected:" response1 response2 response3))))
But if I try to map <! over the channels instead of binding to them individually then I just get a the list of channels instead of their values.
(let [response-channels (map #(http/get "http://date.jsontest.com" {:with-credentials? false}) (range 3))]
(let [responses (into [] (map (fn [c] (go (<! c))) response-channels))]
(println "This just returns the channels:" responses)
; This is still just a vec of many-to-many channels
; [#object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel]
; #object[cljs.core.async.impl.channels.ManyToManyChannel]]
)
)
I suspect it's a problem with the location of the go block, however I can't move it outside of the anonymous function without an error that I'm using <! outside of a go block.
This doesn't work:
(into [] (go (map <! response-channels)))
And neither does this:
(go (let [responses (into [] (map <! response-channels))]))
I also tried merging the channels via async/merge and then using async/reduce to conjoin the values but results are in the order of when the requests were fulfilled, not the order of the channels being merged.
Can anyone shed some light on retrieving values from a list of channels in the order the channels exist in the list?
In Clojure you could do (map <!! response-channels), but that's not possible in ClojureScript. What's even more important is that it's discouraged to use map—or lazy operations in general—for side effects (checkout this blog post to see why). The reason your code doesn't yield the results you're expecting is the (nested) use of fn within the go block (see this answer):
By [the Clojure go-block] stops translation at function boundaries, I mean this: the go block takes its body and translates it into a state-machine. Each call to <! >! or alts! (and a few others) are considered state machine transitions where the execution of the block can pause. At each of those points the machine is turned into a callback and attached to the channel. When this macro reaches a fn form it stops translating. So you can only make calls to <! from inside a go block, not inside a function inside a code block.
I'm not quite sure, but when you have a look at (source map) you'll see that it invokes fn directely as well as via other functions (such as lazy-seq), which is probably why (go (map <! response-channels)) doesn't work.
Anyway, how about doseq:
(go (doseq [c response-channels]
(println (<! c))))
This will respect the order within response-channels.

Clojure core.async, what's the difference between putting (go... ) block inside (doseq ..) and putting it outside?

I've read this article about core.async and learned < ! ! is used to block main thread until go block returns last channel. In the original example, < ! ! and go block is inside (doseq...), is it OK if they are put outside ? Looks like they behave the same.
;;original example code
(let [c (chan)]
(doseq [i (range 10)]
(go
(Thread/sleep 1000)
(>! c i)))
(doseq [_ (range 10)]
(<!!
(go
(println (<! c))))))
;;putting <!! part outside doseq
(let [c (chan)]
(doseq [i (range 10)]
(go
(Thread/sleep 1000)
(>! c i)))
(<!!
(go
(doseq [_ (range 10)]
(println (<! c))))))
Since <!! is blocking, the doseq will wait for the previous go block to be over before starting another one. So it's very serial. By putting the doseq in the go you just move where the code is executed and it doesn't change the serial nature of this code.
In truth since it's blocking and serial you could as well get rid of the go and just:
(doseq [_ (range 10)]
(println (<!! c))

How do I create variables in sequence in common Lisp?

I have the following code inside a function that is reading in a file which is a map. I get an error that *numrows* is an illegal dimension. I think this is because lisp is processing these variables in parallel. How can I fix this?
(setq *numrows* (read map))
(setq *numcols* (read map))
(setq *map* (make-array '(*numrows* *numcols*) :initial-element nil))
You're misdiagnosing the problem. The first argument you're passing to MAKE-ARRAY is a list of two symbols, *NUMROWS* and *NUMCOLS*. However, the first argument to MAKE-ARRAY should be a list of non-negative integers. The easiest way to fix your example is to make a list with the values instead: (list *numrows* *numcols*). So the code would look like this instead:
(setq *numrows* (read map))
(setq *numcols* (read map))
(setq *map* (make-array (list *numrows* *numcols*) :initial-element nil))
You normally wouldn't use setq like this, though. It'd probably be better, depending on the context, to bind those variables with LET*:
(let* ((numrows (read map))
(numcols (read map))
(map-array (make-array (list numrows numcols) :initial-element nil))
; do something with map-array
)

Resources