This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-09-30
Channels
- # ai (3)
- # beginners (86)
- # boot (3)
- # chestnut (1)
- # cider (29)
- # clara (2)
- # cljs-dev (18)
- # cljsrn (1)
- # clojure (104)
- # clojure-greece (3)
- # clojure-losangeles (1)
- # clojure-spec (2)
- # clojure-uk (1)
- # clojurescript (5)
- # core-async (5)
- # css (3)
- # emacs (3)
- # figwheel (7)
- # fulcro (60)
- # lein-figwheel (3)
- # luminus (4)
- # off-topic (7)
- # portkey (14)
- # reagent (12)
- # rum (1)
- # shadow-cljs (9)
@dannystanny01 @rcustodio I'd say try to avoid it. It doesn't work in clojurescript, and it's really annoying trying to read a namespace where you have to jump to the top to find out where a symbol comes from. The build in clojure libs all have mostly standard, terse, aliases which makes it easy to tell where they come from. (ns foo.core (:require [clojure.string :as str])) (str/upper-case "string")
(`clojure.set :as set` clojure.walk :as walk` etc.)
@madstap, thanks! I actually ended up doing that with (:require [clojure.string :as str])
since just importing I saw some warnings about ns collisions in REPL
so this is driving me crazy
(ns rna-transcription)
(defn translate
[letter]
(cond
(= letter "G") "C"
(= letter "C") "G"
(= letter "T") "A"
:else "U"))
(defn to-rna
[msg]
(str (map #(translate %) msg)))
(print (to-rna "GCTA"))
outputs
clojure.lang.LazySeq@3604c1
Now map returns a lazy-sequence. It does not loop. A good thing to start thinking about early is the difference between lazy and eager.
Generally, when the collection is the last argument of a function, its a sequence function, and almost always lazy.
Lazy functions don't loop, they only return a lazy-seq. They wrap your computation into a lazy sequence. That can later be used to loop one element at a time, only when the element is needed.
str calls the .toString function of an object. A lazy-seq is an object, and its toString implementation just returns the class name and memory pointer location, that's why you get clojure.lang.LazySeq@3604c1
.
So what you want to ask yourself is, when do you want to actually loop and translate? Is it inside to-rna? If so, you must realize your lazy-sequence inside to-rna.
Now, the second issue is that lazy-sequences in clojure don't toString in the way you want, you want the elements to be concatenated inside a string.
So you also want to convert the lazy-seq into something that has the str behavior you want, or you need to implement your own str over lazy-seq that does what you want
The conversion will also force the realization of the lazy-seq, so you don't need the doall.
So a good thing to start to think about is, what am I dealing with here? Is it a sequence function? Is it a lazy-seq ? Do I want to process all elements right away? Or do I want to process them one at a time only when I access an element? Do I want it represented as a lazy-seq? Or would I prefer a seq? A vector? A list?
Wow, that's incredibly helpful, thank you so much! You've given me much to think about. Here's where I ended up with that little program if you have any additional pointers:
(ns rna-transcription (:require [clojure.string :as str]))
(defn translate
[letter]
(cond
(= letter \G) "C"
(= letter \C) "G"
(= letter \T) "A"
(= letter \A) "U"
:else (throw (AssertionError. "Wrong nucleotide"))))
(defn to-rna [msg] (str/join (map translate msg)))
to-rna
should be iterating the string, and translating the letters.... but I'm getting back an object?
Yeah, calling str
on a lazy seq returns the representation of the object. Try pr-str
.
@madstap just used apply, that seems to kinda be right... except it returns "UUUU" 0_o
(defn to-rna
[msg]
(apply str (map #(translate %) msg)))
apply str
does something different. It's just like calling str
with each element of the sequence as an argument instead of the whole sequence as an argument.
the function arg to reduce must take two arguments
fyi you could remove the call to into and the behavior would not change at all
right, the reducing function must accept an accumulator argument and also the current element, in that order
you can ignore the arg, but your function needs to accept it
yeah, it's a bot, it's a little slow though
I’ve been reading the Clojure Programming book by Chas Emerick (et al.) during the past few days. Even though this is the third “basic” Clojure Book I am reading, I am learning a lot. I thought it was going to be a waste to go through the first chapters, since it’s about basic building blocks, but I was completely wrong and reading them gave me a lot of insight. Just wanted to share some feedback with you guys, since I picked this recommendation from this channel. This is definitely a very nice book for beginners.
I wonder why it doesn’t talk about core.async, though
It’s a 2014 book. Was core.async a thing at that point?
core.async is not part of the standard library. In 90% of cases, you won't need it. Its really just an optional nice to have component for certain specific concurrent use cases. Most books don't cover non standard library things, so I'm not surprised.
Makes sense! Thanks for pointing that to me, I appreciate it 😄
core.async was definitely a thing then
I guess the author wanted a smaller scope
focusing on enforcing basic concepts
Hey all, I am fetching an array of objects (js) from an endpoint and I would like to spread
(sorry for the js parlance) it into a list, here is what I have:
(def cities ())
(-> (js/fetch endpoint)
(.then (fn [res] (.json res)))
(.then (fn [res] (join (js->clj res) cities)
As you can see, I was playing with the idea that the issue was that res
is a js object and does not have the required methods, so I was attempting to convert it with (js->clj res)
which join is that?
I believe the one from the standard library
I tried a few methods, not sure which one is correct - still learning to read the CLJ docs
there's no such thing as clojure.core/join - I just don't know what that function is supposed to be
hmmm, lets ignore that then...which method should I be using to get my desired result?
OK, for starters, () is immutable, all clojure data structures are immutable
so you need to either replace it, or use a mutable container, or use a local binding so that a new version can be passed to the consumer
True. This is where JS is holding me back a little mentally. What would idiomatic clojure look like if I am writing a small, self contained program which is required to 1. get data 2. store data is some global var (is this an atom in clojure?) 3. have other functions that can operate on this global data store?
if (.json res)
returns an array, all you need is
(def cities (atom nil))
(-> (js/fetch endpoint)
(.then (fn [res] (reset! cities (seq (.json res))))))
or closer to your original if .json needs to return a promise, etc.
also, when you mentioned "required methods" what exactly did you have in mind?
For example, a JS object is not seqable, correct?
you said it was an array, arrays are seqable
if it's an object, well we need to figure out what exactly you are trying to do to it
Sorry, you are right. I was thinking of a NodeList
yeah, there are weird things that are a pain to handle even in js
but if you have an array or object, things should be straightforward. Also, js->clj is probably not the ideal answer generally
From my readings, it did not seem like a good idea. I was desperate for a solution in that moment 😉
in cljs you can use google closure, goog.object has things that make dealing with values a lot easier
just curious now, in js, if I wanted to join two arrays, I would do this:
a1 = [1, 2, 3]
a2 = [4]
a3 = [...a1, ...a2] // [1, 2, 3, 4]
What is the equivalent in clojure?Either (concat a1 a2)
- yields a lazy seq - or (into a1 a2)
(yields a collection of the same type as a1
)
Thanks!
(into a1 a2)
if a1 is a clojure type
or (into [] cat [a1 a2])
if not
or just (concat a1 a2)
- depending on what you are trying to do
concat is lazy, into is strict