Fork me on GitHub

@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 "G") "C"
    (= letter "C") "G"
    (= letter "T") "A"
    :else "U"))

(defn to-rna
  (str (map #(translate %) msg)))

(print (to-rna "GCTA"))
outputs clojure.lang.LazySeq@3604c1


You don't need to wrap translate in a lambda, since its already a one-arity fn.


(map translate msg) will work


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.


Sequence functions, like map, filter, remove, for, etc. are all lazy


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.


You can do that with (doall lazy-seq)


This will force the looping to happen at that moment


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


An easy solution for you is to convert to a non lazy sequence using seq


(defn to-rna
  (str (seq (map #(translate %) msg))))


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 \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.


I require as string, it doesn’t get any warning


@madstap just used apply, that seems to kinda be right... except it returns "UUUU" 0_o

(defn to-rna
  (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.


Also, calling seq on a string returns a sequence of characters. (not= "G" \G)


And map calls seq on it's argument.


So you should have (= letter \G) in your translate fn


Also,`(map #(translate %) msg)` is redundant, can be just (map translate msg).


thanks 👍


Hello, why is this doesn´t work ? (reduce #(conj %1 "1") [] (into [] (range 2)))


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


so, I can´t ignore it?


I´m using range just to repeating "1"


you can ignore the arg, but your function needs to accept it


ok, thank you 4 ur help


yeah, it's a bot, it's a little slow though


hi how do i use web fonts with garden?


Looking for details...

Lucas Barbosa14:09:18

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.

Lucas Barbosa14:09:56

I wonder why it doesn’t talk about core.async, though

Lucas Barbosa14:09:20

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.

Lucas Barbosa00:10:14

Makes sense! Thanks for pointing that to me, I appreciate it 😄


core.async was definitely a thing then

Lucas Barbosa14:09:48

I guess the author wanted a smaller scope

Lucas Barbosa14:09:01

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)


(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