Fork me on GitHub
#beginners
<
2018-10-21
>
peter-kehl06:10:01

Form validation: Say that a form is well-formed, but even in compile time (after expanding macros) it's clear that a form will fail when run. Why doesn't it fail at compile time, please?

#("string-literal")

dpsutton14:10:34

another thing to note, is that that is not necessarily bad syntax

dpsutton14:10:00

(extend-type js/String IFn (-invoke ([this] "hi"))) would make that valid code

peter-kehl21:10:26

Thank you @andy.fingerhut and @U11BV7MTK.

andy.fingerhut07:10:34

@sb If you get that to work, you could make it higher performance by caching the result the first time the function is called, then using the cached value on later calls.

andy.fingerhut07:10:34

@sb If you get that to work, you could make it higher performance by caching the result the first time the function is called, then using the cached value on later calls.

sb08:10:43

@andy.fingerhut With memoize enough or do I need to use a better solution?

andy.fingerhut08:10:46

One way would be to have a Clojure atom that is initially nil, and if it is nil when the function is called, calculate the function name, and store the value in the atom.

andy.fingerhut08:10:30

That technique could be done using a separate atom per "log call site"

sb08:10:54

Ok, thanks! I test it! 👍

sb10:10:50

Thanks, that is faster! (~60%)

andy.fingerhut07:10:42

@peter.kehl I can only give you my guess as to the true answer to your question, since I do not know for certain. My guess is that this is a fairly uncommon mistake to make, and it is caught the first time that code is executed anyway.

Michael Fiano08:10:08

Hello. I have a Java byte array, and I'd like to change the ordering of the bytes to little endian, so I call the .wrap method of a ByteBuffer, and then call (.order buf ByteOrder/LITTLE_ENDIAN). Finally, I retrieve the array with the ByteBuffer's .array method, but it is giving back to me the original array. What is the correct way to get a reordered byte array back?

moxaj09:10:56

@mfiano what does that byte array contain? encoded integers?

andy.fingerhut09:10:29

I have not used Java's ByteBuffer class before, but from a quick scan of some of the methods, it is possible that the order method only changes the "view" that you get when using some methods to get data from the ByteBuffer, but the array method returns the current value of the backing array.

moxaj09:10:34

what you are doing right now is a noop

Michael Fiano09:10:17

I'm not sure what the answer is. I am reading octets from a binary file using another library, which has a .toByteArray method

andy.fingerhut09:10:34

Perhaps calling order method, then the bulk get method to retrieve the data through the ByteBuffer, storing it into a different array, will do what you want in that other array

Michael Fiano09:10:53

It is also possible that the .array method only returns the backing array unmodified

moxaj09:10:22

say you write 4 integers into the buffer, then change the endianness - nothing will happen, those bytes are already written

moxaj09:10:59

so, if given a byte array, you'd need to know what it represents, read it accordingly, reset the position to 0, change the endianness, and write the valuse back, then finally get all the bytes with get(byte[] dst)

Michael Fiano09:10:35

Ok I'm very new to Java and Clojure. I'm just trying to re-order a byte array while retaining the Java type in order to do more interop afterwards so I can't use Clojure sequence functions.

Michael Fiano09:10:45

I'll try some more. Thanks for the tips

Michael Fiano09:10:52

Hmm, I can't figure it out. I'll sleep on it

sb11:10:51

Hello, how can I solve this in Clojurescript?

