Fork me on GitHub
#beginners
<
2017-09-30
>
madstap00:09:41

@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.)

dannystanny0101:09:08

@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

dannystanny0101:09:08

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 [email protected]

didibus23:09:36

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

didibus23:09:50

(map translate msg) will work

didibus23:09:54

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.

didibus23:09:20

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

didibus23:09:48

Generally, when the collection is the last argument of a function, its a sequence function, and almost always lazy.

didibus23:09:33

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.

didibus23:09:22

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 [email protected].

didibus23:09:21

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.

didibus23:09:10

You can do that with (doall lazy-seq)

didibus23:09:20

This will force the looping to happen at that moment

didibus23:09:52

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.

didibus23:09:19

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

didibus23:09:51

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

didibus23:09:11

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

didibus23:09:55

The conversion will also force the realization of the lazy-seq, so you don't need the doall.

didibus23:09:31

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?

didibus23:09:46

@dannystanny01

dannystanny0109:10:52

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)))

dannystanny0101:09:06

to-rna should be iterating the string, and translating the letters.... but I'm getting back an object?

madstap01:09:24

Yeah, calling str on a lazy seq returns the representation of the object. Try pr-str.

rcustodio01:09:46

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

dannystanny0101:09:35

@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)))

madstap01:09:35

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.

madstap01:09:44

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

madstap01:09:13

And map calls seq on it's argument.

madstap01:09:34

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

madstap01:09:20

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

fabrao02:09:21

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

noisesmith02:09:56

the function arg to reduce must take two arguments

noisesmith02:09:06

fyi you could remove the call to into and the behavior would not change at all

noisesmith02:09:40

right, the reducing function must accept an accumulator argument and also the current element, in that order

fabrao02:09:07

so, I can´t ignore it?

fabrao02:09:51

I´m using range just to repeating "1"

noisesmith02:09:37

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

fabrao02:09:11

ok, thank you 4 ur help

noisesmith03:09:08

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

sakalli05:09:18

hi how do i use web fonts with garden?

jiyinyiyong13:09:19

Looking for details...

lvbarbosa14: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.

lvbarbosa14:09:56

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

lvbarbosa14:09:20

It’s a 2014 book. Was core.async a thing at that point?

didibus23:09:18

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.

lvbarbosa00:10:14

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

noisesmith14:09:48

core.async was definitely a thing then

lvbarbosa14:09:48

I guess the author wanted a smaller scope

lvbarbosa14:09:01

focusing on enforcing basic concepts

tkjone15:09:39

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)

tkjone15:09:17

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)

noisesmith15:09:56

which join is that?

tkjone15:09:19

I believe the one from the standard library

tkjone15:09:38

I tried a few methods, not sure which one is correct - still learning to read the CLJ docs

noisesmith15:09:43

there's no such thing as clojure.core/join - I just don't know what that function is supposed to be

tkjone15:09:18

hmmm, lets ignore that then...which method should I be using to get my desired result?

noisesmith15:09:58

OK, for starters, () is immutable, all clojure data structures are immutable

noisesmith15:09:39

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

tkjone15:09:50

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?

noisesmith15:09:30

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))))))

noisesmith15:09:36

or closer to your original if .json needs to return a promise, etc.

noisesmith15:09:16

also, when you mentioned "required methods" what exactly did you have in mind?

tkjone15:09:13

For example, a JS object is not seqable, correct?

noisesmith15:09:28

you said it was an array, arrays are seqable

noisesmith15:09:45

if it's an object, well we need to figure out what exactly you are trying to do to it

tkjone15:09:24

Sorry, you are right. I was thinking of a NodeList

noisesmith15:09:47

yeah, there are weird things that are a pain to handle even in js

noisesmith15:09:20

but if you have an array or object, things should be straightforward. Also, js->clj is probably not the ideal answer generally

tkjone15:09:51

From my readings, it did not seem like a good idea. I was desperate for a solution in that moment 😉

noisesmith15:09:50

in cljs you can use google closure, goog.object has things that make dealing with values a lot easier

tkjone15:09:17

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?

val_waeselynck15:09:34

Either (concat a1 a2) - yields a lazy seq - or (into a1 a2) (yields a collection of the same type as a1)

noisesmith15:09:27

(into a1 a2)

noisesmith15:09:45

if a1 is a clojure type

noisesmith15:09:04

or (into [] cat [a1 a2]) if not

noisesmith15:09:29

or just (concat a1 a2) - depending on what you are trying to do

noisesmith15:09:35

concat is lazy, into is strict