Fork me on GitHub
#beginners
<
2019-07-12
>
jayesh-bhoot03:07:24

Hi. I am trying to make sense of the clojure syntax and grammar. Am I correct when I say "where keywords (function in JS, def in Python, etc.) are used in other languages, clojure uses macros (defn) and special forms (fn, if)?"

andy.fingerhut03:07:33

I suppose there could be considered some similarities there. special forms are built into Clojure at a very low level, and you can't easily "turn them off" (not that anyone would want to, I don't think). A significant difference is that you can write your own macros in the Clojure language, and they effectively extend the language using itself. I don't believe there is anything quite like that in JS or Python.

jayesh-bhoot03:07:35

@andy.fingerhut Oh I agree that macros are much more capable. I was trying to place clojure concepts in relation to other programming languages. I will try to rephrase: "While a programming language like Python has certain reserved tokens called keywords (eg: def, if, class), nothing like it exists in clojure. Or the closest thing like it is the special forms." Am I correct here?

andy.fingerhut03:07:13

That sounds like a pretty reasonable analogy to me.

andy.fingerhut03:07:42

I do not know off hand whether it is possible in Clojure to redefine the special forms, within Clojure itself. If it is, that would be another way they would differ from keywords in those languages.

andy.fingerhut03:07:08

I suspect that might not be possible to do in Clojure.

andy.fingerhut03:07:34

Heck, let me try and see what happens, though.

jayesh-bhoot03:07:07

Haha I hope I havent sent you on a wild goose chase

jayesh-bhoot03:07:31

So the basic tokens in clojure are pretty much the literals: numeric, string, symbols, collections

jaihindhreddy06:07:18

Not quite so. Clojure has a two-phase syntax. One is in text, and the other is in the interpretation of data. @a, #'a, 'a and #(+ 1 %) come to mind as examples. These are not data. But after the reader reads this, the first phase of syntax is interpreted, and now you are left with data. The above examples are read into (deref a), (var a), (quote a) and (fn [x] (+ 1 x)) respectively (except for the last one which uses arg names that don't clash with symbols you have used in there). But the Clojure compiler doesn't know about this first phase of syntax.

jayesh-bhoot11:07:52

You are right. In that case, I could say that literals are one of the types of tokens parsed in clojure reader/compiler, others being these special characters and of course comments ;.

jayesh-bhoot11:07:29

But it does not have these types of tokens: identifiers, keywords.

jaihindhreddy15:07:58

The whole concept of tokens is to split text to parse. Say you eval'ed @a in the REPL, @ and a are the tokens for the reader. There is no tokens after the reader is done with it. It's just data. This is then turned into an AST, which has a more elaborate representation. In non-LISPs, this mid-phase of data doesn't exist.

jayesh-bhoot13:07:55

Yes. Actually after writing to you, I started digging around these concepts (tokenization, parsing), and dug myself into a hole where I stopped at program segments (.text, .data, heap, stack). 🙂

jayesh-bhoot13:07:33

And now I understand your last message: in other languages, its byte stream -> token stream -> AST.

jayesh-bhoot13:07:15

in lisp, its byte stream -> token stream -> 'data' -> AST

jayesh-bhoot13:07:20

On my way up, now I am looking into clojure's source code repo to see how Symbol and Var are implemented.

andy.fingerhut03:07:01

collections like lists, vectors, maps, and sets are built in, yes.

jayesh-bhoot03:07:46

yes I meant those. great.

dpsutton04:07:34

I don’t think you can even shadow special forms in let bindings.

andy.fingerhut04:07:26

I believe I saw one weird case in an open source Clojure code base where they wrote a macro named 'catch', which shadowed the catch special sub-form within a try.

andy.fingerhut04:07:10

I wouldn't have noticed, except I was testing the Eastwood linter at the time, and it was misbehaving on that before fixing it.

andy.fingerhut04:07:54

That code was definitely several sigmas away from the mean, though.

dpsutton04:07:42

Ha. You are an encyclopedia of edge cases

naproxen17:07:32

i failed with js interlop ^^

dpsutton17:07:54

My guess is sethours doesn’t return anything

valtteri17:07:21

>>> The setHours() method sets the hours for a specified date according to local time, and returns the number of milliseconds since January 1, 1970 00:00:00 UTC until the time represented by the updated Date instance.

noisesmith17:07:05

yeah, that number isn't the value you want

valtteri17:07:12

I suggest using doto macro

noisesmith17:07:20

it mutates now, so give it a different name and continue using it

noisesmith17:07:24

doto works as well

naproxen17:07:26

what is doto macro

naproxen18:07:00

ah this looks like the solution thank you ^^