Fork me on GitHub
#beginners
<
2018-01-23
>
Michael Stokley00:01:55

i'm trying to model a singly linked list. I don't think hash maps will work because i want to allow same-valued nodes. what about a record?

Michael Stokley00:01:31

in python i'd use a class, and as far as i can tell the simplest "class"-like thing in clojure is a record

noisesmith01:01:39

list and lazy-seq are already singly linked lists, I don't know why you would use a hash-map, how is that useful when each node has exactly one successor?

noisesmith01:01:55

if you want to make a singly linked list in clojure and not use a list or lazy-seq (or something from java.util.Collection), the easiest thing is {:value foo :next bar} where bar is another hash with the same keys, or nil

Michael Stokley01:01:26

what would node.next look like if i used a list?

noisesmith01:01:05

in fact, there's a next method too

noisesmith01:01:17

user=> (.next (list 1 2 3))
(2 3)

noisesmith01:01:54

but it's better to use the next function, as it knows how to handle other types, and it's a first class value

Michael Stokley01:01:06

looks like that would work great

Michael Stokley01:01:31

but part of the exercise is deliberately using a more primitive data type, perhaps

noisesmith01:01:43

function instead of method

user=> (next (list 1 2 3))
(2 3)

Michael Stokley01:01:44

where you're handling the nodes and nothing else, if that makes sense

noisesmith01:01:03

sure - then you can use (:next l) if l is the hash map I initially proposed

Michael Stokley01:01:20

when would you use a record over a hash map?

noisesmith01:01:42

+user=> (defn construct [x y] {:val x :next y})
#'user/construct
+user=> (construct 1 (construct 2 (construct 3 nil)))
{:val 1, :next {:val 2, :next {:val 3, :next nil}}}
+user=> (def ls *1)
#'user/ls
+user=> (:next ls)
{:val 2, :next {:val 3, :next nil}}
+user=> (:next (:next ls))
{:val 3, :next nil}

noisesmith01:01:06

generally you would use a record if you need to implement a protocol or interface - if you have methods you need to overload

Michael Stokley01:01:25

ok, that makes sense.

Michael Stokley01:01:53

am i right in thinking the above example doesn't implement a protocol/interface that hash-map doesn't already have?

noisesmith01:01:09

right - it literally is a hash-map

noisesmith01:01:40

if you wanted it to print like a list, or be accepted by all the standard list functions, then you'd want to implement the Interfaces that define a clojure list

sudakatux01:01:46

Im trying to build a simple rest-api with Luminus. just playing. would like to expose the guestbook as a json api. been googling for a while now and i still cant find a simple example for returning basic json data like array or simple objects from a given db query

noisesmith01:01:52

@michael740 if you wanted to also make sure it wasn't a hash-map and couldn't be used that way, there's also deftype

noisesmith01:01:46

@jstuartmilne there's a wrap-json middleware that can take a request handler function and return a new one that makes json - then you just return your data structure

noisesmith01:01:26

@jstuartmilne any standard clojure binding for a database should hand you plain data structures as a result, then it's just a question of making the transforamtions (if any) needed to construct the data your client should expect

sudakatux01:01:57

thank u @noisesmith I kind of got the theory behind it, just couldnt mange to find an example.

sudakatux01:01:36

do you know of a working example to check it out.

noisesmith01:01:45

where f is a function that takes a request and returns some data

sudakatux01:01:23

interesting ill give that a shot

sudakatux01:01:36

thanks again

noisesmith01:01:50

np - I think the example in those docs should be enough to start with - though I understand if you haven't used ring much yet you'll want to play with the request and see what's in it

noisesmith01:01:08

the good news is it's a hash-map, you can print it, look at the keys, use standard clojure data functions on it

noisesmith01:01:34

ring is an exemplary clojure library in that it eliminates a lot of unneeded complexity to just let you use data

sudakatux01:01:10

yeah i was going through the Luminus docks. and the documentation specifies By default, muuntaja middleware library is used to infer the response type when a route returns a map containing the:body key:

sudakatux01:01:20

meaning it should infer

noisesmith01:01:48

interesting - what did you try putting under that key? and what would it use to infer by?

sudakatux01:01:56

or at least thats my understanding. Im surprised i could not find an example for a simple CRUD

sudakatux01:01:56

(GET "/message" []
     :return      []
     :summary     "x^y with header-parameters"
     (ok (db/get-messages)))

noisesmith01:01:59

OK - looking at the muuntaja repo, it looks like it adds the right headers if your :body contains a string that looks like json?

