Fork me on GitHub
#beginners
<
2015-12-01
>
cjmurphy03:12:36

Does anyone know why question marks are sometimes at the beginning, as in having a key in a hash-map like this {:?data nil}?

cjmurphy03:12:04

I understand a ? at the end is the same as the convention in Java of having is at the beginning, it denotes a predicate. But what does it mean when the ? is at the beginning?

andrut03:12:00

I've seen (?assoc m k v) which means conditional assoc -> assoc value v only if it's present, maybe it means optional data then?

eraserhd03:12:00

There’s a convention in lisps of using a prefix question mark to indicate a meta-variable or something that will be unified or substituted.

eraserhd03:12:29

Sorry, that’s an obtuse statement. Let me find an example.

cjmurphy03:12:42

haha, a bit

eraserhd03:12:28

?char and ?line get replaced later.

eraserhd03:12:33

In that example, ?nfa ?inputs and ?result get substituted once for each line in the table.

eraserhd03:12:11

Am I helping or shedding dark on the subject? simple_smile

cjmurphy03:12:14

Its given me something to look out for, that I'll be able to 'complete' a bit later I think. Something like a default. 'substituted' is a funny word in an immutable language thou.

eraserhd03:12:45

Well, it is copied with values replaced.

cjmurphy04:12:42

Most things that are mapped, get build out into something different, could have a ? at the beginning.

eraserhd04:12:11

You’re saying you’d expect to see it more often?

cjmurphy04:12:43

I guess I am, if it was a rigid convention.

cjmurphy04:12:31

Prolly it means a little more than I understand right now. I know I'll get it when I see an example I need to understand. That's how I got destructuring.

eraserhd04:12:50

The idea is introduced in Paul Graham’s “On Lisp” on page 238. Titled “Destructuring” ironically.

seancorfield04:12:31

I've seen the ?var thing quite a bit in the context of... well, I thought logic programming... but now I'm having a hard time finding examples online.

eraserhd04:12:05

@seancorfield: It’s in core.unify.

seancorfield04:12:13

I know they (Clojure/core) talk about Datomic in terms of Datalog queries but when I went looking for that, everything looked like Prolog instead...

seancorfield04:12:39

Ah @eraserhd that's where I've seen it... I expected to see it in core.logic as well but...

roelof06:12:01

@trancehime: thanks, maybe this can be something for a project I have in min

trancehime06:12:24

I am new too, it's all a learning experience for me

seancorfield06:12:22

Hey @roelof ! Good morning !

seancorfield06:12:34

What's today's project?

seancorfield06:12:31

Ah yes... that's an interesting one...

roelof06:12:46

but im happy if 30 is solved

roelof06:12:18

I have to think how I can "store" the old value somehow and compare it against a new one

roelof06:12:27

except for the first number

roelof06:12:20

@seancorfield: first I thought to use set or distinct but no luck . Set does not do the job and distinct deletes to much

seancorfield06:12:08

Since you want to go from a collection to a subset of it, you probably want to start with reduce

roelof06:12:54

that is what I thought

seancorfield06:12:01

Bear in mind you need to produce two things: an accumulated value (the collection with no duplicate elements) and the last seen value (so you can detect duplicates).

seancorfield06:12:18

Then you can just extract the accumulated value.

roelof06:12:32

yes that is what I already thought

seancorfield06:12:40

Think about how you do this in a non-FP language...

seancorfield06:12:56

and then fold that into a reduce as a pair of values.

roelof06:12:16

if last_element != former_element then add last_element to acc and former_element = last_element else take the next element

roelof06:12:27

I do it in words

roelof06:12:56

the problem I see here is that former_element has to have some kind of value

seancorfield06:12:13

Start with nil?

roelof06:12:21

he, that is a idea

roelof06:12:54

so I can do [let former_element nil]

seancorfield06:12:28

Also, consider destructuring which is a great way to pull apart a pair of things

seancorfield06:12:50

(fn [[acc last] x] ...) for example as your reduce function...

roelof06:12:25

oke, then I do not have to assign a value to the last one

roelof06:12:37

good idea , have also not thought about that

roelof06:12:58

oke, how can I call it better then

seancorfield06:12:15

You bind a value to a symbol.

roelof06:12:35

oke, I mean the same

seancorfield06:12:39

And loop / recur will re-bind a (new) value to a symbol.

