Fork me on GitHub
#beginners
<
2019-08-21
>
sova-soars-the-sora03:08:53

hallo... i'm conj'ing maps into a sequence... sometimes i want to remove a map from the sequence, how can i delete a map from a sequence (in an atom) using swap?

sova-soars-the-sora03:08:45

I'm making an online japanese vocabulary quiz for the kanji (imported chinese glyphs) and their compounds.

sova-soars-the-sora03:08:10

Someone suggested that it would be cool to select which glyphs you already know so you can be fed only compounds that satisfy from the set of "known glyphs" you indicate

sova-soars-the-sora03:08:13

so i'm working on that! i'm stoked, it's pretty cool, but there are some weird things. is it okay to store these individual kanji like so?

(def all-tango (atom [{:tango "日" :kanji "日"}
{:tango "月" :kanji "月"}
{:tango "一月" :kanji ["月" "一"]}
{:tango "十月" :kanji ["月" "十"]}
{:tango "同月" :kanji "月"}
{:tango "会う" :kanji "会"}
{:tango "出る" :kanji "出"}
{:tango "出す" :kanji "出"}																						{:tango "同じ" :kanji "同"}]))

(def individual-kanji (atom [{:kanji "日"} {:kanji "会"}	{:kanji "同"}	{:kanji "月"}	{:kanji "一"}	{:kanji "十"}	{:kanji "出"}]))

sova-soars-the-sora03:08:15

As you can see, the individual pieces are noted, and you can click on them on the app and add them to an active set, i want to compare the active set with the :kanji list in the all-tango. (Tango means "vocabulary, words") so you can see each word and then what kanji are part of it.

sova-soars-the-sora03:08:41

Right now I don't know how to compare a collection of "known kanji" against the constituent parts of each vocab word in the all-tango atom.

salam04:08:21

@sova sets are perfect for this use case. you may use a set to store the constituent kanji of a tango (e.g., {:tango "一月" :kanji #{"月" "一"}}). you may use another set to store the "known kanji" (e.g., (def known-kanji #{"日" "同" "一" "出"}). from there on, you can use clojure.set/subset? to filter out tango(s) from the tango vector whose constituent kanji set is a subset of the known-kanji set.

4
salam15:08:50

i’m not in front of a computer right now. but i have a question: why are you keeping all-tango and individual-kanji in atoms?

salam15:08:41

it seems like these represent a known set of things that you can pick elements from and shouldn’t have a reason to change at runtime.

sova-soars-the-sora15:08:58

Great question! I'm making an online quiz. Maybe you can help me figure out what's most natural in Clojure. There's a set of all characters, you can click on them and add them to a known kanji atom (changes at run-time, during runtime) because it'll generate quizzes for you on compound words based on the ones you know.

sova-soars-the-sora15:08:46

Tango and All-Kanji never change, like you say, so what's a more relevant data structure? I've ingrained the atom access pattern it's all i use! haha

salam17:08:51

this is how i would do this: 1) figure out a way to get a list of tango from all-tango based on known-kanji for one round of the game (i.e., state for a single round). 2) leveraging what's in 1), use loop/`recur` to generate state for each round of a continuous game.

sova-soars-the-sora21:08:21

that's great. thank you, i agree! i didn't think about loop and recur, i will have to employ them !

sova-soars-the-sora22:08:06

I got it working. Set thinking was the way to go. I do a simple check if the intersection of kanji and the compounds is a superset of the compounds that make up a compoundword, and if that's true then i print it out. works very pretty so far ^_^

🎉 4
sova-soars-the-sora14:08:40

I need some help writing that filter

Ian Fernandez14:08:11

I'm using deps.edn in clojure in macOS

Ian Fernandez14:08:24

but It's not detecting my namespaces

Ian Fernandez14:08:37

{:paths   ["src/main"]
 :deps    {org.clojure/clojure {:mvn/version "1.10.1"}}
 :aliases {:test {:extra-paths ["test/main"]
                  :extra-deps  {lambdaisland/kaocha {:mvn/version "0.0-529"}}
                  :main-opts   ["-m" "kaocha.runner"]}}}