sudakatux01:01:20

so been trying different things

noisesmith01:01:10

oh, you have to explicitly call muuntaja's encode function if it is using that

sudakatux01:01:51

i think the middleware does that

noisesmith01:01:11

but what I don't understand is what tells it "make this json"

sudakatux01:01:25

yeah you are right

sudakatux01:01:34

im clearly missing soemthing hang on

noisesmith01:01:38

anyway, looks like there's docs at the muuntaja repo https://github.com/metosin/muuntaja/wiki/With-Ring (edited for better example)

sudakatux01:01:43

thank u. i still havent figured it out but im not completly lost now

sudakatux01:01:58

was the simplest thing

sudakatux01:01:24

(GET "/message" []
         {:body {:data (db/get-messages)}})

Michael Stokley01:01:45

i'm trying to translate a simple tail call recursion into loop...recur

Michael Stokley01:01:48

(defn reverse_l
  [list_]
  (if-not (seq list_)
    list_
    (concat (reverse_l (rest list_))
            (list (first list_)))))

Michael Stokley01:01:05

am i correct in thinking my call to reverse_l is not in the tail position?

Michael Stokley01:01:09

and therefore i'd need to rework it into something fundamentally not recursive

johnj01:01:41

yes, is not in tail position

Michael Stokley01:01:13

yeah, it throws a compiler exception right away.

Michael Stokley01:01:29

or rather, this does:

(defn reverse-l
  [l]
  (loop [l l]
    (if-not (seq l) l
            (concat (recur (rest l))
                    (list (first l))))))

johnj01:01:39

it can be recursive, but there are many options for recursion because of the limits of the JVM

noisesmith01:01:57

in order to make reverse tail recursive, you need an extra argument representing the already-reversed

noisesmith01:01:18

and then you are putting data into that, instead of the stack

Michael Stokley01:01:21

(reverse-l (rest l))?

johnj01:01:25

the way you should reach first is to use the sequence abstraction

noisesmith01:01:45

@michael740 to make it tail recursive it needs at least two args

noisesmith01:01:04

so you end up with more convoluted code, and a helper function

Michael Stokley01:01:11

hmm. i thought loop was sort of the iterator?

noisesmith01:01:21

if you work out on paper what the function is doing, you'll find that you need two accumulators as it recurs - you can't represent everything in one argument

noisesmith01:01:39

loop is a target for recur - it's basically a goto label plus argument bindings

noisesmith01:01:46

you need two bindings in the loop

johnj01:01:11

if you want to tail call with recur, you can define a local fn that takes the extra arguments

noisesmith01:01:33

@lockdown- loop takes as many args as you like, there's no need for a local function

Michael Stokley01:01:29

oh. the extra arg you're talking about is the accumulation?

noisesmith01:01:55

the essential thing here is to recursively reverse an argument and not consume stack, you need to track two things - unprocessed items, and processed items

johnj01:01:02

@noisesmith yeah, I said that because he can still make his main function take just argument (more elegant I think in this case) and inner function that recurs use the other args

Michael Stokley01:01:21

ok, this gets me on the right track... i'll work it out šŸ™‚

noisesmith01:01:35

@lockdown- right and what I'm saying is that loop takes as many args as you need, and that's the reason you use it instead of recur to the function itself (also a valid target for recur)

johnj02:01:01

oh yeah, it can be loop or a local function

johnj02:01:51

I would think the clojure way here would just be to use the sequence api abstraction

johnj02:01:20

unless its for learning purposes

noisesmith02:01:41

yes, we have to assume that what @michael740 is doing here is an exercise, the existing clojure.core/reverse does use the sequence abstraction (implicitly via reduce1)

noisesmith02:01:42

the code is quite elegant for those who aren't doing this exercise by the way, figuring out why it works can be enlightening (and I'll spoil it a bit by saying it does use a two argument function but ... not exactly the way I am suggesting at first glance)

Michael Stokley02:01:58

(defn reverse-l
  [l]
  (loop [to-reverse l
         reversed (list)]
    (if-not
        (seq to-reverse)
      reversed
      (recur (rest to-reverse)
             (concat
              (list (first to-reverse))
              reversed)))))

noisesmith02:01:30

@michael740 check this out

user=> (source reverse)
(defn reverse
  "Returns a seq of the items in coll in reverse order. Not lazy."
  {:added "1.0"
   :static true}
  [coll]
    (reduce1 conj () coll))