seancorfield06:12:49

That way you'll get into the FP mindset.

roelof06:12:54

some other fp langugaes call it assign I think

roelof06:12:41

now it is simple problem if you figured all the seperate parts

roelof06:12:02

I will fire up cursive as soon as my daugther is to school

seancorfield06:12:24

Heh, I do this in a bare repl... I find IDEs overwhelming...

roelof06:12:54

oke, everyone his own preferences way of work

roelof06:12:18

I think in about a hour I can try to make this exercise work

roelof06:12:46

I mean work to look if my ideas are correct

seancorfield06:12:32

4clojure had a lot fewer exercises when I did it... for a while I was actually keeping up with it at first... but it got away from me once it got to about 70 challenges!

roelof06:12:31

oke, and do you do now other challenges or do you use clojure for work @seancorfield

seancorfield06:12:10

Clojure is my primary work language these days. We first took Clojure to production in 2011.

seancorfield06:12:26

It only became our primary language late last year

roelof06:12:50

oke, and may I know what you make with clojure ?

seancorfield06:12:00

Internet dating platform.

roelof06:12:38

oke, when Im much more familiair I think I will try to make a e-commerce site or a accounting site

roelof06:12:51

but I think that will be next year

roelof06:12:13

and no pressure because clojure and programming is a hobby of mine

seancorfield06:12:58

Most of our low-level e-commerce integration is done with Clojure now (iTunes, Paymentwall, Braintree, SBW)

roelof06:12:26

oke, I think about the front part, making invoices , adding and deleting products in clojure

seancorfield06:12:30

In our app, the VC part of MVC is CFML, and some of our M (legacy code). More and more of our M is Clojure now.

seancorfield06:12:00

But we've also moved nearly all of our HTML emails over to Clojure (using Selmer) now.

trancehime06:12:22

I'm hand-writing (in a notebook!!) the stuff I'd like to do with async, mostly, since I am using sente, this would be my event-msg-handler :ev-id

roelof06:12:35

oke, I doubt between luminus and doing everything myself but as I said that is a problem of the future

trancehime06:12:31

I've avoided using framework (I'm not even sure I'd call Luminus a real framework. Even the main site calls it a 'micro-framework' which is probably more accurate) and instead rolled out my own handlers and stuff.

trancehime06:12:42

Helps me to learn the language while also accomplishing tasks

trancehime07:12:55

Incidentally, I've actually run into the most hiccups (heh) in Clojure with regards to destructuring

roelof07:12:35

oke, then I have to find a good book/tutorial where things like compujure and ring are explained

roelof07:12:11

is Web development with clojure a good book ?

trancehime07:12:05

Couldn't tell you; I didn't really have time to read books

agile_geek07:12:23

@roelof: It is, if like me, you learn best by working through an example end to end. Did you say you came to Clojure from Ruby and Rails? If so it would probably suit you quite well.

roelof07:12:15

I did come from the rails world

roelof07:12:12

@agile_geek: do you have a example of a end-to-end example. I though web development has one a picture upload site

agile_geek07:12:38

The picture upload site is the main example that runs through most of the chapters in the book. There is a RESTful API example in the early chapters that was using the liberator library but I haven’t seen the second edition of Web Development with Clojure so it may have changed as there are a lot of new libraries in that field.

roelof07:12:06

Any better example then ?

agile_geek07:12:41

@roelof: nothing specific springs to mind although there are loads of blog articles on Clojure web development. The example in the book works quite well as it covers rendering pages in different templating libraries, using ClojureScript, database integration with JDBC and Korma, etc.

agile_geek07:12:22

I just read around libraries and built my own little examples.

roelof07:12:02

oke, thanks for the info @agile_geek

roelof07:12:32

@seancorfield: is this what you mean as a solution : https://www.refheap.com/112225

trancehime07:12:52

I had to spend a lot of note-taking to wrap my head properly around defmulti

roelof07:12:54

that is a difficult one but I saw on the clojure koans that you can also use protocols as a alternative

agile_geek07:12:33

You can although Protocols can only dispatch on type whereas multimethods can dispatch on anything.

roelof07:12:15

oke, maybe I misunderstood the koans

trancehime07:12:46

I wanted to understand defmulti properly as I plan to manage my sente event handlers through a defmulti

seancorfield07:12:17

@roelof: without the ( ) around acc but yes.

