Fork me on GitHub
#off-topic
<
2019-03-27
>
seancorfield00:03:40

GPL is "viral" and a lot of companies categorically won't touch libraries licensed under GPL.

Daniel Hines00:03:55

What does it mean for a license to be “reciprocal”?

Daniel Hines00:03:27

(e.g, when RH says MIT and BSD are not reciprocal)

seancorfield01:03:08

In particular, MIT and BSD are discussed in that context at the bottom of that article.

seancorfield01:03:54

(I didn't know -- it took me a few minutes on Bing to find something that actually explained it!)

john01:03:02

All open source / free software / copy left licenses are just bandaids over the farcicality of the copyright / patent trade law in general

john01:03:49

So, my dear fellow Clojurians, render for me in your mind, if you would, an imaginary data structure we shall call a #smv

john01:03:23

in written edn form, it might look like this:

#smv [[0 :a "bob"]]

john01:03:09

The first column is the key index colum of the vector. The second is the key column for the map relations. If a key relation is missing (#smv/nil) then the index for the row (its first element) defaults to the key

john01:03:31

If we were to define one of these #smv like so:

(def smv
  #smv
  [[0 :a "bob"]
   [1 :b "ann"]])

john01:03:11

Calling conj on an #smv act's like a vector:

(conj smv "ted")
Would produce:
#smv
[[0 :a "bob"]
 [1 :b "ann"]
 [2 :smv/nil "ted"]]

john01:03:36

Calling assoc would act like a hash-map:

(assoc smv :granny "sue")
#smv
[[0 :a "bob"]
 [1 :b "ann"]
 [2 :smv/nil "ted"]
 [3 :granny "sue"]]

john01:03:23

When executing sequential operations, only the last element of each #smv element is returned:

(vals smv)
#smv
("bob" "anm" "ann" "ted" "sue")

(seq smv)
#smv
("bob" "anm" "ann" "ted" "sue")
When executing map-like operations, it would act like a map:
(keys smv)
#smv
(:a :b 2 :granny)

john01:03:06

Now, I haven't actually gone an implemented such a structure, but would something like that seem worth experimenting with?

john01:03:47

It's like a unified structure that can be acted upon by all functions that act on sets, maps and vectors

john01:03:30

Under the hood, it would hold an extra hashmap, which contains a map of keys to index nodes on the vector, to preserve fast lookup

john01:03:07

Point being, "it is better to have 100 functions operate on one data structure..."

john01:03:22

So the idea would be, see how far that could be taken to the extreme

john01:03:12

What I haven't worked out yet is how the set mechanics will work

john01:03:15

But, in general, I'm thinking that the vals of a key value pair, should only impact the equality value of the thing

yuhan01:03:45

Would this structure allow for duplicate keys?

john01:03:50

Just like how the key associated with the third item of a vector happens to be 2, but the value is not impacted by the twoness in its vector

yuhan01:03:02

otherwise you couldn't conj more than once

john01:03:35

associng on an existing key would overwrite it

john01:03:09

conjing doesn't take a key, so the next index becomes the key, sotospeak

john01:03:24

the map would be implicitly ordered

john01:03:51

in the order the structure is constructed

john01:03:21

I guess the bigger philosophical question would be, could it be possible to combine the sequential, associative and relational properties into one data structure, such that all mutation functions can operate over that one structure

yuhan01:03:30

wouldn't the key for conj operation be a default :smv/nil?

john01:03:42

But if you called key on that nth item, you'd get the number back, I'd think

yuhan01:03:26

then what would (assoc (conj (conj #smv "a") "b) :smv/nil "c") produce

john01:03:26

well, :smv/nil is suppose to be for internal use, so you can still use nil as a key in your map, if you want

john01:03:51

But that could probably be handled more internally

john01:03:39

But calling (assoc (conj (conj #smv [] "a") "b") :blah "c") would I think produce:

#smv
[[0 :nilish-thing "a"]
 [1 :nilish-thing "b"]
 [2 :blah "c"]]

yuhan01:03:15

but you wouldn't be able to assoc or get the :nilish-thing?

john01:03:19

or

#smv
[[0 #smv/nil nil "a"]
 [1 #smv/nil nil "b"]
 [2 #smv/nil nil "c"]]

john01:03:00

well, you'd have some internal thing that allowed you to represent when the key should be represented as its index or as the key it's been provided

john01:03:09

doesn't matter what the nillish thing is

john01:03:14

nor does it have to be exposed

yuhan01:03:44

ie. (get *1 nil) on your above example

yuhan01:03:02

would that return "a" "b" or "c"

yuhan01:03:05

just trying to see where the sequence and mapping semantics might conflict

john01:03:36

in the above example, #smv/nil nil would literally mean "no key is here, use the number to the left as the key"

yuhan01:03:55

and if you had

#smv
[[0 1   "a"]
 [1 #smv/nil nil "b"]]

john01:03:06

so

(get
 [[0 #smv/nil nil "a"]
  [1 nil "b"]
  [2 #smv/nil nil "c"]]
 nil)
would return "b"

john01:03:53

An important point of difference when trying to understand where sequence and mapping might conflict... when sequencing a map, it gives you key-value pairs. This gives you only the values, like a sequence would.

john01:03:31

But if you call keys on it, you could zipmap it to recreate it

john01:03:04

with the seqed vals

yuhan01:03:00

seems like values which were inserted using sequence-like conj would then be inaccessible from the mapping-like operations

yuhan01:03:53

what would you get to return "c" in your above example?

john01:03:11

either first or #(nth % 0) or (get % 0)... but I would be in error if I assumed "a" should have a named label. Which would rightly trouble your expectations of map-like things.

john01:03:47

I thought you said "a"

john01:03:00

so last, etc

john01:03:40

It's like a vector where you can give items optional names

yuhan01:03:17

yeah, so you couldn't use (get ...) to access it

john01:03:58

#(get % 2) => "c"

yuhan01:03:19

and if there was a key of 2?

john01:03:41

Then that'd be the key of 2

yuhan01:03:00

how would you know in advance if an integer key is treated as a key or an index

yuhan01:03:25

I think this would complect too many things into one

john01:03:31

If it's an integer, it's always the key and index

yuhan01:03:59

if I wanted a mapping data structure with a well defined ordering I'd use an (ordered-map)

yuhan01:03:53

and fmap from fluokitten does a good job of abstracting maps as containers of their values (instead of kv pairs)

john01:03:32

Complect too many things into one... Maybe. That's what I want to know though. Or would having a singular, uni-structure actually simplify things further?

john01:03:57

I suppose datoms are sorta like that, or you could use them that way

3Jane08:03:22

@john PHP arrays work like that, at once a vector/array and a hash map

👍 5
3Jane08:03:04

Some very “interesting” side effects stem from that. I like Clojure precisely because it mostly avoids the problem, and its collection functions operate on structures in a sane way.

💯 5
3Jane08:03:40

(Modulo clojure.set and contains?)

andy.fingerhut08:03:40

There is a problem with contains? on Clojure sets?

bronsa09:03:01

I read that as - contains? - clojure.set

bronsa09:03:44

contains being weirdly named as we know, clojure.set having bad GIGO

3Jane09:03:36

What he said

bronsa11:03:01

First service is free, next time I'll start requesting a fee

andy.fingerhut16:03:43

Oh, understood then. Yeah, I've done what I know how to, and am authorized to do, for clojure.set over the years. I'm done with it.

👍 4
joelsanchez16:03:27

some day I will know why rename-keys is in clojure.set. this is not that day, nor will be tomorrow

andy.fingerhut16:03:59

My best guess: clojure.set started as things like union, intersection, difference, then grew into operations on relations like join, project. Rich found it a good idea to create rename-keys in order to implement join.

3Jane16:03:06

…you’ve just changed my life significantly for the better

3Jane16:03:18

(I found out about project)

3Jane16:03:20

also this looks like a relational algebra implementation

andy.fingerhut16:03:37

It looks like a relational algebra implementation, because it is 🙂

andy.fingerhut16:03:20

Entirely for in-memory data structures, and not optimized to the N-th degree with indexes, etc. the way a production SQL database often is.

mbjarland08:03:03

Thank you @hiredman, @seancorfield and everybody else for the responses on GPL and clojure! Much appreciated and yet another testament to the helpfulness of the community.

👍 5
danieroux12:03:47

A mini rant on accretion not deletion. I've been failing to reify an interface, getting the error message Can't define method not in interfaces: extract. Added the this parameter. Still no luck. Turns out the documentation I was looking at was wrong. And, the interface had a breaking change in the next version! They added a previousTimestamp parameter, and dropped the old method. https://kafka.apache.org/0101/javadoc/org/apache/kafka/streams/processor/TimestampExtractor.html and https://kafka.apache.org/10/javadoc/org/apache/kafka/streams/processor/TimestampExtractor.html </end>

john14:03:07

Another interesting datastructure: a map where the keys are sets and associng simply adds a key to a keyset for an existing val. A get would return the val for the keyset-val pair whose keyset contained the passed in key to get. All keysets in a keyset map would have to be distinct though, to ensuring only one val per key.

john14:03:58

Though I suppose similar behavior is achieved with nested maps...

john14:03:09

Or, alternatively, a keyset map where keysets didn't have to have all distinct elements - just each keyset be unique. Then you could query the keyset map for all vals that include some passed in keyset.

john14:03:50

But this idea of treating an associative data structure like a sequential one when provided to a function that normally operates on sequential things, like filter, perhaps the keys associated with the value (if there is one) could be attached to the value as meta data, so the sequencing function still access to the key? Or would it be better to pass values that happen to have keys associated with them as KeyValuePairs when a sequential function runs into them?

john15:03:01

otherwise, doing sequential operations on #smv like things would seem lossy, since the seq coming out the other end wouldn't preserve the keys

john15:03:59

Or one could just go with Index-Key-Value tri's [i k v] and seq operations just receive something like an IndexedMapEntry that had those three components

john15:03:13

But I'm still partial to exploring this idea where keys don't impact the value semantics for the values in an associative data structure

john15:03:34

where the structure acts sequential, associative and relational

jaide16:03:28

Been playing with bacon in cljs and using this as a reference to make some dynamic animations:

(ns app.animation
  (:refer-clojure :exclude [range])
  (:require [bacon :as bacon :refer [End]]))

(def time-started (atom 0))

(defn ease
  [x]
  (* x x))

(defn transition
  "Takes a duration in ms and an easing function.
  Returns a bacon stream that emits a percentage so that it reaches 1 at the
  end of the duration."
  [duration ease-fn]
  (-> (.interval bacon (/ duration 100) 0)
      (.scan 0 inc)
      (.takeWhile #(<= % 100))
      (.map #(/ % 100))
      (.map ease-fn)))

(defn fade-in
  [opacity]
  (set! (-> js/document (.-body) (.-style) (.-opacity))
        opacity))

(defn go!
  []
  (-> (.once bacon 0)
      (.flatMap #(transition 1000 ease))
      (.doAction fade-in)
      (.onEnd identity)))

jaide16:03:41

Though I think my ease function is off

🥓 4
jaide22:03:21

Oh. Turns out I screwed up most of the code… well. Learning. 🤷