Michael Stokley02:01:04

how do i see the source code for reduce1?

noisesmith02:01:50

for now you can mostly ignore reduce1 and just look at reduce - it's defined in clojure's java code iirc

noisesmith02:01:36

oh - reduce isn't much helpful - it just invokes .reduce method or coll-reduce in clojure.core.protocols

noisesmith02:01:49

so yeah, both are in the java code - they are folds if that helps

Michael Stokley02:01:04

i have a little experience looking at folds in SICP. i remember they can often reverse collections

Michael Stokley02:01:20

maybe that's the intuition you were getting at?

noisesmith02:01:33

that's part of it yes - a reduce can be treated as a loop that always has 1 accumulator for an arbitrary value, and one loop binding that represents "the next item" - it returns the last value of that accumulator when it gets done with the last item

noisesmith02:01:20

@michael740 a very simple improvement you can use with your existing code is use (cons (first to-reverse) reversed) to replace your usage of concat

johnj02:01:45

just wanted to point out that there are many ways to recur in clojure because of the jvm can't optimize direct recursion, and choosing which one is the aproppiate one is not that easy at the beginning, there to many variables to have in mind

johnj02:01:54

no, in private, I'm newbien and may misguide you.

Michael Stokley02:01:47

cons works in "reverse" order??

noisesmith02:01:49

equivalent is (conj reversed (first to-reverse))

noisesmith02:01:58

compared to conj, yes, it's opposite order

Michael Stokley02:01:17

user> (cons 1 (list 2 3))
(1 2 3)

Michael Stokley02:01:35

your suggestion works but i don't see how

Michael Stokley02:01:08

cons puts the first arg in the head position. i want (first to-reverse) last

noisesmith02:01:12

(cons x l) and (concat (list x) l) do the same thing - except cons does it more directly

noisesmith02:01:30

no - you want it at the current head, the same way you were putting it with concat

noisesmith02:01:06

if you add a println that shows each item you process and the current value of what you have processed so far, I think you'll see how it works

Michael Stokley02:01:56

oh. ok. i think i was still thinking about the simpler, recursively-defined function.

Michael Stokley02:01:34

where you do indeed want to return something like (cons (reversed (cdr l)) (car l))

noisesmith02:01:02

cons has args in the opposite order though

noisesmith02:01:23

the second arg to cons must be a collection or nil (treated as equivalent to ())

Michael Stokley02:01:32

yes, that's right.

johnj02:01:13

@noisesmith in the wild, is trampoline or leftfn used much?

noisesmith02:01:47

not as often as you might expect - they are pretty niche tools but very handy when you need them

noisesmith02:01:54

and often they work well together

noisesmith02:01:17

(since you want to be able to refer to other steps mutually in mutual recursion)

johnj02:01:03

@noisesmith by working together you mean using trampoline inside a letfn?

noisesmith02:01:57

I mean the should be able to return each other in order to trampoline (or use each others in partials as the case may be)

noisesmith02:01:20

this can also be done with declare, or by passing one function to the other, but it can simplify things to use letfn

johnj02:01:01

letfn alone consumes allocates stacks frames right?

noisesmith02:01:57

it creates functions, those functions use stack, yes

urbis05:01:16

Hello, could smbd please explain why in one case

(take 5 (map prn (range 10)))
REPL prints 10 numbers & in other case
(transduce (comp (take 5)
                 (map prn))
           conj
           []
           (range 10))
it prints only 5 but we have take 5 in both examples?

onionpancakes07:01:10

I believe the first example prints 10 because of chunking. The latter doesn't chunk.

Michael Stokley06:01:01

does prn cause side effects?

Michael Stokley06:01:40

both map and range are supposed to return lazy sequences

Michael Stokley06:01:52

seems like the short answer is something like, lazy-sequences and side effects don't mix?

urbis06:01:28

@michael740 yes, to that post

urbis06:01:04

@michael740 šŸ˜… Yes, I got that from the article. Currently trying to understand trasreducers better. Thank you for your response)

Michael Stokley06:01:16

i hope you get a more detailed explanation. i'd be curious to know, too

ikitommi06:01:35

For those who use compojure-api (directly or via Luminus), there is a namespace in the 2.0.0-version. Works like this:

(require '[ :as help])

(help/help)
;; all topics

(help/help :meta)
;; all registered handlers

(help/help :meta :path-params)
;; help on :path-params

ikitommi06:01:57

the last on prints (with nice colors ;)):

:path-params