seancorfield07:12:50

and you need an initial value which would be... [[] nil] perhaps?

seancorfield07:12:43

I think you want [acc x] for that case BTW

seancorfield07:12:21

so (if (= last x) [acc x] [(conj acc x) x])... something like that?

seancorfield07:12:36

So, yeah, I think you're very close...

roelof07:12:53

@seancorfield: where in your code is then the [ [] nil] part or do Ihave to add it myself

seancorfield07:12:46

It's the initial value for reduce...

seancorfield07:12:56

(reduce func init coll)

andymyers07:12:38

@adam_cameron: I've been tinkering for a while and I'm still very much a beginner. I just haven't had the consistency with it. It's totally different to anything else I've used

adam_cameron07:12:19

That's what I'm finding too (and I'm not really any further than "G'day world" still).

adam_cameron07:12:14

Other stuff keeps getting in the way. For example I am currently writing a CFML-oriented blog article. And have another one to do after that (which is a guest author one, so will be quick to do). But I only have another 35min left before I need to start my day job

roelof07:12:42

@seancorfield: so it will be (reduce (if (= last x) [acc x] [(conj acc x) x]) [[] nil] coll)

seancorfield07:12:03

@roelof: something like that, yeah...

roelof07:12:21

oke, I will try it in repl. thanks for the help

roelof07:12:48

@andymyers: any questions where we can help you

trancehime07:12:08

I've got a question. Well, assuming I used io/copy to write a file to the local filesystem, how would I go about to retrieve that same file in a different function or page to display it?

seancorfield07:12:58

@roelof: you need a fn in there

seancorfield07:12:08

(fn [[acc last] x] ...)

agile_geek07:12:28

@andymyers: I’ve been on the Clojure / Lisp journey for close to three years but almost all outside the ‘day job’. It takes time but stick with it. If this is your first lisp and first functional language it’s a whole new paradigm and a completely alien syntax to learn and you go through ‘cycles’ of understanding.

seancorfield07:12:57

It's a lot easier when you can integrate it into your work... because it takes repetition...

seancorfield07:12:09

wax on, wax off... over and over again...

roelof08:12:13

yes, that is why I try to do one or two 4clojure exercises a day

seancorfield08:12:33

Yes, do exercises every day. Very important.

roelof08:12:49

hmm, I think a parentheses problem : When I do this (fn [[acc last] x] (reduce (if (= last x) [acc x] [(conj acc x) x]) [[] nil]) list)) I see this output : => #object[clojure_exercises.core$roelof$fn__1456 0x5316c2d8 "clojure_exercises.core$roelof$fn__1456@5316c2d8"]

seancorfield08:12:05

reduce takes a function...

seancorfield08:12:19

Your reduce has an if instead of a function

seancorfield08:12:39

(reduce (fn ...) init coll)

roelof08:12:44

@seancorfield: yes, somehow I have to check if last is equal to x

seancorfield08:12:54

(reduce (fn [[acc last] x] (if ...)) [[] nil] list) -- like that?

seancorfield08:12:55

Remember it's always (reduce function init coll)

agile_geek08:12:03

@roelof: the way I think of reduce is that it’s calling a function over every element of a sequence while maintaining state in [acc last] in @seancorfield’s example.

roelof08:12:09

thanks, it was a parentheses problem. I have now a output like this ; "[[\\L \\e \\r \\o \\y] \\y]" so I have to makeit look like a string

trancehime08:12:01

Hmm. Never mind. I was told the written files would be linked to some domain I could just refer to.

roelof08:12:53

hmm, another nice challenge. When the input is a string , then the output must also be a string , if it's a list the output must also be a string

roelof08:12:07

I could use into but then I have to say which type it must be

roelof08:12:30

back to the cheat sheet for a better function

roelof08:12:52

anyone who can give me a tip where to look

seancorfield08:12:12

The 4clojure test does apply str

seancorfield08:12:35

You're overthinking

seancorfield08:12:11

(reduce (fn [[acc last] x] (if ...)) [[] nil] list) -- is the template

seancorfield08:12:55

When the input is A string you'll get a sequence of characters

roelof08:12:57

yes, I know but then on a string I see [ "t" "e" "s" "t"] instead of test

seancorfield08:12:21

The 4clojure test does apply str on that so you don't have to worry

roelof08:12:11