(meta #'(clojure.string/replace curr#  "$" "/"))
curr value monitor.monitor$debug .. I tried with #'(symbol (clojure.string/replace....) but not works.

moxaj12:10:00

@sb I don't think var-quote works with expressions

moxaj12:10:49

try using the function var instead?

moxaj12:10:57

although this is cljs

sb12:10:26

Yes, that is a good idea. I try it!

TK16:10:51

Hey guys, I want to know the best way to solve this kinda of problem I need to sort a vector of hashes based on the my-boolean. Sort it true value first. So I have this input:

[{:id 1 :my-boolean false}
 {:id 2 :my-boolean true}
 {:id 3 :my-boolean false}]
And I want this output:
[{:id 2 :my-boolean true}
 {:id 1 :my-boolean false}
 {:id 3 :my-boolean false}]
My first approach was to update my-boolean to an integer, to use the sort-by function - true --> 0 - false --> 1 Something like this
(def my-hashes
  [{:id 1 :my-boolean false}
   {:id 2 :my-boolean true}
   {:id 3 :my-boolean false}])

(def bool-enum {true 0 false 1})

(defn boolean-to-int
  [my-hash]
  (get bool-enum (:my-boolean my-hash)))

(defn update-my-boolean
  [my-hash]
  (assoc my-hash :my-boolean (boolean-to-int my-hash)))

(defn new-hash
  []
  (map update-my-boolean my-hashes))

(defn sorted-hash
  []
  (sort-by :my-boolean (new-hash)))

(sorted-hash)

;; ({:id 2, :my-boolean 0} {:id 1, :my-boolean 1} {:id 3, :my-boolean 1})
Can I solve this problem without the update from boolean to an integer?

dpsutton16:10:23

(let [data [{:id 1 :my-boolean false}
            {:id 2 :my-boolean true}
            {:id 3 :my-boolean false}]
      {yes true no false} (group-by :my-boolean data)]
  (concat yes no))

dpsutton16:10:32

(let [data [{:id 1 :my-boolean false}
            {:id 2 :my-boolean true}
            {:id 3 :my-boolean false}]
      group (juxt #(filter :my-boolean %) #(filter (complement :my-boolean) %))]
  (apply concat (group data)))

moxaj16:10:23

@leandrotk100 (reverse (sort-by :my-boolean my-hashes)) does the job (but it is not 'stable', if you care about that)

orestis16:10:50

Also (since you are sorting by booleans): (sort-by (complement :my-boolean) my-hashes)

moxaj16:10:02

^ that one's stable

orestis16:10:34

The more generic approach: (sort-by (fn [x] (bool-enum (:my-boolean x))) my-hashes)

orestis16:10:58

In general, you should never need to mutate the thing you are trying to sort.

👍 1
orestis16:10:05

The sort-by function uses the “decorate-then-sort” approach, but you only need to provide with the function that provides a sorting value for each element.

orestis16:10:32

(I edited the function above, my rebel-readline repl was misbehaving because I started it with clj)

TK17:10:17

Interesting @orestis!

andy.fingerhut17:10:33

One general technique to reverse the normal comparison order is to create a custom comparator function that swaps the order of the things being compared, e.g. (defn reverse-order-compare [a b] (compare b a))

noisesmith17:10:07

you can do the same thing with (comp - compare)

andy.fingerhut17:10:15

This guide on http://clojure.org mentions that one, and some other tips on comparison functions for Clojure: https://clojure.org/guides/comparators

andy.fingerhut17:10:38

@noisesmith I would be cautious about recommending that to people, for the one tiny corner case where it breaks.

noisesmith17:10:47

or (sort-by f > coll) to reverse what f does

andy.fingerhut17:10:54

(- Integer/MIN_VALUE) is equal to Integer/MIN_VALUE

noisesmith17:10:08

@andy.fingerhut oh - I didn't know that gotcha

andy.fingerhut17:10:17

Actually, to be more precise, (int (- Integer/MIN_VALUE)) is equal to Integer/MIN_VALUE, but Java comparison functions have a return type of int, and Clojure does the truncation to 32-bit int on any comparator functions you define.

andy.fingerhut17:10:44

not where they are defined as functions, because Clojure doesn't know whether it will be used as a comparator -- the int conversion is somewhere in the code Clojure uses when passing it as a comparator function to Java's sort method, or something similar to that.

andy.fingerhut17:10:29

True for all fixed with integer types using 2's complement representation, which every integer in the JVM does.

andy.fingerhut17:10:50

It is mentioned in the guide article

noisesmith17:10:15

user=> (sort-by :a > [{:a 0} {:a 3} {:a 2}])
({:a 3} {:a 2} {:a 0})

andy.fingerhut17:10:24

ok, maybe not that particular case, but the guide article does warn against using subtraction to create a comparison function, because of issues with int wraparound.

noisesmith17:10:52

that was an alternate suggestion, point taken about using - for reversing comparators

noisesmith17:10:37

using > also works with sort

+user=> (sort > [1 3 8 2])
(8 3 2 1)

TK17:10:43

and by any chance can I use the sort-by function to sort based on if the hash has a value (`another-something`) in the vector of :primary to make from this

[{:id 1 :primary ["something"]
 {:id 2 :primary ["another-something"]
 {:id 3 :primary ["another-something"]]
... to this?
[{:id 2 :primary ["another-something"]}
 {:id 3 :primary ["another-something"]}
 {:id 1 :primary ["something"]}]

andy.fingerhut17:10:05

TK was asking about sorting booleans, though, where < > etc. only work with numbers

andy.fingerhut17:10:37

@leandrotk100 If you want to do multi-value sorting, I'd recommend taking a look at the decorate - sort - undecorated technique mentioned in the guide I linked to.

andy.fingerhut17:10:52

Basically, write a function that creates a vector from your values. The vector will be discarded when sorting is done, but used during sorting. The first element of the vector is your primary sort key, 2nd element is secondary sort key, etc., as long as you want. All vectors should be the same length. This works because Clojure's built-in compare function will sort same-length vectors by first element first, then 2nd element if 1st element is same, etc.

grierson17:10:51

What are some good resources to look up after watching "The language of the system"?

andy.fingerhut17:10:37

Maybe not what you are looking for, but there are lots of other good talks by Rich Hickey, many with transcripts available here: https://github.com/matthiasn/talk-transcripts

grierson17:10:42

Maybe some examples of 'Simple services'?

TK18:10:24

@andy.fingerhut thanks for the resource! But what I want is to sort the vector based on an "external value" For example, I have the value another-something, and a vector

[{:id 1 :primary ["something"]
 {:id 2 :primary ["another-something"]
 {:id 3 :primary ["another-something"]]
Based on the value another-something, I want to sort the hashes that have this value on the :primary. In this case, the hashes with id 2 and 3 have another-something as a value of :primary. So the output would be
[{:id 2 :primary ["another-something"]}
 {:id 3 :primary ["another-something"]}
 {:id 1 :primary ["something"]}]

andy.fingerhut19:10:58

So you want all maps with a key of :primary that have the value "another-something" to be first in the result, and all other maps to be after those, and among those that do, order is irrelevant between them in the result, and among those that do not, order is irrelevant in the result?

TK19:10:08

yes! But order is relevant in terms of the :id (increasing order)

enforser19:10:06

user=> (sort-by (partial not= "another-something") ["a" "c" "another-something" "another-something" "something-else" "another-something" 1 4 5 :key])
("another-something" "another-something" "another-something" "a" "c" "something-else" 1 4 5 :key)
could you just sort based off equality?

andy.fingerhut19:10:23

So "primary sort key" is "every map with :primary containing "another-something" must be first", and "secondary sort key is "value of :id key"

TK19:10:05

Yes! I can use the multi-value sorting that you mentioned

andy.fingerhut19:10:42

You could write a function that returns a vector of 2 elements, where the first element is 0 if the map contains "another-something" in its :primary key value, and 1 if it does not.

TK19:10:26

what would be the second element of this vector?

TK19:10:03

From

[{:id 1 :primary ["something"]
 {:id 2 :primary ["another-something"]
 {:id 3 :primary ["another-something"]]
To
[[1 ...]
 [0 ...]
 [0 ...]]

andy.fingerhut19:10:05

The value of the :id key

TK19:10:55

So

[[1 1]
 [0 2]
 [0 3]]

TK19:10:12

Interesting! I read this https://github.com/jafingerhut/thalia/blob/master/doc/project-docs/clojure.core-1.5.1/clojure.core/sort-by.md The decorate - sort - undecorate concept. In this case, I would "undecorate" to re-build the actual vector of maps, right?

TK19:10:40

(->> [-5 4 -1 3 -2]
     (map (fn [x] [(square x) x]))  ; decorate with (square x)
     (sort-by first)                ; sort by the decorated value
     (map second))                  ; undecorate
Should I use the threading operator ->> (so that the computation steps can be written in the order they occur)?

noisesmith19:10:58

how is that different than (sort-by square [...])

TK19:10:06

I think this is just a simple example to show how the decorate - sort - undecorate concept works

andy.fingerhut20:10:35

Decorate here just means "create the derived values which you are going to use for sorting, e.g. vectors with multiple values in them".

andy.fingerhut20:10:47

Undecorated just means "throw away the derived values that were used only for sorting"

andy.fingerhut20:10:09

The decorated values should be paired with the original values being sorted, so there is no need to recreate the original values.

andy.fingerhut21:10:39

@leandrotk100 Whether to use a threading operator, or to write nested function calls, is a style issue that reasonable people can disagree on, I think. Using the threading operator with 2 expressions seems kind of on the edge of usefulness to me. If you have 4 or 5 expressions, I personally prefer the threading operator.

Michael Fiano22:10:47

is it good style to make function parameters all on their own line if 1 or more of them have long nested destructuring going on?

TK23:10:21

Another thing I was thinking is: how do I keep my functions "pure" if I need to use a collection that is not accessible inside my function, for this example

(->> a-collection
     (map function-1)
     (sort-by first)
     (map function-2))
Let's say that in my function-2 I want to access the collection a-collection. How do I keep function-2 pure (don't use external "variables" - only data passed as parameters)?

andy.fingerhut23:10:28

You could write function-2 to take two arguments, one element from a-collection (or whatever is returned from function-1 in your example), as well as the entire collection. Then make a threading expression like this:

andy.fingerhut23:10:55

(->> a-collection
     (map function-1)
     (sort-by first)
     (map #(function-2 % a-collection)))

andy.fingerhut23:10:48

The #(function-2 % a-collection) is another way to write (fn [item] (function-2 item a-collection))