path-params with letk. Schema is used for both coercion and api-docs.


(POST "/math/:x/:y" []
  :path-params [x :- s/Int, {y :- s/Int 1}]
  (ok {:total (+ x y)}))

timo10:01:26

hi there. how do I figure out how to integrate a flatpickr datetime-picker (https://clojars.org/cljsjs/flatpickr) in my reagent form? I don't get how to call the flatpickr. Any help much appreciated!

joshkh11:01:22

clojars question. šŸ™‚ i have a client/server project that i'm deploying to clojars via lein deploy clojars. :prep-tasks takes care of the clojurescript compilation, css is processed, etc. but when i inspect the jar that comes down from clojars it only has some content in the /public dir. most importantly it's missing my compiled javascript. any thoughts?

joshkh12:01:31

hmm, fixed it by adding the uberjar profile to lein deploy

Vincent Cantin13:01:11

I successfully wrote a type that prints out its content, based on bits I found in the source code of clojure.core. However, I don't fully understand the code I typed:

(deftype Node [graph id]
  IPrintWithWriter
  (-pr-writer [this writer opts] (-write writer (str id))))
What is that -write function, and does the - prefix have a special meaning?

bronsa13:01:16

@vincent.cantin thatā€™s cljs not clj

Vincent Cantin13:01:35

yes, you are right

bronsa13:01:46

- doesnā€™t have any special meaning, but itā€™s idiomatic to prefix a protocol method with - and then wrap it in a regular function

bronsa13:01:11

-write is another protocol method

sb14:01:36

Hello, maybe somebody created here osx app based on java. I need to use java to access native things. The jar run fully normal with ā€˜lein runā€™ but when I deployed with javapackager.. and start the application .. I got ā€œapplication need to accept incoming network connectionsā€™. I read many java forum now.. somebody can help me, who solved this problem?

Vincent Cantin14:01:49

If I understand correctly, your app is not using the network and you want to avoid this message. Isn't it?

Vincent Cantin14:01:22

Maybe try to ask on StackOverflow.

sb16:01:59

Yes, that is the problem. I used my application as a local server and therefore I have incoming network connections.

sb16:01:25

I read about in java forums maybe that can solve with SocketLock or else.. but I donā€™t understand fully.

sb16:01:43

Yes, I will drop to Stackoverflow. thx! @vincent.cantin

sb17:01:09

I found out.. I signed the pkg.. but something not correct and in this case: ā€œSuch errors usually indicate broken application signature.ā€

sb17:01:19

I need to fix the signature

Vincent Cantin14:01:27

Just accept in the security settings of OSX.

Vincent Cantin14:01:47

That's an OSX issue, mainly.

sb14:01:02

I understand that. Just I would like to create an app for users.

sb14:01:17

Can I pre-setup something in the java or in the compiler?

Will16:01:13

Where is the best place to go to learn clojure? Iā€™m coming from java and Iā€™ve been struggling with learning clojure for the last 2 weeks. Iā€™m finding the reason Iā€™m struggling is because I donā€™t understand the language and some of itā€™s basics. Itā€™s hard for me to understand a lot of the clojure docs as well. Are there any books, websites, articles, etcā€¦ you guys recommend to help me get up to speed?

felipebarros18:01:16

Have you tried http://purelyfunctional.tv? Eric is great in breaking the basics into digestible pieces. After trying books and tutorials, I've found his videos to work best for me.

chris16:01:10

clojure for the brave and true

t-ice16:01:48

also I liked this just for puzzle practice http://clojurescriptkoans.com/

Drew Verlee16:01:37

Living Clojure or Clojure for the brave and true. Both have a different style. If your looking for a more nuts and bolts approach, Joy of Clojure.

dpsutton16:01:43

if you're willing to purchase pragprog has a book written written by alex miller and stu halloway. i've purchased it for myself and a coworker based on how much i enjoyed it. definitely worth the purchase price https://pragprog.com/book/shcloj3/programming-clojure-third-edition

michaels16:01:25

I started with clojure for the brave and true. That fact that it was free online was great - and so I went and bought it!

michaels16:01:22

Also, if youā€™ve done https://www.codewars.com/ , clojure is one of the languages. It can be interesting to solve a kata in, say, java, then try it again in clojure, then once youā€™ve solved it, compare your solution to others and say, ā€œOh, ok, I didnā€™t know that was a thing.ā€

Will16:01:16

Thanks a lot guys! Iā€™ll try all these out

sundarj16:01:05

i also found reading through all the stuff on https://clojure.org great

sundarj16:01:15

good luck, and welcome! šŸ™‚

sundarj16:01:07

oh! of course! there is this series too: https://www.youtube.com/watch?v=P76Vbsk_3J0, by rich hickey, the designer of clojure

ekhart16:01:25

there are also challanges at http://www.4clojure.com

matan18:01:26

Is a Java array the only option for O(1) indexed access?

noisesmith18:01:55

vectors are very close - O(log32(n)) iirc

noisesmith18:01:15

they have to get very large before the difference between that and O(1) is likely to matter

matan18:01:26

Yes, I know

matan18:01:41

But otherwise Java arrays. Thanks for confirming!

noisesmith18:01:45

if a vector isn't fast enough, us an array

noisesmith18:01:16

but do profile - it's very likely that indexed lookup is not your bottleneck

matan18:01:27

yes, of course

matan18:01:44

which tool do you profile with yourself, by the way?

matan18:01:59

free for open source right?

noisesmith18:01:14

you can get a free license for open source use yes

Jeroen21:01:46

Any thoughts or recommendations on an editor/IDE for Clojure? Using NightCode and Atom with some REPL support. But both are not really it. Emacs is just too intimidatingā€¦ I do use VIM occasionally, but it seems a hassle to set upā€¦

noisesmith22:01:07

the vim setup was much easier than cider for emacs was fwiw, it's just a language mode and then optionally a lispy editing mode (I like vim-sexp) and finally fireplace if you want repl integration - fireplace is trivial to set up

raheel18:01:57

I would highly recommend giving Spacemacs a try. I am a complete Emacs newbie, and after 4-5 months, I am the most productive I have ever been in any IDE/language setup

Feijolo00:01:26

spacemacs is good but the repl kept getting in my way, I had a better time using vim + fireplace, the vim-sexp is cool and the vim-sexp-mappings-for-regular-people makes editing a breeze

Feijolo00:01:44

spacemacs is indeed powerful but I kept getting the impression that some things were off the place

chris21:01:50

emacs or cursive

chris21:01:24

or just whatever editor and a repl

seancorfield21:01:25

@jeroen.leenarts Is there something specific you don't like about Atom/ProtoREPL? That's what I use (I switched from Emacs).

Jeroen22:01:21

Itā€™s a hassle to setupā€¦ šŸ™‚

adc1722:01:09

@jeroen.leenarts if you want to avoid setup hassle, check out http://lighttable.com/

Jeroen22:01:14

Lighttable seems abandoned.

donmullen22:01:34

@jeroen845 Still a bit intimidating - but a lot of clojure dev are likely http://spacemacs.org/ - and very little additional setup needed from defaults.

sundarj22:01:25

@jeroen.leenarts there's also a clojure extension for Visual Studio Code (great editor, haven't tried the extension though)