oke, I tried it on a local repl to see if it works

roelof08:12:33

and on strings I see local the wrong answer

roelof08:12:40

the rest seems to work well

seancorfield08:12:03

But are you actually testing the right thing?

seancorfield08:12:25

On strings you will get a vector of characters. That's correct.

roelof08:12:43

I see on the first one apply str is mentioned. I did not saw it

roelof08:12:06

it working , Another one solved and i saw a very short solution : #(map first (partition-by identity %))

roelof08:12:50

learned another trick

roelof08:12:42

@seancorfield: thanks, now a break and maybe this afternoon or evening the next challenge : http://www.4clojure.com/problem/47

roelof08:12:39

I solved it already but do not fully understand why this is the number

agile_geek08:12:47

@roelof everyone gets tripped up by contains?. Research what contains? does when it operates on an indexed data structure (like vector) versus an associative data structure (like a map).

roelof08:12:37

oke, I will try with the right answer what the outcome of all is

roelof08:12:03

I did read the page about contains? on the clojure cheat-sheet

roelof08:12:35

Am I right here : (contains? [1 1 1 1 1] 2 ) is right because there is a second number avaible

roelof08:12:04

I did not give the right answer here because I do want to spoil the fun for others

roelof08:12:32

but i ask this so I can understand it right

agile_geek08:12:26

almost, vectors are zero indexed so it’s because there’s a third number available.

agile_geek08:12:51

i.e. (contains? [1 1] 2) would return false

roelof08:12:02

oke, thanks, now I understand why the answer is the answer

roelof08:12:57

I still this community because everyone is willing to help and explain things to a newcomer/beginner

agile_geek08:12:34

We were all beginners sometime… and we are all still learning.

roelof09:12:42

other , I tried other languages and there sometimes beginners questions are or ignored of just given a answer without explanation

roelof09:12:18

here no answers but explanations and questions so the newcomer will find the right answer him/her self

roelof09:12:46

and I like that. that way Im learning and not just copy past answers

roelof09:12:01

next challenge for today re-implement interpose

roelof09:12:05

but now a break

trancehime09:12:36

I know I'm still learning

andymyers09:12:51

Thanks folks. Might be time I revisit the 4clojure. I only got about 25% of it done last time round. @adam_cameron are you in this with me?

adam_cameron09:12:31

I was gonna look at Project Euler to start with, but yeah, why not? It'd be good to be able to compare notes. What I mostly need is time.

adam_cameron09:12:15

I only get about 45min in the morning and same @ lunchtime to do anything @ the moment. Evening spare time is all Fallout 4. And this will remain the case for... a while.

roelof12:12:42

@andymyers: if you have questions about 4clojure , ask here, Here there are enough people that can and learn you good clojure ?

adam_cameron12:12:44

(off topic alert) @roelof: sporadically. I don't buy a lot of games, but I don't mind the occasional one. The previous game I bought was Skyrim (so back in 2011), to put it in perspective. I'm finding FO4 to be pretty engrossing currently though.

roelof13:12:55

oke, no problem., everyone his/her hobby

roelof13:12:15

If you want me to remove things I will do

ioneyed14:12:41

Hello all - I am using compojure to create a restful API using postgresql as my data store - I have a route / that invokes a call to my model to return all the rows in the database. The issue is that when I visit the page in a browser or do a get call to the api endpoint the data being returned acts like a file download that comes up empty. No errors but no data either - I can provide more code if needed but any initial thoughts?

roberto14:12:24

@ioneyed look into wrap-json-body and wrap-json-response middlewares.

ioneyed14:12:39

@roberto: do I need to use wrap-defaults at all? It looks like it provides some benefits but since I will be handling file uploads through the api. If I do need it then I am assuming I need to chain the middlewares via a

(-> (wrap-json-body)
            (wrap-defaults app-routes site-defaults))

ioneyed14:12:59

Just using the wrap-json-body instead of wrap-defaults did allow the api to return the proper structure - Thanks! just curious about the defaults that were setup when I ran lein new compojure <appname>

trancehime14:12:14

I am going to go ahead and pass out. Also order matters.

roberto14:12:33

@ioneyed: you used the wrong defaults. There is a site-defaults and an api-defaults

roberto14:12:44

site-defaults are for traditional html pages

roberto14:12:32

