This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-12-29
Channels
- # announcements (7)
- # babashka (36)
- # beginners (67)
- # braveandtrue (11)
- # cider (8)
- # clojure (52)
- # clojure-conj (4)
- # clojure-poland (1)
- # clojure-spec (9)
- # clojure-uk (8)
- # clojurescript (42)
- # core-typed (11)
- # cursive (4)
- # emacs (1)
- # fulcro (1)
- # graalvm (24)
- # hoplon (10)
- # hyperfiddle (1)
- # off-topic (30)
- # re-frame (7)
- # reitit (1)
- # sql (1)
hey guys
I'm using some clojurescript and I don't know how to print a result from an #object[cljs.core.async.impl.channels.ManyToManyChannel]
can I do
(cljs.core.async/go
(println
(cljs.core.async/<! (fn))))
@d.ian.b You'll need to give a bit more context. What is fn
and what does (fn)
return? And what values are being put into that channel?
Assuming (require '[clojure.core.async :as a])
,
user=> (def a (a/chan))
#'user/a
user=> (a/go (a/>! a 42))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x194a653d "clojure.core.async.impl.channels.ManyToManyChannel@194a653d"]
user=> (a/go (println (a/<! a)))
#object[clojure.core.async.impl.channels.ManyToManyChannel 0x23973547 "clojure.core.async.impl.channels.ManyToManyChannel@23973547"]
user=> 42
I'm using pathom and parallel-parser]
(def parser
(p/parallel-parser
{::p/env {::p/reader [p/map-reader
pc/parallel-reader
pc/open-ident-reader]}
::p/mutate pc/mutate-async
::p/plugins [(pc/connect-plugin {::pc/register app-registry})
p/error-handler-plugin
p/trace-plugin]}))
(cljs.core.async/go (println (cljs.core.async/<! (into [] (parser {} '[{::latest-product [:product/title :product/brand]}])))))
i'm doing something like this
(cljs.core.async/<! (parser {} '[{::latest-product [:product/title :product/brand]}]))
=> returns #object[cljs.core.async.impl.channels.ManyToManyChannel]
https://wilkerlucio.github.io/pathom/v2/pathom/2.2.0/connect/resolvers.html => resolvers with single input
I'm confused... in the first piece of code you have (into [] ,,,)
and you're trying to call <!
on ... a vector? but in the second piece of code you're calling <!
on the result of the parser
call, which doesn't seem the same...
...and then if you're getting a channel back from <!
then I can only deduce you're putting a channel onto a channel, rather than... the value you're looking for?
hummm! makes sense
The go function will return a #object[cljs.core.async.impl.channels.ManyToManyChannel]
`=> (def c (a/chan)) #'c` `=> (a/go (println (a/<! c))) #object[cljs.core.async.impl.channels.ManyToManyChannel] => (a/put! c "hello") true hello`
And because its async, the println will happen some time in the future, whenever parser is done doing what it does, and not as soon as you send the form to the repl
I've tried to put the result into a vector before print and returned me #object[cljs.core.async.impl.channels.ManyToManyChannel]
hummm! makes sense
when I did (.log js/console (fn)) I could inspect the result,
maybe I'll stay here ^^'
like here
I'll stay with "normal" parsers, until I understand how theses stuff works, thanks
For CI/CD, which one is easier to setup? CircleCI or GitHub Actions? I am using Clojure CLI.
They're both pretty easy but GitHub Actions means you don't need to do any setup so I'll say that's "easier". You can see what I've done for next.jdbc
here: https://github.com/seancorfield/next-jdbc/blob/master/.github/workflows/test.yml
In ClojureScript, is there a equivalent to jsoneditor to edit edn data structures? https://github.com/josdejong/jsoneditor
They're both pretty easy but GitHub Actions means you don't need to do any setup so I'll say that's "easier". You can see what I've done for next.jdbc
here: https://github.com/seancorfield/next-jdbc/blob/master/.github/workflows/test.yml
Hi, I’m coming from a Haskell background and I’m trying to learn Clojure. My first steps in pattern matching are pretty frustrating. My question is what is the most idiomatic way to write a code like this (minimal example):
fun :: [a] -> Int -- type signature - function taking list of any a and returning a number
fun [] = 7 -- if the list is empty, just return 7
fun (x:xs) = fun xs -- if the list is not empty (it has a head x), recursively call fun on its tail (possibly empty)
I came up with something like this:
(defn fun [u]
(match [(first u) (rest u)]
[nil _] 7
[x xs] (fun xs)))
but I don’t like it, it seems verbose, I need to use first and rest explicitly and also I have no idea how to pattern match on an empty list (first pattern should be more like: [nil '()]
but it generates compilation error.In idiomatic Clojure, something like that is more commonly written like this:
(defn fun [[h & more]] ;; <-- idiom: destructuring an array into a head and tail
(if (seq more) ;; <-- idiom: seq returns nil if given an empty array (nil is "falsey")
(fun more)
7))
if
for two-way branching, or cond
for multi-way branching is idiomatic. Pattern matching a la Haskell is not a part of Clojure, although there is a library or two that are not commonly used that provide something like it (although no static guarantees of exhaustivity of cases). Destructuring in Clojure is fairly commonly used: https://clojure.org/reference/special_forms#binding-forms
Also in that example (recur more)
guarantees tail-call optimization with no call stack growth, which is important if the sequence length can exceed the call stack limit of the JVM (default is somewhere around 8000 somethings, but I forget the unit of the somethings)
core.match is one of the libraries I was referring to (without names, sorry). It exists, and some fraction of people use it, but I don't believe it is widely used.
Ok, so another example to make sure if I get it:
replaceFirstWith :: Eq a => a -> a -> [a] -> [a]
replaceFirstWith _ _ [] = []
replaceFirstWith y z (x : xs) | x == y = z : xs
replaceFirstWith y z (x : xs) = x : replaceFirstWith y z xs
In Clojure (first my initial version then after your comments):
(defn replaceFirstWith [y z u]
(match [(first u) (rest u)]
[nil _] '()
[x :guard #(= % y) xs] (conj xs z)
[x xs] (conj (replaceFirstWith y z xs) x)
))
(defn replaceFirstWith2 [y z [h & more]]
(cond
(= h nil) '()
(= h y) (conj more z)
:else (conj (replaceFirstWith2 y z more) h)
))
(let’s forget about tail recursion for a moment)If you want the function to support nil
as an element of a sequence, then the first condition would not be correct.
So how to check if [h & more]
is an empty list? In Haskell there is a pattern syntax p@(x:xs)
(or using the same names whole_list@(h:more)
) where p
stands for whole matched list.
And I think perhaps the earlier example from @manutter51 did not handle the case of a single element sequence correctly
Hmm, should be ok for a single element list, but would probably bomb on an empty list, now that I look at it
The perils of playing "REPL in my head"
It is somewhat common in clojure.core code (which isn't always idiomatic) to define a separate function arity for the empty list, e.g. see (source max-key)
Here is one way to write the function fun
above so that it handles empty sequences correctly:
(defn fun2 [[h & xs :as s]]
(if (seq s)
(+ h (fun2 xs))
7))
Sorry, I added the (+ h ...)
part myself, so I could test to see that it was doing something with every element
The :as s
part of that seems to correspond fairly closely to the Haskell p@
syntax you describe above, but I'm not familiar enough with the Haskell version to know if they are identical in all ways.
So, I suppose the following modified definition should handle nil
as an element of a sequence:
(defn replaceFirstWith2 [y z [h & more :as s]]
(cond
(= (seq s) nil) '() ;; -> (empty? s) '()
(= h y) (conj more z)
:else (conj (replaceFirstWith2 y z more) h)
))
But in this case I have an impression that (= (seq s) nil)
is a bit too much for such a simple check.you can also try (empty? s)
it will return true
for nil
and any kind of empty collection
one thing I like about Clojure is that it seems to handle nil
very well, as in all std functions are made so that they don’t explode on nil
so if you’re destructuring like this [a & as]
and you don’t expect nils in your collection, you can just check if a
is nil
I see... It’s good to know that there are relatively sane conventions although I’m used to very strict static typing and I like when the code like this just does not compile. But I’m trying to convince myself to other benefits of this approach.
@adam.szlachta Clojure is amazing at data processing and transformation. I’ve rolled out two non trivial production systems since 2015
oh no, you only have today!
It is considered more idiomatic in Clojure to use (seq s)
rather than (not (empty? s))
but it certainly may be less obvious to someone new to Clojure. If you want to avoid a not
call, you can put the non-empty case first, before the empty case.
But in most cases (and what I got used to) firstly I check for an empty list (corner case), and (empty? s)
does the job, no need for not
. So remaining conditions will be implicitly (not (empty? s))
which does not have to be checked anymore.
nil
is logical false in if/cond/when conditions, as well as false
, and this is relied on quite often, so it is quite rare to see (nil? ..)
in a conditional expression.