Ian Fernandez14:08:45

it's like this the deps.edn

Ian Fernandez14:08:06

the tree of files is:

.
├── README.md
├── bin
│   └── kaocha
├── deps.edn
├── src
│   └── main
│       └── core.clj
└── test
    └── main
        └── core_test.clj

Ian Fernandez14:08:49

the namespaces are: and for core.clj =>

(ns main.core)
and for core_test.clj =>
(ns main.core-test)

Ian Fernandez14:08:21

is there something wrong?

uosl14:08:36

could you try changing :paths to only "src"?

clj 4
Ian Fernandez14:08:00

it worked, why

uosl14:08:56

np! the namespaces start from the path, so with "src/main" it was expecting to find the files in src/main/main/core.clj.

👍 8
uosl14:08:34

you should make the same change in :extra-paths as well

robertfw18:08:03

I am defining a rather long regex and am trying to split it over multiple lines. Currently I'm using re-pattern and constructing my string up of multiple fragments split over a few lines, though this means having to double escape. Is there a way to build up a regex over multiple lines without having to perform that double escaping? (e.g., #"\d{2}" must be written "\\d{2}")

noisesmith18:08:58

user=> (re-pattern (str #"\d" #"\w"))
#"\d\w"

noisesmith18:08:48

you can use the regex reader by using the #"" notation for each of the substrings

noisesmith18:08:52

it combines as expected

noisesmith18:08:16

you can also use format with %s instead of str if that makes things clearer (%s also does the right thing with an re input)

Michael Stokley20:08:06

i have a hash map with a key :@timestamp

Michael Stokley20:08:41

when i try to get the value it throws a syntax error Invalid token: :

Michael Stokley20:08:02

i've tried putting it in double quotes and escaping it with \

Michael Stokley20:08:04

i guess i could change it into a string... any other options folks may know of?

ghadi20:08:37

Sounds like elasticsearch. (keyword "@timestamp") should get you going

💯 4
ghadi20:08:57

It is constructable but not readable as a literal

Chase21:08:39

hello! I had some questions on my solution for the Collatz Conjecture problem on exercism:

(defn collatz [num]                                                                   
  (if (or (neg? num) (zero? num))                                                     
    (throw (Exception. "Input must be a positive number"))                            
    (loop [num num                                                                    
           count 0]                                                                   
      (cond                                                                           
       (= 1 num) count                                                                
       (even? num) (recur (/ num 2) (inc count))                                      
       (odd? num) (recur (+ 1 (* 3 num)) (inc count))))))

Chase21:08:58

The tests for (collatz 0) and (collatz -15) were checking for thrown? Throwable (collatz 0) which I've never encountered before so I just hacked together my solution with assumptions of what they were looking for. Any advice or is that ok for simple error checking? Error checking in general is a huge blind spot. Any resources you recommend? I own a few Clojure books but haven't really hit on that subject yet.

Chase21:08:10

I feel my brain is just stuck on loop/recur for solving problems. I resort to it a lot in exercism and 4clojure. Is this ok and you found you moved more towards reduce and higher order sort of functional solutions as you progress or am I really building bad habits by keep reaching for this current method? At the moment I find it much easier to wrap my head around.

noisesmith21:08:09

that if / first branch could jjust be {:pre [(pos? num)]}

noisesmith21:08:36

I don't think reduce makes any sense here as there's no incoming seq to consume

noisesmith21:08:56

perhaps (->> (iterate ...) (take-while ...) (last)) ?

noisesmith21:08:53

or drop-while / first

Chase21:08:58

ok, good stuff already! I definitely want to learn about this pos? check. I was trying to think of a good way to do that.

Chase21:08:39

Yeah, for this particular one I wasn't thinking reduce would be good. But in general I've been told I should be trying to move away from loop/recur when possible but my brain keeps taking me there.

noisesmith21:08:49

pre automatically throws assertion error, which should work in your case

Chase22:08:27

what exactly is frowned upon with loop/recur? Is it just not a good idiomatic way for functional programming?

noisesmith22:08:58

it's low level

noisesmith22:08:22

it does things by hand that can be done in a less error prone way via higher level constructs

noisesmith22:08:28

consider this version

(->> 12
      (vector 0)
      (iterate (fn [[c n]]
                 [(inc c)
                  (if (even? n)
                    (/ n 2)
                    (inc (* 3 n)))]))
      (map second)
      (take-while (comp not #{1})))

noisesmith22:08:11

it returns a lazy-seq of values of the function until it hits 1

noisesmith22:08:55

that''s another advantage to not using loop/recur - you can do lazy processing

noisesmith22:08:05

oh wait - that's weird, one moment

noisesmith22:08:11

fixed - returns the thing you want (count) plus the values along the way

(->> 12
      (iterate (fn [n]
                 (if (even? n)
                   (/ n 2)
                   (inc (* 3 n)))))
      (take-while (complement #{1}))
      ((juxt count identity)))

noisesmith22:08:21

you can turn that (juxt ...) into count to just get that

noisesmith22:08:52

it could be my clojure stockholm syndrome, but to me that's much more direct in describing the algorithm than the loop version

noisesmith22:08:35

1) iterate this function on N 2) keep getting values until you get the value 1 3) count the results

noisesmith22:08:02

it's got an off-by-one in there that's easy enough to fix lol

Chase22:08:11

interesting stuff right there. i hope to get to that level some day. at my current ability my solution (I've refactored a little cleaner) is much more understandable but I can just see that yours is super Clojure-y. hahaha. I like it.

noisesmith22:08:44

note that the name of the clojure function iterate is precisely the term for the mathematical operation your loop is doing

noisesmith22:08:32

and the iterate function really does do what the core of your loop does (repeatedly call f on its result)

Chase22:08:18

awesome. I've saved this away and will work through it some more. I'm definitely taking away some great ideas here

noisesmith22:08:10

if I was doing this in a project, I would define and use this function also (based on take-while but it also takes the first item failing the predicate as well)

(ins)user=> (defn take-until [pred coll] (lazy-seq (when-let [[e & es] (seq coll)] (cons e (when (pred e) (take-until pred es))))))
#'user/take-until
(cmd)user=> (take-until (complement #{10}) (range))
(0 1 2 3 4 5 6 7 8 9 10)

Chase09:08:39

hey @U051SS2EU, you might be happy to know I already used that :pre catch to great effect to solve another problem. And I got rid of a loop to use some sweet threading macros and map functions. Thank you again!

(defn dna->rna [dna]
  (case dna
    "G" "C"
    "C" "G"
    "T" "A"
    "A" "U"))

(defn to-rna [dna]
  {:pre [(every? #{\A \C \G \T} dna)]}
  (->> dna
       (map str)
       (map dna->rna)
       (apply str)))

noisesmith17:08:59

btw you could skip (map str) by putting a char -> char mapping in dna->rna

noisesmith17:08:26

and dna->rna could just be a hash-map:

(def dna->rna
  {\G \C
   \C \G
   \T \A
   \A \U})

noisesmith17:08:04

since hash-maps act as lookup functions when called

Chase20:08:56

ooh, I like that.

Chase20:08:49

that was actually really eye opening advice. I've never used a def to a map like that and feeding it values as if it was a function or something. It's just so fun when you starting seeing these patterns in the way clojure is designed.

noisesmith20:08:35

it comes from the formal definition of a function - mathematically a pure function is equivalent to a map

noisesmith20:08:00

so why not use a map as a function (with a very specific domain, of course)

sova-soars-the-sora22:08:06

I got it working. Set thinking was the way to go. I do a simple check if the intersection of kanji and the compounds is a superset of the compounds that make up a compoundword, and if that's true then i print it out. works very pretty so far ^_^

🎉 4