I’ve always had to use wrap-json-body, for some reason the order in which you apply the middlewares is significant, and I can never get it right.

ioneyed15:12:47

so I still need to have the wrap-defaults but switch out to use the api-defaults

roberto15:12:10

yeah, the api-defaults will add the wrap-json-body

ioneyed15:12:29

oh so I don't need to use the wrap-json-body itself.

roberto15:12:01

you know what, I’m wrong. You still need to add wrap-json-body et al

roelof15:12:24

why do I get this error message : CompilerException clojure.lang.ArityException: Wrong number of args (2) passed to: core/my-interpose on this code ; https://www.refheap.com/112242

roelof15:12:41

im passing two arguments to the funcion

roberto15:12:43

look at conj

roberto15:12:30

btw, I was wrong yesterday about the reduce fn. It only takes an accumulator and one iterator.

roelof15:12:23

no problem, With some help I could solve it seancorfield help me

roelof15:12:03

@roberto: nvm = nevermind ?

roelof16:12:43

anyone else who see the mistake I have made somewhere

roberto16:12:46

@roelof: your fn inside reduce is wrong

roberto16:12:51

it only should take 2 args

roberto16:12:32

also, the idiomatic way to write vars or function names is to hyphenate them, instead of snake case.

roberto16:12:44

E.g. prefer my-interpose over my_interpose

roelof16:12:58

chips. then I have to rethink my code

roelof16:12:50

Somehow I have to use a acc , the current item and the char who needs to be placed into the right place

roelof16:12:28

@roberto: you are right. When I change my code to ' (reduce (fn [acc ch ] (conj acc ch "2")) [[]] list)' it does work

seancorfield16:12:55

@roelof: nice... I always forget about partition-by!

roelof16:12:44

@seancorfield: I did it know it because I not needed it before

roelof16:12:12

can you help me with my custom interpose

seancorfield16:12:02

Where are you on the problem now?

seancorfield16:12:31