seancorfield22:01:52

@jeroen.leenarts You only have to set it up once per machine and the "opinionated guide" is pretty straightforward šŸ™‚

ažyliuk22:01:15

About a month ago I tried every option available. Vscode, atom, emacs and cursive. Iā€™d suggest emacs with cider or cursive. Spacemacs is free and easy to install and require a little configuration. Cursive is free for studying :)

seancorfield22:01:40

(my usual suggestion is "whatever editor you're already using" with some sort of Clojure plugin to hook into a REPL)

Jeroen22:01:56

That last medium link seems to have worked for meā€¦ Trying atom with basic repl support now. Works much better then the ā€œopiniated guide I used beforeā€.

dadair23:01:47

I regularly try out a bunch of IDEs and I almost always go back to Spacemacs + CIDER. Although I donā€™t think Spacemacs is substantially greater than any other editor. I feel like they all have certain limitations that can be annoying for certain use-cases (e.g., lack of extract-function in cursive, lack of static analysis in spacemacs ā€” but also some static analysis can be annoying when using certain macros; such as Clara Rules rules/queries)

Jeroen14:01:13

Really looks interestingā€¦ Emacs for my VIM fingersā€¦ Only problem is that their install from scratch is currently brokenā€¦ Just my luckā€¦ šŸ˜‚ https://github.com/syl20bnr/spacemacs/issues/10244

pablore14:01:13

They are migrating from the standard melpa package repository to their own ā€œspacemelpaā€ repository.

Jeroen15:01:39

@U7V9HE682 Any reference on that I can keep an eye on?

Jeroen10:01:41

They fixed things. šŸ™‚ And this looks kinda good actually.