(I just woke up and I'm on my phone - not yet out of bed! :) )

roelof16:12:16

but it seems that I cannot use the three arguments on the fn

roelof16:12:50

but somehow I need to use a acc, the current item and the char which needs to be imposed

roelof16:12:28

we can discuss this over 2 hours if you then have time

seancorfield16:12:28

You don't need ch in the reduce fn - it doesn't change and it's available in the whole my-interpose function

seancorfield16:12:43

That leaves acc and x - two args

roberto16:12:31

@roelof hint: do some research about scope in clojure

roelof16:12:05

oke, I tried this (reduce (fn [acc ch ] (conj acc ch )) [ch] list) but then the ch is only 1 inserted

roberto16:12:14

the ch is in scope within your function, and the reduce fn can access the outer function’s scope.

seancorfield16:12:04

Before you go too far with reduce: consider the shape of the solution... if you have four elements in your list you'll only have three copies of ch, between the elements

roelof16:12:58

oke, I changed the function to this (reduce (fn [acc x ] (conj acc ch x )) [ch] list) and now see this : [0 0 1 0 2 0 3]

roelof16:12:19

almost there the solution needs to be [ 1 0 2 0 3]

seancorfield16:12:30

You are starting with [ch]

seancorfield16:12:51

And then prepending it to every element

seancorfield16:12:05

So it's in there twice at the beginning.

roelof16:12:27

oke, when I changed it to acc x ch I see this : [0 1 0 2 0 3 0] and it needs to be [ 0 1 0 2 0 3]

seancorfield16:12:00

Think about what the accumulator should start with

seancorfield16:12:27

Your reduce prepends ch to every element so...?

seancorfield16:12:25

Also think about what (my-interpose 0 []) should return

roelof16:12:26

correct, so I have to find a way that on the last one the function quits

seancorfield16:12:41

No, don't think of it like that

seancorfield16:12:03

Easier to do something different at the beginning than the end

roelof16:12:26

oke, my-interpose 0 [] schould return a empty [] because there are no items

seancorfield16:12:55

What about (my-interpose 0 [1])

roelof16:12:20

I think [1] because there is only 1 item

roelof16:12:41

interpose schould only work on a map of 2 items

seancorfield16:12:42

(Stepping away for 15)

roelof16:12:21

oke, Im going to make dinner soon. My Wife has called that she is coming to home

roelof16:12:20

hmm, checking the length of list is not going to help

roberto16:12:42

This is pseudo code, not clojure code:

(fn [acc it]
   (if (last of list) == (it)
        (conj acc it)
        (conj acc ch it)))

roelof17:12:13

oke, that way

roelof17:12:07

@roberto: thanks for the tip

roelof17:12:30

Im now making dinner so after making and eating it, I will try it

seancorfield17:12:11

@roberto: No need to special case it and easier to do something different at the start of the list, rather than the end /cc @roelof

seancorfield17:12:39

but remember if you have [0 1 0 2 0 3] you can always call rest to get [1 0 2 0 3]

roelof17:12:11

oke, then the problem is solved

roelof17:12:39

@seancorfield: this is not working : (rest(reduce (fn [acc x ] (conj acc ch x) ) [ch] list))

roelof17:12:37

it still outputs : (0 1 0 2 0 3)

seancorfield17:12:22

As I said above, you’re starting with [ch] which is not correct

seancorfield17:12:04

Since you are prepending ch to each element, you’ll have two ch at the beginning — you only want one.

roelof17:12:55

oke, but when I do this (rest(reduce (fn [acc x ] (conj acc ch x) ) ch list)) then I see this error message : CompilerException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IPersistentCollection,

seancorfield17:12:08

Because ch is not a vector.

seancorfield17:12:15

Think about the types.

roelof17:12:36

acc is a []

seancorfield17:12:47

right… so what’s the initial value?

roelof17:12:01

a empty []

seancorfield17:12:11

so what goes in the reduce?

seancorfield17:12:22

(reduce func init coll)

seancorfield17:12:33

so the init expression should be… ?

roelof17:12:53

[] for init

roelof17:12:04

[] for acc

roelof17:12:23

@seancorfield: thanks , this is working : `(rest(reduce (fn [acc x ] (conj acc ch x) ) [] list)) )`

roelof17:12:39

now testing for the rest of the examples of 4clojure

seancorfield17:12:47

It always helps to think about the base cases… empty list, single element list...

roelof18:12:07

oke, thanks again and again

roelof18:12:28

@seancorfield: found a shorter one : #(drop-last (interleave %2 (repeat %1))

roelof18:12:38

time to study how this one works

roelof18:12:35

oke, interleave places the ch into a place

roelof18:12:10

and I will not surprise me that repeat cares of that it also happens on the other places

roelof18:12:30

so no more 4clojure for today

roelof18:12:04

maybe play a little with the web development with clojure first edition

seancorfield18:12:15

My solution would be something like #(rest (mapcat vector (repeat %1) %2)) — untested

roelof18:12:38

looks almost like another solution I found : fn [sep xs] (drop-last (mapcat list xs (repeat sep))))

seancorfield18:12:12

Yup, in this case — with mapcat — you could use either vector or list interchangeably

seancorfield18:12:49

and drop-last and rest are mirror images — so swapping the args to mapcat would require swapping drop-last / rest

seancorfield18:12:37

I’d probably use butlast instead of the 1-arity drop-last tho’...

seancorfield18:12:18

(drop-last coll) == (drop-last 1 coll) — you can drop an arbitrary number of elements off the end

roelof18:12:36

oke, as we say in the Netherlands, All roads leads to Rome. So there are more then 1 ways to solve a problem

seancorfield18:12:03

Many, many more than one simple_smile

roelof18:12:41

and that is a good one

roelof18:12:54

I think a good one to play with partition-by

roelof18:12:02

but now to tired

roelof20:12:08

could not resist but I solved it

Tim20:12:46

what is the logic behind this:

user> (conj '( 3 4) 2 1)
(1 2 3 4)

ordnungswidrig20:12:53

conj can take any number of elements to ‚add' to the collection

frank21:12:08

also conj adds to the head for lists

ordnungswidrig21:12:32

the location where it’s added depends on the collection type

Tim21:12:37

yeah, I see now

user> (conj '(1 2) 3 4 '(5 6) 7)
(7 (5 6) 4 3 1 2)

seancorfield22:12:03

@tmtwd: conj uses the "fastest" way to add elements so for vectors it’s at the end, for lists it’s at the beginning (behaving like cons). For maps and sets it’s just "whatever" simple_smile

Tim22:12:47

I knew conj had some inconsistency like that, but I forgot what it was

seancorfield22:12:49

Well, it’s consistent but it’s just not obvious...